LCOV - code coverage report
Current view: top level - src/backend/access/common - heaptuple.c (source / functions) Hit Total Coverage
Test: PostgreSQL 11devel Lines: 432 471 91.7 %
Date: 2017-11-22 12:18:04 Functions: 22 23 95.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 400 472 84.7 %

           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                 :            :  * tuptoaster.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 'i' (or 'd') 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 'p', 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-2017, 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/sysattr.h"
      61                 :            : #include "access/tuptoaster.h"
      62                 :            : #include "executor/tuptable.h"
      63                 :            : #include "utils/expandeddatum.h"
      64                 :            : 
      65                 :            : 
      66                 :            : /* Does att's datatype allow packing into the 1-byte-header varlena format? */
      67                 :            : #define ATT_IS_PACKABLE(att) \
      68                 :            :     ((att)->attlen == -1 && (att)->attstorage != 'p')
      69                 :            : /* Use this if it's already known varlena */
      70                 :            : #define VARLENA_ATT_IS_PACKABLE(att) \
      71                 :            :     ((att)->attstorage != 'p')
      72                 :            : 
      73                 :            : 
      74                 :            : /* ----------------------------------------------------------------
      75                 :            :  *                      misc support routines
      76                 :            :  * ----------------------------------------------------------------
      77                 :            :  */
      78                 :            : 
      79                 :            : 
      80                 :            : /*
      81                 :            :  * heap_compute_data_size
      82                 :            :  *      Determine size of the data area of a tuple to be constructed
      83                 :            :  */
      84                 :            : Size
      85                 :   56854362 : heap_compute_data_size(TupleDesc tupleDesc,
      86                 :            :                        Datum *values,
      87                 :            :                        bool *isnull)
      88                 :            : {
      89                 :   56854362 :     Size        data_length = 0;
      90                 :            :     int         i;
      91                 :   56854362 :     int         numberOfAttributes = tupleDesc->natts;
      92                 :            : 
      93         [ +  + ]:  250580158 :     for (i = 0; i < numberOfAttributes; i++)
      94                 :            :     {
      95                 :            :         Datum       val;
      96                 :            :         Form_pg_attribute atti;
      97                 :            : 
      98         [ +  + ]:  193725796 :         if (isnull[i])
      99                 :   17327062 :             continue;
     100                 :            : 
     101                 :  176398734 :         val = values[i];
     102                 :  176398734 :         atti = TupleDescAttr(tupleDesc, i);
     103                 :            : 
     104 [ +  + ][ +  + ]:  176398734 :         if (ATT_IS_PACKABLE(atti) &&
                 [ +  + ]
     105         [ +  + ]:    8065304 :             VARATT_CAN_MAKE_SHORT(DatumGetPointer(val)))
     106                 :            :         {
     107                 :            :             /*
     108                 :            :              * we're anticipating converting to a short varlena header, so
     109                 :            :              * adjust length and don't count any alignment
     110                 :            :              */
     111                 :    7789800 :             data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));
     112                 :            :         }
     113 [ +  + ][ +  + ]:  168608934 :         else if (atti->attlen == -1 &&
     114         [ +  + ]:     106858 :                  VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
     115                 :            :         {
     116                 :            :             /*
     117                 :            :              * we want to flatten the expanded value so that the constructed
     118                 :            :              * tuple doesn't depend on it
     119                 :            :              */
     120 [ +  + ][ +  - ]:       1540 :             data_length = att_align_nominal(data_length, atti->attalign);
                 [ +  - ]
     121                 :       1540 :             data_length += EOH_get_flat_size(DatumGetEOHP(val));
     122                 :            :         }
     123                 :            :         else
     124                 :            :         {
     125 [ +  + ][ +  + ]:  168607394 :             data_length = att_align_datum(data_length, atti->attalign,
         [ +  + ][ +  + ]
                 [ +  + ]
     126                 :            :                                           atti->attlen, val);
     127 [ +  + ][ +  + ]:  168607394 :             data_length = att_addlength_datum(data_length, atti->attlen,
         [ +  + ][ +  + ]
         [ +  - ][ +  - ]
                 [ +  + ]
     128                 :            :                                               val);
     129                 :            :         }
     130                 :            :     }
     131                 :            : 
     132                 :   56854362 :     return data_length;
     133                 :            : }
     134                 :            : 
     135                 :            : /*
     136                 :            :  * heap_fill_tuple
     137                 :            :  *      Load data portion of a tuple from values/isnull arrays
     138                 :            :  *
     139                 :            :  * We also fill the null bitmap (if any) and set the infomask bits
     140                 :            :  * that reflect the tuple's data contents.
     141                 :            :  *
     142                 :            :  * NOTE: it is now REQUIRED that the caller have pre-zeroed the data area.
     143                 :            :  */
     144                 :            : void
     145                 :   56628502 : heap_fill_tuple(TupleDesc tupleDesc,
     146                 :            :                 Datum *values, bool *isnull,
     147                 :            :                 char *data, Size data_size,
     148                 :            :                 uint16 *infomask, bits8 *bit)
     149                 :            : {
     150                 :            :     bits8      *bitP;
     151                 :            :     int         bitmask;
     152                 :            :     int         i;
     153                 :   56628502 :     int         numberOfAttributes = tupleDesc->natts;
     154                 :            : 
     155                 :            : #ifdef USE_ASSERT_CHECKING
     156                 :            :     char       *start = data;
     157                 :            : #endif
     158                 :            : 
     159         [ +  + ]:   56628502 :     if (bit != NULL)
     160                 :            :     {
     161                 :    6593328 :         bitP = &bit[-1];
     162                 :    6593328 :         bitmask = HIGHBIT;
     163                 :            :     }
     164                 :            :     else
     165                 :            :     {
     166                 :            :         /* just to keep compiler quiet */
     167                 :   50035174 :         bitP = NULL;
     168                 :   50035174 :         bitmask = 0;
     169                 :            :     }
     170                 :            : 
     171                 :   56628502 :     *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL);
     172                 :            : 
     173         [ +  + ]:  248260626 :     for (i = 0; i < numberOfAttributes; i++)
     174                 :            :     {
     175                 :  191632124 :         Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
     176                 :            :         Size        data_length;
     177                 :            : 
     178         [ +  + ]:  191632124 :         if (bit != NULL)
     179                 :            :         {
     180         [ +  + ]:   75831812 :             if (bitmask != HIGHBIT)
     181                 :   62523562 :                 bitmask <<= 1;
     182                 :            :             else
     183                 :            :             {
     184                 :   13308250 :                 bitP += 1;
     185                 :   13308250 :                 *bitP = 0x0;
     186                 :   13308250 :                 bitmask = 1;
     187                 :            :             }
     188                 :            : 
     189         [ +  + ]:   75831812 :             if (isnull[i])
     190                 :            :             {
     191                 :   17128566 :                 *infomask |= HEAP_HASNULL;
     192                 :   17128566 :                 continue;
     193                 :            :             }
     194                 :            : 
     195                 :   58703246 :             *bitP |= bitmask;
     196                 :            :         }
     197                 :            : 
     198                 :            :         /*
     199                 :            :          * XXX we use the att_align macros on the pointer value itself, not on
     200                 :            :          * an offset.  This is a bit of a hack.
     201                 :            :          */
     202                 :            : 
     203         [ +  + ]:  174503558 :         if (att->attbyval)
     204                 :            :         {
     205                 :            :             /* pass-by-value */
     206 [ +  + ][ +  + ]:  148381708 :             data = (char *) att_align_nominal(data, att->attalign);
                 [ +  + ]
     207   [ +  +  +  +  :  148381708 :             store_att_byval(data, values[i], att->attlen);
                      - ]
     208                 :  148381708 :             data_length = att->attlen;
     209                 :            :         }
     210         [ +  + ]:   26121850 :         else if (att->attlen == -1)
     211                 :            :         {
     212                 :            :             /* varlena */
     213                 :   14663916 :             Pointer     val = DatumGetPointer(values[i]);
     214                 :            : 
     215                 :   14663916 :             *infomask |= HEAP_HASVARWIDTH;
     216         [ +  + ]:   14663916 :             if (VARATT_IS_EXTERNAL(val))
     217                 :            :             {
     218 [ +  - ][ +  + ]:      23156 :                 if (VARATT_IS_EXTERNAL_EXPANDED(val))
     219                 :       1540 :                 {
     220                 :            :                     /*
     221                 :            :                      * we want to flatten the expanded value so that the
     222                 :            :                      * constructed tuple doesn't depend on it
     223                 :            :                      */
     224                 :       1540 :                     ExpandedObjectHeader *eoh = DatumGetEOHP(values[i]);
     225                 :            : 
     226 [ +  + ][ +  - ]:       1540 :                     data = (char *) att_align_nominal(data,
                 [ +  - ]
     227                 :            :                                                       att->attalign);
     228                 :       1540 :                     data_length = EOH_get_flat_size(eoh);
     229                 :       1540 :                     EOH_flatten_into(eoh, data, data_length);
     230                 :            :                 }
     231                 :            :                 else
     232                 :            :                 {
     233                 :      21616 :                     *infomask |= HEAP_HASEXTERNAL;
     234                 :            :                     /* no alignment, since it's short by definition */
     235 [ +  + ][ +  - ]:      21616 :                     data_length = VARSIZE_EXTERNAL(val);
                 [ +  - ]
     236                 :      23156 :                     memcpy(data, val, data_length);
     237                 :            :                 }
     238                 :            :             }
     239         [ +  + ]:   14640760 :             else if (VARATT_IS_SHORT(val))
     240                 :            :             {
     241                 :            :                 /* no alignment for short varlenas */
     242                 :    3803068 :                 data_length = VARSIZE_SHORT(val);
     243                 :    3803068 :                 memcpy(data, val, data_length);
     244                 :            :             }
     245 [ +  + ][ +  + ]:   10837692 :             else if (VARLENA_ATT_IS_PACKABLE(att) &&
     246         [ +  + ]:    7987130 :                      VARATT_CAN_MAKE_SHORT(val))
     247                 :            :             {
     248                 :            :                 /* convert to short varlena -- no alignment */
     249                 :    7789800 :                 data_length = VARATT_CONVERTED_SHORT_SIZE(val);
     250                 :    7789800 :                 SET_VARSIZE_SHORT(data, data_length);
     251                 :    7789800 :                 memcpy(data + 1, VARDATA(val), data_length - 1);
     252                 :            :             }
     253                 :            :             else
     254                 :            :             {
     255                 :            :                 /* full 4-byte header varlena */
     256 [ +  + ][ +  - ]:    3047892 :                 data = (char *) att_align_nominal(data,
                 [ +  - ]
     257                 :            :                                                   att->attalign);
     258                 :    3047892 :                 data_length = VARSIZE(val);
     259                 :   14663916 :                 memcpy(data, val, data_length);
     260                 :            :             }
     261                 :            :         }
     262         [ +  + ]:   11457934 :         else if (att->attlen == -2)
     263                 :            :         {
     264                 :            :             /* cstring ... never needs alignment */
     265                 :    2608702 :             *infomask |= HEAP_HASVARWIDTH;
     266                 :            :             Assert(att->attalign == 'c');
     267                 :    2608702 :             data_length = strlen(DatumGetCString(values[i])) + 1;
     268                 :    2608702 :             memcpy(data, DatumGetPointer(values[i]), data_length);
     269                 :            :         }
     270                 :            :         else
     271                 :            :         {
     272                 :            :             /* fixed-length pass-by-reference */
     273 [ +  + ][ +  + ]:    8849232 :             data = (char *) att_align_nominal(data, att->attalign);
                 [ +  + ]
     274                 :            :             Assert(att->attlen > 0);
     275                 :    8849232 :             data_length = att->attlen;
     276                 :    8849232 :             memcpy(data, DatumGetPointer(values[i]), data_length);
     277                 :            :         }
     278                 :            : 
     279                 :  174503558 :         data += data_length;
     280                 :            :     }
     281                 :            : 
     282                 :            :     Assert((data - start) == data_size);
     283                 :   56628502 : }
     284                 :            : 
     285                 :            : 
     286                 :            : /* ----------------------------------------------------------------
     287                 :            :  *                      heap tuple interface
     288                 :            :  * ----------------------------------------------------------------
     289                 :            :  */
     290                 :            : 
     291                 :            : /* ----------------
     292                 :            :  *      heap_attisnull  - returns true iff tuple attribute is not present
     293                 :            :  * ----------------
     294                 :            :  */
     295                 :            : bool
     296                 :   24727184 : heap_attisnull(HeapTuple tup, int attnum)
     297                 :            : {
     298         [ +  + ]:   24727184 :     if (attnum > (int) HeapTupleHeaderGetNatts(tup->t_data))
     299                 :          4 :         return true;
     300                 :            : 
     301         [ +  - ]:   24727180 :     if (attnum > 0)
     302                 :            :     {
     303         [ +  + ]:   24727180 :         if (HeapTupleNoNulls(tup))
     304                 :   15516650 :             return false;
     305                 :    9210530 :         return att_isnull(attnum - 1, tup->t_data->t_bits);
     306                 :            :     }
     307                 :            : 
     308         [ #  # ]:          0 :     switch (attnum)
     309                 :            :     {
     310                 :            :         case TableOidAttributeNumber:
     311                 :            :         case SelfItemPointerAttributeNumber:
     312                 :            :         case ObjectIdAttributeNumber:
     313                 :            :         case MinTransactionIdAttributeNumber:
     314                 :            :         case MinCommandIdAttributeNumber:
     315                 :            :         case MaxTransactionIdAttributeNumber:
     316                 :            :         case MaxCommandIdAttributeNumber:
     317                 :            :             /* these are never null */
     318                 :          0 :             break;
     319                 :            : 
     320                 :            :         default:
     321                 :          0 :             elog(ERROR, "invalid attnum: %d", attnum);
     322                 :            :     }
     323                 :            : 
     324                 :          0 :     return false;
     325                 :            : }
     326                 :            : 
     327                 :            : /* ----------------
     328                 :            :  *      nocachegetattr
     329                 :            :  *
     330                 :            :  *      This only gets called from fastgetattr() macro, in cases where
     331                 :            :  *      we can't use a cacheoffset and the value is not null.
     332                 :            :  *
     333                 :            :  *      This caches attribute offsets in the attribute descriptor.
     334                 :            :  *
     335                 :            :  *      An alternative way to speed things up would be to cache offsets
     336                 :            :  *      with the tuple, but that seems more difficult unless you take
     337                 :            :  *      the storage hit of actually putting those offsets into the
     338                 :            :  *      tuple you send to disk.  Yuck.
     339                 :            :  *
     340                 :            :  *      This scheme will be slightly slower than that, but should
     341                 :            :  *      perform well for queries which hit large #'s of tuples.  After
     342                 :            :  *      you cache the offsets once, examining all the other tuples using
     343                 :            :  *      the same attribute descriptor will go much quicker. -cim 5/4/91
     344                 :            :  *
     345                 :            :  *      NOTE: if you need to change this code, see also heap_deform_tuple.
     346                 :            :  *      Also see nocache_index_getattr, which is the same code for index
     347                 :            :  *      tuples.
     348                 :            :  * ----------------
     349                 :            :  */
     350                 :            : Datum
     351                 :  139668030 : nocachegetattr(HeapTuple tuple,
     352                 :            :                int attnum,
     353                 :            :                TupleDesc tupleDesc)
     354                 :            : {
     355                 :  139668030 :     HeapTupleHeader tup = tuple->t_data;
     356                 :            :     char       *tp;             /* ptr to data part of tuple */
     357                 :  139668030 :     bits8      *bp = tup->t_bits;    /* ptr to null bitmap in tuple */
     358                 :  139668030 :     bool        slow = false;   /* do we have to walk attrs? */
     359                 :            :     int         off;            /* current offset within data */
     360                 :            : 
     361                 :            :     /* ----------------
     362                 :            :      *   Three cases:
     363                 :            :      *
     364                 :            :      *   1: No nulls and no variable-width attributes.
     365                 :            :      *   2: Has a null or a var-width AFTER att.
     366                 :            :      *   3: Has nulls or var-widths BEFORE att.
     367                 :            :      * ----------------
     368                 :            :      */
     369                 :            : 
     370                 :  139668030 :     attnum--;
     371                 :            : 
     372         [ +  + ]:  139668030 :     if (!HeapTupleNoNulls(tuple))
     373                 :            :     {
     374                 :            :         /*
     375                 :            :          * there's a null somewhere in the tuple
     376                 :            :          *
     377                 :            :          * check to see if any preceding bits are null...
     378                 :            :          */
     379                 :  123826534 :         int         byte = attnum >> 3;
     380                 :  123826534 :         int         finalbit = attnum & 0x07;
     381                 :            : 
     382                 :            :         /* check for nulls "before" final bit of last byte */
     383         [ +  + ]:  123826534 :         if ((~bp[byte]) & ((1 << finalbit) - 1))
     384                 :   10049224 :             slow = true;
     385                 :            :         else
     386                 :            :         {
     387                 :            :             /* check for nulls in any "earlier" bytes */
     388                 :            :             int         i;
     389                 :            : 
     390         [ +  + ]:  158188212 :             for (i = 0; i < byte; i++)
     391                 :            :             {
     392         [ +  + ]:   44423248 :                 if (bp[i] != 0xFF)
     393                 :            :                 {
     394                 :      12346 :                     slow = true;
     395                 :      12346 :                     break;
     396                 :            :                 }
     397                 :            :             }
     398                 :            :         }
     399                 :            :     }
     400                 :            : 
     401                 :  139668030 :     tp = (char *) tup + tup->t_hoff;
     402                 :            : 
     403         [ +  + ]:  139668030 :     if (!slow)
     404                 :            :     {
     405                 :            :         Form_pg_attribute att;
     406                 :            : 
     407                 :            :         /*
     408                 :            :          * If we get here, there are no nulls up to and including the target
     409                 :            :          * attribute.  If we have a cached offset, we can use it.
     410                 :            :          */
     411                 :  129606460 :         att = TupleDescAttr(tupleDesc, attnum);
     412         [ +  + ]:  129606460 :         if (att->attcacheoff >= 0)
     413 [ +  + ][ +  + ]:  111362648 :             return fetchatt(att, tp + att->attcacheoff);
         [ +  + ][ +  + ]
     414                 :            : 
     415                 :            :         /*
     416                 :            :          * Otherwise, check for non-fixed-length attrs up to and including
     417                 :            :          * target.  If there aren't any, it's safe to cheaply initialize the
     418                 :            :          * cached offsets for these attrs.
     419                 :            :          */
     420         [ +  + ]:   18243812 :         if (HeapTupleHasVarWidth(tuple))
     421                 :            :         {
     422                 :            :             int         j;
     423                 :            : 
     424         [ +  + ]:   41085150 :             for (j = 0; j <= attnum; j++)
     425                 :            :             {
     426         [ +  + ]:   41067558 :                 if (TupleDescAttr(tupleDesc, j)->attlen <= 0)
     427                 :            :                 {
     428                 :   17965610 :                     slow = true;
     429                 :   17965610 :                     break;
     430                 :            :                 }
     431                 :            :             }
     432                 :            :         }
     433                 :            :     }
     434                 :            : 
     435         [ +  + ]:   28305382 :     if (!slow)
     436                 :            :     {
     437                 :     278202 :         int         natts = tupleDesc->natts;
     438                 :     278202 :         int         j = 1;
     439                 :            : 
     440                 :            :         /*
     441                 :            :          * If we get here, we have a tuple with no nulls or var-widths up to
     442                 :            :          * and including the target attribute, so we can use the cached offset
     443                 :            :          * ... only we don't have it yet, or we'd not have got here.  Since
     444                 :            :          * it's cheap to compute offsets for fixed-width columns, we take the
     445                 :            :          * opportunity to initialize the cached offsets for *all* the leading
     446                 :            :          * fixed-width columns, in hope of avoiding future visits to this
     447                 :            :          * routine.
     448                 :            :          */
     449                 :     278202 :         TupleDescAttr(tupleDesc, 0)->attcacheoff = 0;
     450                 :            : 
     451                 :            :         /* we might have set some offsets in the slow path previously */
     452 [ +  + ][ +  + ]:     281198 :         while (j < natts && TupleDescAttr(tupleDesc, j)->attcacheoff > 0)
     453                 :       2996 :             j++;
     454                 :            : 
     455                 :     556404 :         off = TupleDescAttr(tupleDesc, j - 1)->attcacheoff +
     456                 :     278202 :             TupleDescAttr(tupleDesc, j - 1)->attlen;
     457                 :            : 
     458         [ +  + ]:     798538 :         for (; j < natts; j++)
     459                 :            :         {
     460                 :     548464 :             Form_pg_attribute att = TupleDescAttr(tupleDesc, j);
     461                 :            : 
     462         [ +  + ]:     548464 :             if (att->attlen <= 0)
     463                 :      28128 :                 break;
     464                 :            : 
     465 [ +  + ][ +  + ]:     520336 :             off = att_align_nominal(off, att->attalign);
                 [ +  + ]
     466                 :            : 
     467                 :     520336 :             att->attcacheoff = off;
     468                 :            : 
     469                 :     520336 :             off += att->attlen;
     470                 :            :         }
     471                 :            : 
     472                 :            :         Assert(j > attnum);
     473                 :            : 
     474                 :     278202 :         off = TupleDescAttr(tupleDesc, attnum)->attcacheoff;
     475                 :            :     }
     476                 :            :     else
     477                 :            :     {
     478                 :   28027180 :         bool        usecache = true;
     479                 :            :         int         i;
     480                 :            : 
     481                 :            :         /*
     482                 :            :          * Now we know that we have to walk the tuple CAREFULLY.  But we still
     483                 :            :          * might be able to cache some offsets for next time.
     484                 :            :          *
     485                 :            :          * Note - This loop is a little tricky.  For each non-null attribute,
     486                 :            :          * we have to first account for alignment padding before the attr,
     487                 :            :          * then advance over the attr based on its length.  Nulls have no
     488                 :            :          * storage and no alignment padding either.  We can use/set
     489                 :            :          * attcacheoff until we reach either a null or a var-width attribute.
     490                 :            :          */
     491                 :   28027180 :         off = 0;
     492                 :   28027180 :         for (i = 0;; i++)       /* loop exit is at "break" */
     493                 :  124654454 :         {
     494                 :  152681634 :             Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
     495                 :            : 
     496 [ +  + ][ +  + ]:  152681634 :             if (HeapTupleHasNulls(tuple) && att_isnull(i, bp))
     497                 :            :             {
     498                 :   17942392 :                 usecache = false;
     499                 :   17942392 :                 continue;       /* this cannot be the target att */
     500                 :            :             }
     501                 :            : 
     502                 :            :             /* If we know the next offset, we can skip the rest */
     503 [ +  + ][ +  + ]:  134739242 :             if (usecache && att->attcacheoff >= 0)
     504                 :   78676552 :                 off = att->attcacheoff;
     505         [ +  + ]:   56062690 :             else if (att->attlen == -1)
     506                 :            :             {
     507                 :            :                 /*
     508                 :            :                  * We can only cache the offset for a varlena attribute if the
     509                 :            :                  * offset is already suitably aligned, so that there would be
     510                 :            :                  * no pad bytes in any case: then the offset will be valid for
     511                 :            :                  * either an aligned or unaligned value.
     512                 :            :                  */
     513 [ +  + ][ +  + ]:   11550902 :                 if (usecache &&
     514 [ +  + ][ -  + ]:     249622 :                     off == att_align_nominal(off, att->attalign))
                 [ +  - ]
     515                 :      37086 :                     att->attcacheoff = off;
     516                 :            :                 else
     517                 :            :                 {
     518 [ +  + ][ +  + ]:   11264194 :                     off = att_align_pointer(off, att->attalign, -1,
         [ +  - ][ +  - ]
     519                 :            :                                             tp + off);
     520                 :   11301280 :                     usecache = false;
     521                 :            :                 }
     522                 :            :             }
     523                 :            :             else
     524                 :            :             {
     525                 :            :                 /* not varlena, so safe to use att_align_nominal */
     526 [ +  + ][ +  + ]:   44761410 :                 off = att_align_nominal(off, att->attalign);
                 [ +  + ]
     527                 :            : 
     528         [ +  + ]:   44761410 :                 if (usecache)
     529                 :     206250 :                     att->attcacheoff = off;
     530                 :            :             }
     531                 :            : 
     532         [ +  + ]:  134739242 :             if (i == attnum)
     533                 :   28027180 :                 break;
     534                 :            : 
     535 [ +  + ][ +  - ]:  106712062 :             off = att_addlength_pointer(off, att->attlen, tp + off);
         [ +  + ][ +  + ]
         [ +  - ][ +  - ]
                 [ +  + ]
     536                 :            : 
     537 [ +  + ][ +  + ]:  106712062 :             if (usecache && att->attlen <= 0)
     538                 :   27685814 :                 usecache = false;
     539                 :            :         }
     540                 :            :     }
     541                 :            : 
     542 [ +  + ][ +  + ]:   28305382 :     return fetchatt(TupleDescAttr(tupleDesc, attnum), tp + off);
         [ +  + ][ +  + ]
     543                 :            : }
     544                 :            : 
     545                 :            : /* ----------------
     546                 :            :  *      heap_getsysattr
     547                 :            :  *
     548                 :            :  *      Fetch the value of a system attribute for a tuple.
     549                 :            :  *
     550                 :            :  * This is a support routine for the heap_getattr macro.  The macro
     551                 :            :  * has already determined that the attnum refers to a system attribute.
     552                 :            :  * ----------------
     553                 :            :  */
     554                 :            : Datum
     555                 :   23211242 : heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
     556                 :            : {
     557                 :            :     Datum       result;
     558                 :            : 
     559                 :            :     Assert(tup);
     560                 :            : 
     561                 :            :     /* Currently, no sys attribute ever reads as NULL. */
     562                 :   23211242 :     *isnull = false;
     563                 :            : 
     564   [ +  +  +  -  :   23211242 :     switch (attnum)
                +  +  - ]
     565                 :            :     {
     566                 :            :         case SelfItemPointerAttributeNumber:
     567                 :            :             /* pass-by-reference datatype */
     568                 :     823864 :             result = PointerGetDatum(&(tup->t_self));
     569                 :     823864 :             break;
     570                 :            :         case ObjectIdAttributeNumber:
     571         [ +  - ]:   20021840 :             result = ObjectIdGetDatum(HeapTupleGetOid(tup));
     572                 :   20021840 :             break;
     573                 :            :         case MinTransactionIdAttributeNumber:
     574                 :         42 :             result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmin(tup->t_data));
     575                 :         42 :             break;
     576                 :            :         case MaxTransactionIdAttributeNumber:
     577                 :          0 :             result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmax(tup->t_data));
     578                 :          0 :             break;
     579                 :            :         case MinCommandIdAttributeNumber:
     580                 :            :         case MaxCommandIdAttributeNumber:
     581                 :            : 
     582                 :            :             /*
     583                 :            :              * cmin and cmax are now both aliases for the same field, which
     584                 :            :              * can in fact also be a combo command id.  XXX perhaps we should
     585                 :            :              * return the "real" cmin or cmax if possible, that is if we are
     586                 :            :              * inside the originating transaction?
     587                 :            :              */
     588                 :        124 :             result = CommandIdGetDatum(HeapTupleHeaderGetRawCommandId(tup->t_data));
     589                 :        124 :             break;
     590                 :            :         case TableOidAttributeNumber:
     591                 :    2365372 :             result = ObjectIdGetDatum(tup->t_tableOid);
     592                 :    2365372 :             break;
     593                 :            :         default:
     594                 :          0 :             elog(ERROR, "invalid attnum: %d", attnum);
     595                 :            :             result = 0;         /* keep compiler quiet */
     596                 :            :             break;
     597                 :            :     }
     598                 :   23211242 :     return result;
     599                 :            : }
     600                 :            : 
     601                 :            : /* ----------------
     602                 :            :  *      heap_copytuple
     603                 :            :  *
     604                 :            :  *      returns a copy of an entire tuple
     605                 :            :  *
     606                 :            :  * The HeapTuple struct, tuple header, and tuple data are all allocated
     607                 :            :  * as a single palloc() block.
     608                 :            :  * ----------------
     609                 :            :  */
     610                 :            : HeapTuple
     611                 :   12281556 : heap_copytuple(HeapTuple tuple)
     612                 :            : {
     613                 :            :     HeapTuple   newTuple;
     614                 :            : 
     615 [ +  - ][ -  + ]:   12281556 :     if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)
     616                 :          0 :         return NULL;
     617                 :            : 
     618                 :   12281556 :     newTuple = (HeapTuple) palloc(HEAPTUPLESIZE + tuple->t_len);
     619                 :   12281556 :     newTuple->t_len = tuple->t_len;
     620                 :   12281556 :     newTuple->t_self = tuple->t_self;
     621                 :   12281556 :     newTuple->t_tableOid = tuple->t_tableOid;
     622                 :   12281556 :     newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
     623                 :   12281556 :     memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_len);
     624                 :   12281556 :     return newTuple;
     625                 :            : }
     626                 :            : 
     627                 :            : /* ----------------
     628                 :            :  *      heap_copytuple_with_tuple
     629                 :            :  *
     630                 :            :  *      copy a tuple into a caller-supplied HeapTuple management struct
     631                 :            :  *
     632                 :            :  * Note that after calling this function, the "dest" HeapTuple will not be
     633                 :            :  * allocated as a single palloc() block (unlike with heap_copytuple()).
     634                 :            :  * ----------------
     635                 :            :  */
     636                 :            : void
     637                 :          0 : heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest)
     638                 :            : {
     639 [ #  # ][ #  # ]:          0 :     if (!HeapTupleIsValid(src) || src->t_data == NULL)
     640                 :            :     {
     641                 :          0 :         dest->t_data = NULL;
     642                 :          0 :         return;
     643                 :            :     }
     644                 :            : 
     645                 :          0 :     dest->t_len = src->t_len;
     646                 :          0 :     dest->t_self = src->t_self;
     647                 :          0 :     dest->t_tableOid = src->t_tableOid;
     648                 :          0 :     dest->t_data = (HeapTupleHeader) palloc(src->t_len);
     649                 :          0 :     memcpy((char *) dest->t_data, (char *) src->t_data, src->t_len);
     650                 :            : }
     651                 :            : 
     652                 :            : /* ----------------
     653                 :            :  *      heap_copy_tuple_as_datum
     654                 :            :  *
     655                 :            :  *      copy a tuple as a composite-type Datum
     656                 :            :  * ----------------
     657                 :            :  */
     658                 :            : Datum
     659                 :      41376 : heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
     660                 :            : {
     661                 :            :     HeapTupleHeader td;
     662                 :            : 
     663                 :            :     /*
     664                 :            :      * If the tuple contains any external TOAST pointers, we have to inline
     665                 :            :      * those fields to meet the conventions for composite-type Datums.
     666                 :            :      */
     667         [ +  + ]:      41376 :     if (HeapTupleHasExternal(tuple))
     668                 :         32 :         return toast_flatten_tuple_to_datum(tuple->t_data,
     669                 :            :                                             tuple->t_len,
     670                 :            :                                             tupleDesc);
     671                 :            : 
     672                 :            :     /*
     673                 :            :      * Fast path for easy case: just make a palloc'd copy and insert the
     674                 :            :      * correct composite-Datum header fields (since those may not be set if
     675                 :            :      * the given tuple came from disk, rather than from heap_form_tuple).
     676                 :            :      */
     677                 :      41344 :     td = (HeapTupleHeader) palloc(tuple->t_len);
     678                 :      41344 :     memcpy((char *) td, (char *) tuple->t_data, tuple->t_len);
     679                 :            : 
     680                 :      41344 :     HeapTupleHeaderSetDatumLength(td, tuple->t_len);
     681                 :      41344 :     HeapTupleHeaderSetTypeId(td, tupleDesc->tdtypeid);
     682                 :      41344 :     HeapTupleHeaderSetTypMod(td, tupleDesc->tdtypmod);
     683                 :            : 
     684                 :      41344 :     return PointerGetDatum(td);
     685                 :            : }
     686                 :            : 
     687                 :            : /*
     688                 :            :  * heap_form_tuple
     689                 :            :  *      construct a tuple from the given values[] and isnull[] arrays,
     690                 :            :  *      which are of the length indicated by tupleDescriptor->natts
     691                 :            :  *
     692                 :            :  * The result is allocated in the current memory context.
     693                 :            :  */
     694                 :            : HeapTuple
     695                 :   17932768 : heap_form_tuple(TupleDesc tupleDescriptor,
     696                 :            :                 Datum *values,
     697                 :            :                 bool *isnull)
     698                 :            : {
     699                 :            :     HeapTuple   tuple;          /* return tuple */
     700                 :            :     HeapTupleHeader td;         /* tuple data */
     701                 :            :     Size        len,
     702                 :            :                 data_len;
     703                 :            :     int         hoff;
     704                 :   17932768 :     bool        hasnull = false;
     705                 :   17932768 :     int         numberOfAttributes = tupleDescriptor->natts;
     706                 :            :     int         i;
     707                 :            : 
     708         [ -  + ]:   17932768 :     if (numberOfAttributes > MaxTupleAttributeNumber)
     709         [ #  # ]:          0 :         ereport(ERROR,
     710                 :            :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
     711                 :            :                  errmsg("number of columns (%d) exceeds limit (%d)",
     712                 :            :                         numberOfAttributes, MaxTupleAttributeNumber)));
     713                 :            : 
     714                 :            :     /*
     715                 :            :      * Check for nulls
     716                 :            :      */
     717         [ +  + ]:  112604964 :     for (i = 0; i < numberOfAttributes; i++)
     718                 :            :     {
     719         [ +  + ]:  100600372 :         if (isnull[i])
     720                 :            :         {
     721                 :    5928176 :             hasnull = true;
     722                 :    5928176 :             break;
     723                 :            :         }
     724                 :            :     }
     725                 :            : 
     726                 :            :     /*
     727                 :            :      * Determine total space needed
     728                 :            :      */
     729                 :   17932768 :     len = offsetof(HeapTupleHeaderData, t_bits);
     730                 :            : 
     731         [ +  + ]:   17932768 :     if (hasnull)
     732                 :    5928176 :         len += BITMAPLEN(numberOfAttributes);
     733                 :            : 
     734         [ +  + ]:   17932768 :     if (tupleDescriptor->tdhasoid)
     735                 :    2204278 :         len += sizeof(Oid);
     736                 :            : 
     737                 :   17932768 :     hoff = len = MAXALIGN(len); /* align user data safely */
     738                 :            : 
     739                 :   17932768 :     data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
     740                 :            : 
     741                 :   17932768 :     len += data_len;
     742                 :            : 
     743                 :            :     /*
     744                 :            :      * Allocate and zero the space needed.  Note that the tuple body and
     745                 :            :      * HeapTupleData management structure are allocated in one chunk.
     746                 :            :      */
     747                 :   17932768 :     tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
     748                 :   17932768 :     tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
     749                 :            : 
     750                 :            :     /*
     751                 :            :      * And fill in the information.  Note we fill the Datum fields even though
     752                 :            :      * this tuple may never become a Datum.  This lets HeapTupleHeaderGetDatum
     753                 :            :      * identify the tuple type if needed.
     754                 :            :      */
     755                 :   17932768 :     tuple->t_len = len;
     756                 :   17932768 :     ItemPointerSetInvalid(&(tuple->t_self));
     757                 :   17932768 :     tuple->t_tableOid = InvalidOid;
     758                 :            : 
     759                 :   17932768 :     HeapTupleHeaderSetDatumLength(td, len);
     760                 :   17932768 :     HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid);
     761                 :   17932768 :     HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod);
     762                 :            :     /* We also make sure that t_ctid is invalid unless explicitly set */
     763                 :   17932768 :     ItemPointerSetInvalid(&(td->t_ctid));
     764                 :            : 
     765                 :   17932768 :     HeapTupleHeaderSetNatts(td, numberOfAttributes);
     766                 :   17932768 :     td->t_hoff = hoff;
     767                 :            : 
     768         [ +  + ]:   17932768 :     if (tupleDescriptor->tdhasoid)   /* else leave infomask = 0 */
     769                 :    2204278 :         td->t_infomask = HEAP_HASOID;
     770                 :            : 
     771         [ +  + ]:   17932768 :     heap_fill_tuple(tupleDescriptor,
     772                 :            :                     values,
     773                 :            :                     isnull,
     774                 :            :                     (char *) td + hoff,
     775                 :            :                     data_len,
     776                 :            :                     &td->t_infomask,
     777                 :            :                     (hasnull ? td->t_bits : NULL));
     778                 :            : 
     779                 :   17932768 :     return tuple;
     780                 :            : }
     781                 :            : 
     782                 :            : /*
     783                 :            :  * heap_modify_tuple
     784                 :            :  *      form a new tuple from an old tuple and a set of replacement values.
     785                 :            :  *
     786                 :            :  * The replValues, replIsnull, and doReplace arrays must be of the length
     787                 :            :  * indicated by tupleDesc->natts.  The new tuple is constructed using the data
     788                 :            :  * from replValues/replIsnull at columns where doReplace is true, and using
     789                 :            :  * the data from the old tuple at columns where doReplace is false.
     790                 :            :  *
     791                 :            :  * The result is allocated in the current memory context.
     792                 :            :  */
     793                 :            : HeapTuple
     794                 :      97608 : heap_modify_tuple(HeapTuple tuple,
     795                 :            :                   TupleDesc tupleDesc,
     796                 :            :                   Datum *replValues,
     797                 :            :                   bool *replIsnull,
     798                 :            :                   bool *doReplace)
     799                 :            : {
     800                 :      97608 :     int         numberOfAttributes = tupleDesc->natts;
     801                 :            :     int         attoff;
     802                 :            :     Datum      *values;
     803                 :            :     bool       *isnull;
     804                 :            :     HeapTuple   newTuple;
     805                 :            : 
     806                 :            :     /*
     807                 :            :      * allocate and fill values and isnull arrays from either the tuple or the
     808                 :            :      * repl information, as appropriate.
     809                 :            :      *
     810                 :            :      * NOTE: it's debatable whether to use heap_deform_tuple() here or just
     811                 :            :      * heap_getattr() only the non-replaced columns.  The latter could win if
     812                 :            :      * there are many replaced columns and few non-replaced ones. However,
     813                 :            :      * heap_deform_tuple costs only O(N) while the heap_getattr way would cost
     814                 :            :      * O(N^2) if there are many non-replaced columns, so it seems better to
     815                 :            :      * err on the side of linear cost.
     816                 :            :      */
     817                 :      97608 :     values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
     818                 :      97608 :     isnull = (bool *) palloc(numberOfAttributes * sizeof(bool));
     819                 :            : 
     820                 :      97608 :     heap_deform_tuple(tuple, tupleDesc, values, isnull);
     821                 :            : 
     822         [ +  + ]:    2510284 :     for (attoff = 0; attoff < numberOfAttributes; attoff++)
     823                 :            :     {
     824         [ +  + ]:    2412676 :         if (doReplace[attoff])
     825                 :            :         {
     826                 :    1445420 :             values[attoff] = replValues[attoff];
     827                 :    1445420 :             isnull[attoff] = replIsnull[attoff];
     828                 :            :         }
     829                 :            :     }
     830                 :            : 
     831                 :            :     /*
     832                 :            :      * create a new tuple from the values and isnull arrays
     833                 :            :      */
     834                 :      97608 :     newTuple = heap_form_tuple(tupleDesc, values, isnull);
     835                 :            : 
     836                 :      97608 :     pfree(values);
     837                 :      97608 :     pfree(isnull);
     838                 :            : 
     839                 :            :     /*
     840                 :            :      * copy the identification info of the old tuple: t_ctid, t_self, and OID
     841                 :            :      * (if any)
     842                 :            :      */
     843                 :      97608 :     newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
     844                 :      97608 :     newTuple->t_self = tuple->t_self;
     845                 :      97608 :     newTuple->t_tableOid = tuple->t_tableOid;
     846         [ +  + ]:      97608 :     if (tupleDesc->tdhasoid)
     847         [ +  - ]:      47230 :         HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
     848                 :            : 
     849                 :      97608 :     return newTuple;
     850                 :            : }
     851                 :            : 
     852                 :            : /*
     853                 :            :  * heap_modify_tuple_by_cols
     854                 :            :  *      form a new tuple from an old tuple and a set of replacement values.
     855                 :            :  *
     856                 :            :  * This is like heap_modify_tuple, except that instead of specifying which
     857                 :            :  * column(s) to replace by a boolean map, an array of target column numbers
     858                 :            :  * is used.  This is often more convenient when a fixed number of columns
     859                 :            :  * are to be replaced.  The replCols, replValues, and replIsnull arrays must
     860                 :            :  * be of length nCols.  Target column numbers are indexed from 1.
     861                 :            :  *
     862                 :            :  * The result is allocated in the current memory context.
     863                 :            :  */
     864                 :            : HeapTuple
     865                 :       1236 : heap_modify_tuple_by_cols(HeapTuple tuple,
     866                 :            :                           TupleDesc tupleDesc,
     867                 :            :                           int nCols,
     868                 :            :                           int *replCols,
     869                 :            :                           Datum *replValues,
     870                 :            :                           bool *replIsnull)
     871                 :            : {
     872                 :       1236 :     int         numberOfAttributes = tupleDesc->natts;
     873                 :            :     Datum      *values;
     874                 :            :     bool       *isnull;
     875                 :            :     HeapTuple   newTuple;
     876                 :            :     int         i;
     877                 :            : 
     878                 :            :     /*
     879                 :            :      * allocate and fill values and isnull arrays from the tuple, then replace
     880                 :            :      * selected columns from the input arrays.
     881                 :            :      */
     882                 :       1236 :     values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
     883                 :       1236 :     isnull = (bool *) palloc(numberOfAttributes * sizeof(bool));
     884                 :            : 
     885                 :       1236 :     heap_deform_tuple(tuple, tupleDesc, values, isnull);
     886                 :            : 
     887         [ +  + ]:       2472 :     for (i = 0; i < nCols; i++)
     888                 :            :     {
     889                 :       1236 :         int         attnum = replCols[i];
     890                 :            : 
     891 [ +  - ][ -  + ]:       1236 :         if (attnum <= 0 || attnum > numberOfAttributes)
     892                 :          0 :             elog(ERROR, "invalid column number %d", attnum);
     893                 :       1236 :         values[attnum - 1] = replValues[i];
     894                 :       1236 :         isnull[attnum - 1] = replIsnull[i];
     895                 :            :     }
     896                 :            : 
     897                 :            :     /*
     898                 :            :      * create a new tuple from the values and isnull arrays
     899                 :            :      */
     900                 :       1236 :     newTuple = heap_form_tuple(tupleDesc, values, isnull);
     901                 :            : 
     902                 :       1236 :     pfree(values);
     903                 :       1236 :     pfree(isnull);
     904                 :            : 
     905                 :            :     /*
     906                 :            :      * copy the identification info of the old tuple: t_ctid, t_self, and OID
     907                 :            :      * (if any)
     908                 :            :      */
     909                 :       1236 :     newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
     910                 :       1236 :     newTuple->t_self = tuple->t_self;
     911                 :       1236 :     newTuple->t_tableOid = tuple->t_tableOid;
     912         [ +  + ]:       1236 :     if (tupleDesc->tdhasoid)
     913         [ +  - ]:        100 :         HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
     914                 :            : 
     915                 :       1236 :     return newTuple;
     916                 :            : }
     917                 :            : 
     918                 :            : /*
     919                 :            :  * heap_deform_tuple
     920                 :            :  *      Given a tuple, extract data into values/isnull arrays; this is
     921                 :            :  *      the inverse of heap_form_tuple.
     922                 :            :  *
     923                 :            :  *      Storage for the values/isnull arrays is provided by the caller;
     924                 :            :  *      it should be sized according to tupleDesc->natts not
     925                 :            :  *      HeapTupleHeaderGetNatts(tuple->t_data).
     926                 :            :  *
     927                 :            :  *      Note that for pass-by-reference datatypes, the pointer placed
     928                 :            :  *      in the Datum will point into the given tuple.
     929                 :            :  *
     930                 :            :  *      When all or most of a tuple's fields need to be extracted,
     931                 :            :  *      this routine will be significantly quicker than a loop around
     932                 :            :  *      heap_getattr; the loop will become O(N^2) as soon as any
     933                 :            :  *      noncacheable attribute offsets are involved.
     934                 :            :  */
     935                 :            : void
     936                 :    1577624 : heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
     937                 :            :                   Datum *values, bool *isnull)
     938                 :            : {
     939                 :    1577624 :     HeapTupleHeader tup = tuple->t_data;
     940                 :    1577624 :     bool        hasnulls = HeapTupleHasNulls(tuple);
     941                 :    1577624 :     int         tdesc_natts = tupleDesc->natts;
     942                 :            :     int         natts;          /* number of atts to extract */
     943                 :            :     int         attnum;
     944                 :            :     char       *tp;             /* ptr to tuple data */
     945                 :            :     long        off;            /* offset in tuple data */
     946                 :    1577624 :     bits8      *bp = tup->t_bits;    /* ptr to null bitmap in tuple */
     947                 :    1577624 :     bool        slow = false;   /* can we use/set attcacheoff? */
     948                 :            : 
     949                 :    1577624 :     natts = HeapTupleHeaderGetNatts(tup);
     950                 :            : 
     951                 :            :     /*
     952                 :            :      * In inheritance situations, it is possible that the given tuple actually
     953                 :            :      * has more fields than the caller is expecting.  Don't run off the end of
     954                 :            :      * the caller's arrays.
     955                 :            :      */
     956                 :    1577624 :     natts = Min(natts, tdesc_natts);
     957                 :            : 
     958                 :    1577624 :     tp = (char *) tup + tup->t_hoff;
     959                 :            : 
     960                 :    1577624 :     off = 0;
     961                 :            : 
     962         [ +  + ]:   10382296 :     for (attnum = 0; attnum < natts; attnum++)
     963                 :            :     {
     964                 :    8804672 :         Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
     965                 :            : 
     966 [ +  + ][ +  + ]:    8804672 :         if (hasnulls && att_isnull(attnum, bp))
     967                 :            :         {
     968                 :     974716 :             values[attnum] = (Datum) 0;
     969                 :     974716 :             isnull[attnum] = true;
     970                 :     974716 :             slow = true;        /* can't use attcacheoff anymore */
     971                 :     974716 :             continue;
     972                 :            :         }
     973                 :            : 
     974                 :    7829956 :         isnull[attnum] = false;
     975                 :            : 
     976 [ +  + ][ +  + ]:    7829956 :         if (!slow && thisatt->attcacheoff >= 0)
     977                 :    7119908 :             off = thisatt->attcacheoff;
     978         [ +  + ]:     710048 :         else if (thisatt->attlen == -1)
     979                 :            :         {
     980                 :            :             /*
     981                 :            :              * We can only cache the offset for a varlena attribute if the
     982                 :            :              * offset is already suitably aligned, so that there would be no
     983                 :            :              * pad bytes in any case: then the offset will be valid for either
     984                 :            :              * an aligned or unaligned value.
     985                 :            :              */
     986 [ +  + ][ +  + ]:     415646 :             if (!slow &&
     987 [ +  + ][ +  - ]:      35850 :                 off == att_align_nominal(off, thisatt->attalign))
                 [ +  - ]
     988                 :       1818 :                 thisatt->attcacheoff = off;
     989                 :            :             else
     990                 :            :             {
     991 [ +  + ][ +  + ]:     377978 :                 off = att_align_pointer(off, thisatt->attalign, -1,
         [ +  - ][ +  - ]
     992                 :            :                                         tp + off);
     993                 :     379796 :                 slow = true;
     994                 :            :             }
     995                 :            :         }
     996                 :            :         else
     997                 :            :         {
     998                 :            :             /* not varlena, so safe to use att_align_nominal */
     999 [ +  + ][ +  + ]:     330252 :             off = att_align_nominal(off, thisatt->attalign);
                 [ +  + ]
    1000                 :            : 
    1001         [ +  + ]:     330252 :             if (!slow)
    1002                 :      32316 :                 thisatt->attcacheoff = off;
    1003                 :            :         }
    1004                 :            : 
    1005 [ +  + ][ +  + ]:    7829956 :         values[attnum] = fetchatt(thisatt, tp + off);
         [ +  + ][ +  + ]
    1006                 :            : 
    1007 [ +  + ][ +  + ]:    7829956 :         off = att_addlength_pointer(off, thisatt->attlen, tp + off);
         [ +  + ][ +  + ]
         [ +  - ][ +  - ]
                 [ +  + ]
    1008                 :            : 
    1009         [ +  + ]:    7829956 :         if (thisatt->attlen <= 0)
    1010                 :     894080 :             slow = true;        /* can't use attcacheoff anymore */
    1011                 :            :     }
    1012                 :            : 
    1013                 :            :     /*
    1014                 :            :      * If tuple doesn't have all the atts indicated by tupleDesc, read the
    1015                 :            :      * rest as null
    1016                 :            :      */
    1017         [ +  + ]:    1579360 :     for (; attnum < tdesc_natts; attnum++)
    1018                 :            :     {
    1019                 :       1736 :         values[attnum] = (Datum) 0;
    1020                 :       1736 :         isnull[attnum] = true;
    1021                 :            :     }
    1022                 :    1577624 : }
    1023                 :            : 
    1024                 :            : /*
    1025                 :            :  * slot_deform_tuple
    1026                 :            :  *      Given a TupleTableSlot, extract data from the slot's physical tuple
    1027                 :            :  *      into its Datum/isnull arrays.  Data is extracted up through the
    1028                 :            :  *      natts'th column (caller must ensure this is a legal column number).
    1029                 :            :  *
    1030                 :            :  *      This is essentially an incremental version of heap_deform_tuple:
    1031                 :            :  *      on each call we extract attributes up to the one needed, without
    1032                 :            :  *      re-computing information about previously extracted attributes.
    1033                 :            :  *      slot->tts_nvalid is the number of attributes already extracted.
    1034                 :            :  */
    1035                 :            : static void
    1036                 :   88855796 : slot_deform_tuple(TupleTableSlot *slot, int natts)
    1037                 :            : {
    1038                 :   88855796 :     HeapTuple   tuple = slot->tts_tuple;
    1039                 :   88855796 :     TupleDesc   tupleDesc = slot->tts_tupleDescriptor;
    1040                 :   88855796 :     Datum      *values = slot->tts_values;
    1041                 :   88855796 :     bool       *isnull = slot->tts_isnull;
    1042                 :   88855796 :     HeapTupleHeader tup = tuple->t_data;
    1043                 :   88855796 :     bool        hasnulls = HeapTupleHasNulls(tuple);
    1044                 :            :     int         attnum;
    1045                 :            :     char       *tp;             /* ptr to tuple data */
    1046                 :            :     long        off;            /* offset in tuple data */
    1047                 :   88855796 :     bits8      *bp = tup->t_bits;    /* ptr to null bitmap in tuple */
    1048                 :            :     bool        slow;           /* can we use/set attcacheoff? */
    1049                 :            : 
    1050                 :            :     /*
    1051                 :            :      * Check whether the first call for this tuple, and initialize or restore
    1052                 :            :      * loop state.
    1053                 :            :      */
    1054                 :   88855796 :     attnum = slot->tts_nvalid;
    1055         [ +  + ]:   88855796 :     if (attnum == 0)
    1056                 :            :     {
    1057                 :            :         /* Start from the first attribute */
    1058                 :   65223490 :         off = 0;
    1059                 :   65223490 :         slow = false;
    1060                 :            :     }
    1061                 :            :     else
    1062                 :            :     {
    1063                 :            :         /* Restore state from previous execution */
    1064                 :   23632306 :         off = slot->tts_off;
    1065                 :   23632306 :         slow = slot->tts_slow;
    1066                 :            :     }
    1067                 :            : 
    1068                 :   88855796 :     tp = (char *) tup + tup->t_hoff;
    1069                 :            : 
    1070         [ +  + ]:  409074130 :     for (; attnum < natts; attnum++)
    1071                 :            :     {
    1072                 :  320218334 :         Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
    1073                 :            : 
    1074 [ +  + ][ +  + ]:  320218334 :         if (hasnulls && att_isnull(attnum, bp))
    1075                 :            :         {
    1076                 :   15017846 :             values[attnum] = (Datum) 0;
    1077                 :   15017846 :             isnull[attnum] = true;
    1078                 :   15017846 :             slow = true;        /* can't use attcacheoff anymore */
    1079                 :   15017846 :             continue;
    1080                 :            :         }
    1081                 :            : 
    1082                 :  305200488 :         isnull[attnum] = false;
    1083                 :            : 
    1084 [ +  + ][ +  + ]:  305200488 :         if (!slow && thisatt->attcacheoff >= 0)
    1085                 :  287035434 :             off = thisatt->attcacheoff;
    1086         [ +  + ]:   18165054 :         else if (thisatt->attlen == -1)
    1087                 :            :         {
    1088                 :            :             /*
    1089                 :            :              * We can only cache the offset for a varlena attribute if the
    1090                 :            :              * offset is already suitably aligned, so that there would be no
    1091                 :            :              * pad bytes in any case: then the offset will be valid for either
    1092                 :            :              * an aligned or unaligned value.
    1093                 :            :              */
    1094 [ +  + ][ +  + ]:    7526614 :             if (!slow &&
    1095 [ +  + ][ +  - ]:     550922 :                 off == att_align_nominal(off, thisatt->attalign))
                 [ +  - ]
    1096                 :      31008 :                 thisatt->attcacheoff = off;
    1097                 :            :             else
    1098                 :            :             {
    1099 [ +  + ][ +  + ]:    6944684 :                 off = att_align_pointer(off, thisatt->attalign, -1,
         [ +  - ][ +  - ]
    1100                 :            :                                         tp + off);
    1101                 :    6975692 :                 slow = true;
    1102                 :            :             }
    1103                 :            :         }
    1104                 :            :         else
    1105                 :            :         {
    1106                 :            :             /* not varlena, so safe to use att_align_nominal */
    1107 [ +  + ][ +  + ]:   11189362 :             off = att_align_nominal(off, thisatt->attalign);
                 [ +  + ]
    1108                 :            : 
    1109         [ +  + ]:   11189362 :             if (!slow)
    1110                 :     275756 :                 thisatt->attcacheoff = off;
    1111                 :            :         }
    1112                 :            : 
    1113 [ +  + ][ +  + ]:  305200488 :         values[attnum] = fetchatt(thisatt, tp + off);
         [ +  + ][ +  + ]
    1114                 :            : 
    1115 [ +  + ][ +  - ]:  305200488 :         off = att_addlength_pointer(off, thisatt->attlen, tp + off);
         [ +  + ][ +  + ]
         [ +  - ][ +  - ]
                 [ +  + ]
    1116                 :            : 
    1117         [ +  + ]:  305200488 :         if (thisatt->attlen <= 0)
    1118                 :   20461772 :             slow = true;        /* can't use attcacheoff anymore */
    1119                 :            :     }
    1120                 :            : 
    1121                 :            :     /*
    1122                 :            :      * Save state for next execution
    1123                 :            :      */
    1124                 :   88855796 :     slot->tts_nvalid = attnum;
    1125                 :   88855796 :     slot->tts_off = off;
    1126                 :   88855796 :     slot->tts_slow = slow;
    1127                 :   88855796 : }
    1128                 :            : 
    1129                 :            : /*
    1130                 :            :  * slot_getattr
    1131                 :            :  *      This function fetches an attribute of the slot's current tuple.
    1132                 :            :  *      It is functionally equivalent to heap_getattr, but fetches of
    1133                 :            :  *      multiple attributes of the same tuple will be optimized better,
    1134                 :            :  *      because we avoid O(N^2) behavior from multiple calls of
    1135                 :            :  *      nocachegetattr(), even when attcacheoff isn't usable.
    1136                 :            :  *
    1137                 :            :  *      A difference from raw heap_getattr is that attnums beyond the
    1138                 :            :  *      slot's tupdesc's last attribute will be considered NULL even
    1139                 :            :  *      when the physical tuple is longer than the tupdesc.
    1140                 :            :  */
    1141                 :            : Datum
    1142                 :   79032754 : slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
    1143                 :            : {
    1144                 :   79032754 :     HeapTuple   tuple = slot->tts_tuple;
    1145                 :   79032754 :     TupleDesc   tupleDesc = slot->tts_tupleDescriptor;
    1146                 :            :     HeapTupleHeader tup;
    1147                 :            : 
    1148                 :            :     /*
    1149                 :            :      * system attributes are handled by heap_getsysattr
    1150                 :            :      */
    1151         [ +  + ]:   79032754 :     if (attnum <= 0)
    1152                 :            :     {
    1153         [ -  + ]:    2296770 :         if (tuple == NULL)      /* internal error */
    1154                 :          0 :             elog(ERROR, "cannot extract system attribute from virtual tuple");
    1155         [ -  + ]:    2296770 :         if (tuple == &(slot->tts_minhdr))    /* internal error */
    1156                 :          0 :             elog(ERROR, "cannot extract system attribute from minimal tuple");
    1157                 :    2296770 :         return heap_getsysattr(tuple, attnum, tupleDesc, isnull);
    1158                 :            :     }
    1159                 :            : 
    1160                 :            :     /*
    1161                 :            :      * fast path if desired attribute already cached
    1162                 :            :      */
    1163         [ +  + ]:   76735984 :     if (attnum <= slot->tts_nvalid)
    1164                 :            :     {
    1165                 :   32022454 :         *isnull = slot->tts_isnull[attnum - 1];
    1166                 :   32022454 :         return slot->tts_values[attnum - 1];
    1167                 :            :     }
    1168                 :            : 
    1169                 :            :     /*
    1170                 :            :      * return NULL if attnum is out of range according to the tupdesc
    1171                 :            :      */
    1172         [ -  + ]:   44713530 :     if (attnum > tupleDesc->natts)
    1173                 :            :     {
    1174                 :          0 :         *isnull = true;
    1175                 :          0 :         return (Datum) 0;
    1176                 :            :     }
    1177                 :            : 
    1178                 :            :     /*
    1179                 :            :      * otherwise we had better have a physical tuple (tts_nvalid should equal
    1180                 :            :      * natts in all virtual-tuple cases)
    1181                 :            :      */
    1182         [ -  + ]:   44713530 :     if (tuple == NULL)          /* internal error */
    1183                 :          0 :         elog(ERROR, "cannot extract attribute from empty tuple slot");
    1184                 :            : 
    1185                 :            :     /*
    1186                 :            :      * return NULL if attnum is out of range according to the tuple
    1187                 :            :      *
    1188                 :            :      * (We have to check this separately because of various inheritance and
    1189                 :            :      * table-alteration scenarios: the tuple could be either longer or shorter
    1190                 :            :      * than the tupdesc.)
    1191                 :            :      */
    1192                 :   44713530 :     tup = tuple->t_data;
    1193         [ +  + ]:   44713530 :     if (attnum > HeapTupleHeaderGetNatts(tup))
    1194                 :            :     {
    1195                 :          4 :         *isnull = true;
    1196                 :          4 :         return (Datum) 0;
    1197                 :            :     }
    1198                 :            : 
    1199                 :            :     /*
    1200                 :            :      * check if target attribute is null: no point in groveling through tuple
    1201                 :            :      */
    1202 [ +  + ][ +  + ]:   44713526 :     if (HeapTupleHasNulls(tuple) && att_isnull(attnum - 1, tup->t_bits))
    1203                 :            :     {
    1204                 :      21124 :         *isnull = true;
    1205                 :      21124 :         return (Datum) 0;
    1206                 :            :     }
    1207                 :            : 
    1208                 :            :     /*
    1209                 :            :      * If the attribute's column has been dropped, we force a NULL result.
    1210                 :            :      * This case should not happen in normal use, but it could happen if we
    1211                 :            :      * are executing a plan cached before the column was dropped.
    1212                 :            :      */
    1213         [ -  + ]:   44692402 :     if (TupleDescAttr(tupleDesc, attnum - 1)->attisdropped)
    1214                 :            :     {
    1215                 :          0 :         *isnull = true;
    1216                 :          0 :         return (Datum) 0;
    1217                 :            :     }
    1218                 :            : 
    1219                 :            :     /*
    1220                 :            :      * Extract the attribute, along with any preceding attributes.
    1221                 :            :      */
    1222                 :   44692402 :     slot_deform_tuple(slot, attnum);
    1223                 :            : 
    1224                 :            :     /*
    1225                 :            :      * The result is acquired from tts_values array.
    1226                 :            :      */
    1227                 :   44692402 :     *isnull = slot->tts_isnull[attnum - 1];
    1228                 :   44692402 :     return slot->tts_values[attnum - 1];
    1229                 :            : }
    1230                 :            : 
    1231                 :            : /*
    1232                 :            :  * slot_getallattrs
    1233                 :            :  *      This function forces all the entries of the slot's Datum/isnull
    1234                 :            :  *      arrays to be valid.  The caller may then extract data directly
    1235                 :            :  *      from those arrays instead of using slot_getattr.
    1236                 :            :  */
    1237                 :            : void
    1238                 :    2614400 : slot_getallattrs(TupleTableSlot *slot)
    1239                 :            : {
    1240                 :    2614400 :     int         tdesc_natts = slot->tts_tupleDescriptor->natts;
    1241                 :            :     int         attnum;
    1242                 :            :     HeapTuple   tuple;
    1243                 :            : 
    1244                 :            :     /* Quick out if we have 'em all already */
    1245         [ +  + ]:    2614400 :     if (slot->tts_nvalid == tdesc_natts)
    1246                 :     868080 :         return;
    1247                 :            : 
    1248                 :            :     /*
    1249                 :            :      * otherwise we had better have a physical tuple (tts_nvalid should equal
    1250                 :            :      * natts in all virtual-tuple cases)
    1251                 :            :      */
    1252                 :    1746320 :     tuple = slot->tts_tuple;
    1253         [ -  + ]:    1746320 :     if (tuple == NULL)          /* internal error */
    1254                 :          0 :         elog(ERROR, "cannot extract attribute from empty tuple slot");
    1255                 :            : 
    1256                 :            :     /*
    1257                 :            :      * load up any slots available from physical tuple
    1258                 :            :      */
    1259                 :    1746320 :     attnum = HeapTupleHeaderGetNatts(tuple->t_data);
    1260                 :    1746320 :     attnum = Min(attnum, tdesc_natts);
    1261                 :            : 
    1262                 :    1746320 :     slot_deform_tuple(slot, attnum);
    1263                 :            : 
    1264                 :            :     /*
    1265                 :            :      * If tuple doesn't have all the atts indicated by tupleDesc, read the
    1266                 :            :      * rest as null
    1267                 :            :      */
    1268         [ +  + ]:    1746360 :     for (; attnum < tdesc_natts; attnum++)
    1269                 :            :     {
    1270                 :         40 :         slot->tts_values[attnum] = (Datum) 0;
    1271                 :         40 :         slot->tts_isnull[attnum] = true;
    1272                 :            :     }
    1273                 :    1746320 :     slot->tts_nvalid = tdesc_natts;
    1274                 :            : }
    1275                 :            : 
    1276                 :            : /*
    1277                 :            :  * slot_getsomeattrs
    1278                 :            :  *      This function forces the entries of the slot's Datum/isnull
    1279                 :            :  *      arrays to be valid at least up through the attnum'th entry.
    1280                 :            :  */
    1281                 :            : void
    1282                 :   66174378 : slot_getsomeattrs(TupleTableSlot *slot, int attnum)
    1283                 :            : {
    1284                 :            :     HeapTuple   tuple;
    1285                 :            :     int         attno;
    1286                 :            : 
    1287                 :            :     /* Quick out if we have 'em all already */
    1288         [ +  + ]:   66174378 :     if (slot->tts_nvalid >= attnum)
    1289                 :   23757304 :         return;
    1290                 :            : 
    1291                 :            :     /* Check for caller error */
    1292 [ +  - ][ -  + ]:   42417074 :     if (attnum <= 0 || attnum > slot->tts_tupleDescriptor->natts)
    1293                 :          0 :         elog(ERROR, "invalid attribute number %d", attnum);
    1294                 :            : 
    1295                 :            :     /*
    1296                 :            :      * otherwise we had better have a physical tuple (tts_nvalid should equal
    1297                 :            :      * natts in all virtual-tuple cases)
    1298                 :            :      */
    1299                 :   42417074 :     tuple = slot->tts_tuple;
    1300         [ -  + ]:   42417074 :     if (tuple == NULL)          /* internal error */
    1301                 :          0 :         elog(ERROR, "cannot extract attribute from empty tuple slot");
    1302                 :            : 
    1303                 :            :     /*
    1304                 :            :      * load up any slots available from physical tuple
    1305                 :            :      */
    1306                 :   42417074 :     attno = HeapTupleHeaderGetNatts(tuple->t_data);
    1307                 :   42417074 :     attno = Min(attno, attnum);
    1308                 :            : 
    1309                 :   42417074 :     slot_deform_tuple(slot, attno);
    1310                 :            : 
    1311                 :            :     /*
    1312                 :            :      * If tuple doesn't have all the atts indicated by tupleDesc, read the
    1313                 :            :      * rest as null
    1314                 :            :      */
    1315         [ +  + ]:   42417512 :     for (; attno < attnum; attno++)
    1316                 :            :     {
    1317                 :        438 :         slot->tts_values[attno] = (Datum) 0;
    1318                 :        438 :         slot->tts_isnull[attno] = true;
    1319                 :            :     }
    1320                 :   42417074 :     slot->tts_nvalid = attnum;
    1321                 :            : }
    1322                 :            : 
    1323                 :            : /*
    1324                 :            :  * slot_attisnull
    1325                 :            :  *      Detect whether an attribute of the slot is null, without
    1326                 :            :  *      actually fetching it.
    1327                 :            :  */
    1328                 :            : bool
    1329                 :   19216136 : slot_attisnull(TupleTableSlot *slot, int attnum)
    1330                 :            : {
    1331                 :   19216136 :     HeapTuple   tuple = slot->tts_tuple;
    1332                 :   19216136 :     TupleDesc   tupleDesc = slot->tts_tupleDescriptor;
    1333                 :            : 
    1334                 :            :     /*
    1335                 :            :      * system attributes are handled by heap_attisnull
    1336                 :            :      */
    1337         [ -  + ]:   19216136 :     if (attnum <= 0)
    1338                 :            :     {
    1339         [ #  # ]:          0 :         if (tuple == NULL)      /* internal error */
    1340                 :          0 :             elog(ERROR, "cannot extract system attribute from virtual tuple");
    1341         [ #  # ]:          0 :         if (tuple == &(slot->tts_minhdr))    /* internal error */
    1342                 :          0 :             elog(ERROR, "cannot extract system attribute from minimal tuple");
    1343                 :          0 :         return heap_attisnull(tuple, attnum);
    1344                 :            :     }
    1345                 :            : 
    1346                 :            :     /*
    1347                 :            :      * fast path if desired attribute already cached
    1348                 :            :      */
    1349         [ +  + ]:   19216136 :     if (attnum <= slot->tts_nvalid)
    1350                 :     615218 :         return slot->tts_isnull[attnum - 1];
    1351                 :            : 
    1352                 :            :     /*
    1353                 :            :      * return NULL if attnum is out of range according to the tupdesc
    1354                 :            :      */
    1355         [ -  + ]:   18600918 :     if (attnum > tupleDesc->natts)
    1356                 :          0 :         return true;
    1357                 :            : 
    1358                 :            :     /*
    1359                 :            :      * otherwise we had better have a physical tuple (tts_nvalid should equal
    1360                 :            :      * natts in all virtual-tuple cases)
    1361                 :            :      */
    1362         [ -  + ]:   18600918 :     if (tuple == NULL)          /* internal error */
    1363                 :          0 :         elog(ERROR, "cannot extract attribute from empty tuple slot");
    1364                 :            : 
    1365                 :            :     /* and let the tuple tell it */
    1366                 :   18600918 :     return heap_attisnull(tuple, attnum);
    1367                 :            : }
    1368                 :            : 
    1369                 :            : /*
    1370                 :            :  * heap_freetuple
    1371                 :            :  */
    1372                 :            : void
    1373                 :   16232140 : heap_freetuple(HeapTuple htup)
    1374                 :            : {
    1375                 :   16232140 :     pfree(htup);
    1376                 :   16232140 : }
    1377                 :            : 
    1378                 :            : 
    1379                 :            : /*
    1380                 :            :  * heap_form_minimal_tuple
    1381                 :            :  *      construct a MinimalTuple from the given values[] and isnull[] arrays,
    1382                 :            :  *      which are of the length indicated by tupleDescriptor->natts
    1383                 :            :  *
    1384                 :            :  * This is exactly like heap_form_tuple() except that the result is a
    1385                 :            :  * "minimal" tuple lacking a HeapTupleData header as well as room for system
    1386                 :            :  * columns.
    1387                 :            :  *
    1388                 :            :  * The result is allocated in the current memory context.
    1389                 :            :  */
    1390                 :            : MinimalTuple
    1391                 :   18661652 : heap_form_minimal_tuple(TupleDesc tupleDescriptor,
    1392                 :            :                         Datum *values,
    1393                 :            :                         bool *isnull)
    1394                 :            : {
    1395                 :            :     MinimalTuple tuple;         /* return tuple */
    1396                 :            :     Size        len,
    1397                 :            :                 data_len;
    1398                 :            :     int         hoff;
    1399                 :   18661652 :     bool        hasnull = false;
    1400                 :   18661652 :     int         numberOfAttributes = tupleDescriptor->natts;
    1401                 :            :     int         i;
    1402                 :            : 
    1403         [ -  + ]:   18661652 :     if (numberOfAttributes > MaxTupleAttributeNumber)
    1404         [ #  # ]:          0 :         ereport(ERROR,
    1405                 :            :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
    1406                 :            :                  errmsg("number of columns (%d) exceeds limit (%d)",
    1407                 :            :                         numberOfAttributes, MaxTupleAttributeNumber)));
    1408                 :            : 
    1409                 :            :     /*
    1410                 :            :      * Check for nulls
    1411                 :            :      */
    1412         [ +  + ]:   55171272 :     for (i = 0; i < numberOfAttributes; i++)
    1413                 :            :     {
    1414         [ +  + ]:   37155650 :         if (isnull[i])
    1415                 :            :         {
    1416                 :     646030 :             hasnull = true;
    1417                 :     646030 :             break;
    1418                 :            :         }
    1419                 :            :     }
    1420                 :            : 
    1421                 :            :     /*
    1422                 :            :      * Determine total space needed
    1423                 :            :      */
    1424                 :   18661652 :     len = SizeofMinimalTupleHeader;
    1425                 :            : 
    1426         [ +  + ]:   18661652 :     if (hasnull)
    1427                 :     646030 :         len += BITMAPLEN(numberOfAttributes);
    1428                 :            : 
    1429         [ -  + ]:   18661652 :     if (tupleDescriptor->tdhasoid)
    1430                 :          0 :         len += sizeof(Oid);
    1431                 :            : 
    1432                 :   18661652 :     hoff = len = MAXALIGN(len); /* align user data safely */
    1433                 :            : 
    1434                 :   18661652 :     data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
    1435                 :            : 
    1436                 :   18661652 :     len += data_len;
    1437                 :            : 
    1438                 :            :     /*
    1439                 :            :      * Allocate and zero the space needed.
    1440                 :            :      */
    1441                 :   18661652 :     tuple = (MinimalTuple) palloc0(len);
    1442                 :            : 
    1443                 :            :     /*
    1444                 :            :      * And fill in the information.
    1445                 :            :      */
    1446                 :   18661652 :     tuple->t_len = len;
    1447                 :   18661652 :     HeapTupleHeaderSetNatts(tuple, numberOfAttributes);
    1448                 :   18661652 :     tuple->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
    1449                 :            : 
    1450         [ -  + ]:   18661652 :     if (tupleDescriptor->tdhasoid)   /* else leave infomask = 0 */
    1451                 :          0 :         tuple->t_infomask = HEAP_HASOID;
    1452                 :            : 
    1453         [ +  + ]:   18661652 :     heap_fill_tuple(tupleDescriptor,
    1454                 :            :                     values,
    1455                 :            :                     isnull,
    1456                 :            :                     (char *) tuple + hoff,
    1457                 :            :                     data_len,
    1458                 :            :                     &tuple->t_infomask,
    1459                 :            :                     (hasnull ? tuple->t_bits : NULL));
    1460                 :            : 
    1461                 :   18661652 :     return tuple;
    1462                 :            : }
    1463                 :            : 
    1464                 :            : /*
    1465                 :            :  * heap_free_minimal_tuple
    1466                 :            :  */
    1467                 :            : void
    1468                 :   13018514 : heap_free_minimal_tuple(MinimalTuple mtup)
    1469                 :            : {
    1470                 :   13018514 :     pfree(mtup);
    1471                 :   13018514 : }
    1472                 :            : 
    1473                 :            : /*
    1474                 :            :  * heap_copy_minimal_tuple
    1475                 :            :  *      copy a MinimalTuple
    1476                 :            :  *
    1477                 :            :  * The result is allocated in the current memory context.
    1478                 :            :  */
    1479                 :            : MinimalTuple
    1480                 :     571084 : heap_copy_minimal_tuple(MinimalTuple mtup)
    1481                 :            : {
    1482                 :            :     MinimalTuple result;
    1483                 :            : 
    1484                 :     571084 :     result = (MinimalTuple) palloc(mtup->t_len);
    1485                 :     571084 :     memcpy(result, mtup, mtup->t_len);
    1486                 :     571084 :     return result;
    1487                 :            : }
    1488                 :            : 
    1489                 :            : /*
    1490                 :            :  * heap_tuple_from_minimal_tuple
    1491                 :            :  *      create a HeapTuple by copying from a MinimalTuple;
    1492                 :            :  *      system columns are filled with zeroes
    1493                 :            :  *
    1494                 :            :  * The result is allocated in the current memory context.
    1495                 :            :  * The HeapTuple struct, tuple header, and tuple data are all allocated
    1496                 :            :  * as a single palloc() block.
    1497                 :            :  */
    1498                 :            : HeapTuple
    1499                 :     288086 : heap_tuple_from_minimal_tuple(MinimalTuple mtup)
    1500                 :            : {
    1501                 :            :     HeapTuple   result;
    1502                 :     288086 :     uint32      len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
    1503                 :            : 
    1504                 :     288086 :     result = (HeapTuple) palloc(HEAPTUPLESIZE + len);
    1505                 :     288086 :     result->t_len = len;
    1506                 :     288086 :     ItemPointerSetInvalid(&(result->t_self));
    1507                 :     288086 :     result->t_tableOid = InvalidOid;
    1508                 :     288086 :     result->t_data = (HeapTupleHeader) ((char *) result + HEAPTUPLESIZE);
    1509                 :     288086 :     memcpy((char *) result->t_data + MINIMAL_TUPLE_OFFSET, mtup, mtup->t_len);
    1510                 :     288086 :     memset(result->t_data, 0, offsetof(HeapTupleHeaderData, t_infomask2));
    1511                 :     288086 :     return result;
    1512                 :            : }
    1513                 :            : 
    1514                 :            : /*
    1515                 :            :  * minimal_tuple_from_heap_tuple
    1516                 :            :  *      create a MinimalTuple by copying from a HeapTuple
    1517                 :            :  *
    1518                 :            :  * The result is allocated in the current memory context.
    1519                 :            :  */
    1520                 :            : MinimalTuple
    1521                 :     280158 : minimal_tuple_from_heap_tuple(HeapTuple htup)
    1522                 :            : {
    1523                 :            :     MinimalTuple result;
    1524                 :            :     uint32      len;
    1525                 :            : 
    1526                 :            :     Assert(htup->t_len > MINIMAL_TUPLE_OFFSET);
    1527                 :     280158 :     len = htup->t_len - MINIMAL_TUPLE_OFFSET;
    1528                 :     280158 :     result = (MinimalTuple) palloc(len);
    1529                 :     280158 :     memcpy(result, (char *) htup->t_data + MINIMAL_TUPLE_OFFSET, len);
    1530                 :     280158 :     result->t_len = len;
    1531                 :     280158 :     return result;
    1532                 :            : }

Generated by: LCOV version 1.13