LCOV - differential code coverage report
Current view: top level - src/backend/access/common - indextuple.c (source / functions) Coverage Total Hit UNC UBC GIC GNC CBC ECB DUB DCB
Current: bed3ffbf9d952be6c7d739d068cdce44c046dfb7 vs 574581b50ac9c63dd9e4abebb731a3b67e5b50f6 Lines: 93.9 % 164 154 7 3 74 80 2 4 86
Current Date: 2026-05-05 10:23:31 +0900 Functions: 100.0 % 7 7 4 3
Baseline: lcov-20260505-025707-baseline Branches: 72.6 % 124 90 22 12 2 50 38 2 22 86
Baseline Date: 2026-05-05 10:27:06 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 91.5 % 82 75 7 74 1
(360..) days: 96.3 % 82 79 3 79 2
Function coverage date bins:
(360..) days: 100.0 % 7 7 4 3
Branch coverage date bins:
(30,360] days: 69.4 % 72 50 22 50
(360..) days: 74.1 % 54 40 12 2 38 2

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * indextuple.c
                                  4                 :                :  *     This file contains index tuple accessor and mutator routines,
                                  5                 :                :  *     as well as various tuple utilities.
                                  6                 :                :  *
                                  7                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                  8                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  9                 :                :  *
                                 10                 :                :  *
                                 11                 :                :  * IDENTIFICATION
                                 12                 :                :  *    src/backend/access/common/indextuple.c
                                 13                 :                :  *
                                 14                 :                :  *-------------------------------------------------------------------------
                                 15                 :                :  */
                                 16                 :                : 
                                 17                 :                : #include "postgres.h"
                                 18                 :                : 
                                 19                 :                : #include "access/detoast.h"
                                 20                 :                : #include "access/heaptoast.h"
                                 21                 :                : #include "access/htup_details.h"
                                 22                 :                : #include "access/itup.h"
                                 23                 :                : #include "access/toast_internals.h"
                                 24                 :                : 
                                 25                 :                : /*
                                 26                 :                :  * This enables de-toasting of index entries.  Needed until VACUUM is
                                 27                 :                :  * smart enough to rebuild indexes from scratch.
                                 28                 :                :  */
                                 29                 :                : #define TOAST_INDEX_HACK
                                 30                 :                : 
                                 31                 :                : /* ----------------------------------------------------------------
                                 32                 :                :  *                index_ tuple interface routines
                                 33                 :                :  * ----------------------------------------------------------------
                                 34                 :                :  */
                                 35                 :                : 
                                 36                 :                :  /* ----------------
                                 37                 :                :   *     index_form_tuple
                                 38                 :                :   *
                                 39                 :                :   *     As index_form_tuple_context, but allocates the returned tuple in the
                                 40                 :                :   *     CurrentMemoryContext.
                                 41                 :                :   * ----------------
                                 42                 :                :   */
                                 43                 :                : IndexTuple
 1398 drowley@postgresql.o       44                 :CBC     9410281 : index_form_tuple(TupleDesc tupleDescriptor,
                                 45                 :                :                  const Datum *values,
                                 46                 :                :                  const bool *isnull)
                                 47                 :                : {
                                 48                 :        9410281 :     return index_form_tuple_context(tupleDescriptor, values, isnull,
                                 49                 :                :                                     CurrentMemoryContext);
                                 50                 :                : }
                                 51                 :                : 
                                 52                 :                : /* ----------------
                                 53                 :                :  *      index_form_tuple_context
                                 54                 :                :  *
                                 55                 :                :  *      This shouldn't leak any memory; otherwise, callers such as
                                 56                 :                :  *      tuplesort_putindextuplevalues() will be very unhappy.
                                 57                 :                :  *
                                 58                 :                :  *      This shouldn't perform external table access provided caller
                                 59                 :                :  *      does not pass values that are stored EXTERNAL.
                                 60                 :                :  *
                                 61                 :                :  *      Allocates returned tuple in provided 'context'.
                                 62                 :                :  * ----------------
                                 63                 :                :  */
                                 64                 :                : IndexTuple
                                 65                 :       17579590 : index_form_tuple_context(TupleDesc tupleDescriptor,
                                 66                 :                :                          const Datum *values,
                                 67                 :                :                          const bool *isnull,
                                 68                 :                :                          MemoryContext context)
                                 69                 :                : {
                                 70                 :                :     char       *tp;             /* tuple pointer */
                                 71                 :                :     IndexTuple  tuple;          /* return tuple */
                                 72                 :                :     Size        size,
                                 73                 :                :                 data_size,
                                 74                 :                :                 hoff;
                                 75                 :                :     int         i;
10466 bruce@momjian.us           76                 :       17579590 :     unsigned short infomask = 0;
                                 77                 :       17579590 :     bool        hasnull = false;
10411 vadim4o@yahoo.com          78                 :       17579590 :     uint16      tupmask = 0;
10466 bruce@momjian.us           79                 :       17579590 :     int         numberOfAttributes = tupleDescriptor->natts;
                                 80                 :                : 
                                 81                 :                : #ifdef TOAST_INDEX_HACK
  938 peter@eisentraut.org       82                 :       17579590 :     Datum       untoasted_values[INDEX_MAX_KEYS] = {0};
                                 83                 :       17579590 :     bool        untoasted_free[INDEX_MAX_KEYS] = {0};
                                 84                 :                : #endif
                                 85                 :                : 
 9611 bruce@momjian.us           86         [ -  + ]:       17579590 :     if (numberOfAttributes > INDEX_MAX_KEYS)
 8324 tgl@sss.pgh.pa.us          87         [ #  # ]:UBC           0 :         ereport(ERROR,
                                 88                 :                :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
                                 89                 :                :                  errmsg("number of index columns (%d) exceeds limit (%d)",
                                 90                 :                :                         numberOfAttributes, INDEX_MAX_KEYS)));
                                 91                 :                : 
                                 92                 :                : #ifdef TOAST_INDEX_HACK
 9418 JanWieck@Yahoo.com         93         [ +  + ]:CBC    44784591 :     for (i = 0; i < numberOfAttributes; i++)
                                 94                 :                :     {
 3180 andres@anarazel.de         95                 :       27205001 :         Form_pg_attribute att = TupleDescAttr(tupleDescriptor, i);
                                 96                 :                : 
 7715 tgl@sss.pgh.pa.us          97                 :       27205001 :         untoasted_values[i] = values[i];
 9210                            98                 :       27205001 :         untoasted_free[i] = false;
                                 99                 :                : 
                                100                 :                :         /* Do nothing if value is NULL or not of varlena type */
 7715                           101   [ +  +  +  + ]:       27205001 :         if (isnull[i] || att->attlen != -1)
 9210                           102                 :       26345856 :             continue;
                                103                 :                : 
                                104                 :                :         /*
                                105                 :                :          * If value is stored EXTERNAL, must fetch it so we are not depending
                                106                 :                :          * on outside storage.  This should be improved someday.
                                107                 :                :          */
 6592 alvherre@alvh.no-ip.      108         [ +  + ]:         859145 :         if (VARATT_IS_EXTERNAL(DatumGetPointer(values[i])))
                                109                 :                :         {
 6969 tgl@sss.pgh.pa.us         110                 :            241 :             untoasted_values[i] =
   83 michael@paquier.xyz       111                 :GNC         241 :                 PointerGetDatum(detoast_external_attr((varlena *)
 3240 tgl@sss.pgh.pa.us         112                 :ECB       (181) :                                                       DatumGetPointer(values[i])));
 9210 tgl@sss.pgh.pa.us         113                 :CBC         241 :             untoasted_free[i] = true;
                                114                 :                :         }
                                115                 :                : 
                                116                 :                :         /*
                                117                 :                :          * If value is above size target, and is of a compressible datatype,
                                118                 :                :          * try to compress it in-line.
                                119                 :                :          */
 6592 alvherre@alvh.no-ip.      120   [ +  +  +  + ]:        1323897 :         if (!VARATT_IS_EXTENDED(DatumGetPointer(untoasted_values[i])) &&
 3240 tgl@sss.pgh.pa.us         121         [ +  + ]:         464752 :             VARSIZE(DatumGetPointer(untoasted_values[i])) > TOAST_INDEX_TARGET &&
 2253                           122         [ +  + ]:          64801 :             (att->attstorage == TYPSTORAGE_EXTENDED ||
                                123         [ -  + ]:          58187 :              att->attstorage == TYPSTORAGE_MAIN))
                                124                 :                :         {
                                125                 :                :             Datum       cvalue;
                                126                 :                : 
 1804                           127                 :           6614 :             cvalue = toast_compress_datum(untoasted_values[i],
                                128                 :           6614 :                                           att->attcompression);
                                129                 :                : 
 9210                           130         [ +  + ]:           6614 :             if (DatumGetPointer(cvalue) != NULL)
                                131                 :                :             {
                                132                 :                :                 /* successful compression */
                                133         [ -  + ]:           1831 :                 if (untoasted_free[i])
 7715 tgl@sss.pgh.pa.us         134                 :UBC           0 :                     pfree(DatumGetPointer(untoasted_values[i]));
 7715 tgl@sss.pgh.pa.us         135                 :CBC        1831 :                 untoasted_values[i] = cvalue;
 9418 JanWieck@Yahoo.com        136                 :           1831 :                 untoasted_free[i] = true;
                                137                 :                :             }
                                138                 :                :         }
                                139                 :                :     }
                                140                 :                : #endif
                                141                 :                : 
 9355 tgl@sss.pgh.pa.us         142         [ +  + ]:       44726424 :     for (i = 0; i < numberOfAttributes; i++)
                                143                 :                :     {
 7715                           144         [ +  + ]:       27203465 :         if (isnull[i])
                                145                 :                :         {
10467 bruce@momjian.us          146                 :          56631 :             hasnull = true;
 9355 tgl@sss.pgh.pa.us         147                 :          56631 :             break;
                                148                 :                :         }
                                149                 :                :     }
                                150                 :                : 
10467 bruce@momjian.us          151         [ +  + ]:       17579590 :     if (hasnull)
                                152                 :          56631 :         infomask |= INDEX_NULL_MASK;
                                153                 :                : 
                                154                 :       17579590 :     hoff = IndexInfoFindDataOffset(infomask);
                                155                 :                : #ifdef TOAST_INDEX_HACK
 6969 tgl@sss.pgh.pa.us         156                 :       17579590 :     data_size = heap_compute_data_size(tupleDescriptor,
                                157                 :                :                                        untoasted_values, isnull);
                                158                 :                : #else
                                159                 :                :     data_size = heap_compute_data_size(tupleDescriptor,
                                160                 :                :                                        values, isnull);
                                161                 :                : #endif
                                162                 :       17579590 :     size = hoff + data_size;
 9519 bruce@momjian.us          163                 :       17579590 :     size = MAXALIGN(size);      /* be conservative */
                                164                 :                : 
 1398 drowley@postgresql.o      165                 :       17579590 :     tp = (char *) MemoryContextAllocZero(context, size);
10467 bruce@momjian.us          166                 :       17579590 :     tuple = (IndexTuple) tp;
                                167                 :                : 
 7715 tgl@sss.pgh.pa.us         168         [ +  + ]:       17579590 :     heap_fill_tuple(tupleDescriptor,
                                169                 :                : #ifdef TOAST_INDEX_HACK
                                170                 :                :                     untoasted_values,
                                171                 :                : #else
                                172                 :                :                     values,
                                173                 :                : #endif
                                174                 :                :                     isnull,
                                175                 :                :                     tp + hoff,
                                176                 :                :                     data_size,
                                177                 :                :                     &tupmask,
                                178                 :                :                     (hasnull ? (uint8 *) tp + sizeof(IndexTupleData) : NULL));
                                179                 :                : 
                                180                 :                : #ifdef TOAST_INDEX_HACK
 9418 JanWieck@Yahoo.com        181         [ +  + ]:       44784591 :     for (i = 0; i < numberOfAttributes; i++)
                                182                 :                :     {
                                183         [ +  + ]:       27205001 :         if (untoasted_free[i])
 7715 tgl@sss.pgh.pa.us         184                 :           2072 :             pfree(DatumGetPointer(untoasted_values[i]));
                                185                 :                :     }
                                186                 :                : #endif
                                187                 :                : 
                                188                 :                :     /*
                                189                 :                :      * We do this because heap_fill_tuple wants to initialize a "tupmask"
                                190                 :                :      * which is used for HeapTuples, but we want an indextuple infomask. The
                                191                 :                :      * only relevant info is the "has variable attributes" field. We have
                                192                 :                :      * already set the hasnull bit above.
                                193                 :                :      */
 8654                           194         [ +  + ]:       17579590 :     if (tupmask & HEAP_HASVARWIDTH)
10467 bruce@momjian.us          195                 :        2137156 :         infomask |= INDEX_VAR_MASK;
                                196                 :                : 
                                197                 :                :     /* Also assert we got rid of external attributes */
                                198                 :                : #ifdef TOAST_INDEX_HACK
 4387 tgl@sss.pgh.pa.us         199         [ -  + ]:       17579590 :     Assert((tupmask & HEAP_HASEXTERNAL) == 0);
                                200                 :                : #endif
                                201                 :                : 
                                202                 :                :     /*
                                203                 :                :      * Here we make sure that the size will fit in the field reserved for it
                                204                 :                :      * in t_info.
                                205                 :                :      */
 9355                           206         [ -  + ]:       17579590 :     if ((size & INDEX_SIZE_MASK) != size)
 8324 tgl@sss.pgh.pa.us         207         [ #  # ]:UBC           0 :         ereport(ERROR,
                                208                 :                :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                209                 :                :                  errmsg("index row requires %zu bytes, maximum size is %zu",
                                210                 :                :                         size, (Size) INDEX_SIZE_MASK)));
                                211                 :                : 
10467 bruce@momjian.us          212                 :CBC    17579590 :     infomask |= size;
                                213                 :                : 
                                214                 :                :     /*
                                215                 :                :      * initialize metadata
                                216                 :                :      */
                                217                 :       17579590 :     tuple->t_info = infomask;
10108                           218                 :       17579590 :     return tuple;
                                219                 :                : }
                                220                 :                : 
                                221                 :                : /* ----------------
                                222                 :                :  *      nocache_index_getattr
                                223                 :                :  *
                                224                 :                :  *      This gets called from index_getattr() macro, and only in cases
                                225                 :                :  *      where we can't use attcacheoff and the value is not null.
                                226                 :                :  * ----------------
                                227                 :                :  */
                                228                 :                : Datum
10321                           229                 :       33043439 : nocache_index_getattr(IndexTuple tup,
                                230                 :                :                       int attnum,
                                231                 :                :                       TupleDesc tupleDesc)
                                232                 :                : {
                                233                 :                :     CompactAttribute *cattr;
                                234                 :                :     char       *tp;             /* ptr to data part of tuple */
   36 nathan@postgresql.or      235                 :GNC    33043439 :     uint8      *bp = NULL;      /* ptr to null bitmap in tuple */
                                236                 :                :     int         data_off;       /* tuple data offset */
                                237                 :                :     int         off;            /* current offset within data */
                                238                 :                :     int         startAttr;
                                239                 :                :     int         firstNullAttr;
   50 drowley@postgresql.o      240                 :       33043439 :     bool        hasnulls = IndexTupleHasNulls(tup);
                                241                 :                :     int         i;
                                242                 :                : 
                                243                 :                :     /* Did someone forget to call TupleDescFinalize()? */
                                244         [ -  + ]:       33043439 :     Assert(tupleDesc->firstNonCachedOffsetAttr >= 0);
                                245                 :                : 
 9287 tgl@sss.pgh.pa.us         246                 :CBC    33043439 :     attnum--;
                                247                 :                : 
   50 drowley@postgresql.o      248                 :GNC    33043439 :     data_off = IndexInfoFindDataOffset(tup->t_info);
   50 drowley@postgresql.o      249                 :CBC    33043439 :     tp = (char *) tup + data_off;
                                250                 :                : 
                                251                 :                :     /*
                                252                 :                :      * To minimize the number of attributes we need to look at, start walking
                                253                 :                :      * the tuple at the attribute with the highest attcacheoff prior to attnum
                                254                 :                :      * or the first NULL attribute prior to attnum, whichever comes first.
                                255                 :                :      */
   50 drowley@postgresql.o      256         [ +  + ]:GNC    33043439 :     if (hasnulls)
                                257                 :                :     {
   36 nathan@postgresql.or      258                 :          66689 :         bp = (uint8 *) ((char *) tup + sizeof(IndexTupleData));
   50 drowley@postgresql.o      259                 :          66689 :         firstNullAttr = first_null_attr(bp, attnum);
                                260                 :                :     }
                                261                 :                :     else
                                262                 :       32976750 :         firstNullAttr = attnum;
                                263                 :                : 
   49                           264   [ +  +  +  + ]:       33043439 :     if (tupleDesc->firstNonCachedOffsetAttr > 0 && firstNullAttr > 0)
                                265                 :                :     {
                                266                 :                :         /*
                                267                 :                :          * Try to start with the highest attribute with an attcacheoff that's
                                268                 :                :          * prior to the one we're looking for, or with the attribute prior to
                                269                 :                :          * the first NULL attribute, if there is one.
                                270                 :                :          */
                                271                 :        6253334 :         startAttr = Min(tupleDesc->firstNonCachedOffsetAttr - 1, firstNullAttr - 1);
   50                           272                 :        6253334 :         off = TupleDescCompactAttr(tupleDesc, startAttr)->attcacheoff;
                                273                 :                :     }
                                274                 :                :     else
                                275                 :                :     {
                                276                 :                :         /* Otherwise, start at the beginning... */
                                277                 :       26790105 :         startAttr = 0;
                                278                 :       26790105 :         off = 0;
                                279                 :                :     }
                                280                 :                : 
                                281                 :                :     /*
                                282                 :                :      * Calculate 'off' up to the first NULL attr.  We use two cheaper loops
                                283                 :                :      * when the tuple has no variable-width columns.  When variable-width
                                284                 :                :      * columns exists, we use att_addlength_pointer() to move the offset
                                285                 :                :      * beyond the current attribute.
                                286                 :                :      */
                                287         [ +  + ]:       33043439 :     if (IndexTupleHasVarwidths(tup))
                                288                 :                :     {
                                289                 :                :         /* Calculate the offset up until the first NULL */
                                290         [ +  + ]:       43633754 :         for (i = startAttr; i < firstNullAttr; i++)
                                291                 :                :         {
                                292                 :       10637714 :             cattr = TupleDescCompactAttr(tupleDesc, i);
                                293                 :                : 
                                294   [ +  +  +  + ]:       10637714 :             off = att_pointer_alignby(off,
                                295                 :                :                                       cattr->attalignby,
                                296                 :                :                                       cattr->attlen,
                                297                 :                :                                       tp + off);
                                298   [ +  +  +  +  :       10637714 :             off = att_addlength_pointer(off, cattr->attlen, tp + off);
                                              -  + ]
                                299                 :                :         }
                                300                 :                : 
                                301                 :                :         /* Calculate the offset for any remaining columns. */
                                302         [ +  + ]:       32996048 :         for (; i < attnum; i++)
                                303                 :                :         {
                                304         [ -  + ]:              8 :             Assert(hasnulls);
                                305                 :                : 
                                306         [ +  - ]:              8 :             if (att_isnull(i, bp))
                                307                 :              8 :                 continue;
                                308                 :                : 
   50 drowley@postgresql.o      309                 :UNC           0 :             cattr = TupleDescCompactAttr(tupleDesc, i);
                                310                 :                : 
                                311   [ #  #  #  # ]:              0 :             off = att_pointer_alignby(off,
                                312                 :                :                                       cattr->attalignby,
                                313                 :                :                                       cattr->attlen,
                                314                 :                :                                       tp + off);
                                315   [ #  #  #  #  :              0 :             off = att_addlength_pointer(off, cattr->attlen, tp + off);
                                              #  # ]
                                316                 :                :         }
                                317                 :                :     }
                                318                 :                :     else
                                319                 :                :     {
                                320                 :                :         /* Handle tuples with only fixed-width attributes */
                                321                 :                : 
                                322                 :                :         /* Calculate the offset up until the first NULL */
   50 drowley@postgresql.o      323         [ +  + ]:GNC       48659 :         for (i = startAttr; i < firstNullAttr; i++)
10892 scrappy@hub.org           324                 :ECB   (3959255) :         {
   50 drowley@postgresql.o      325                 :GNC        1260 :             cattr = TupleDescCompactAttr(tupleDesc, i);
                                326                 :                : 
                                327         [ -  + ]:           1260 :             Assert(cattr->attlen > 0);
                                328                 :           1260 :             off = att_nominal_alignby(off, cattr->attalignby);
                                329                 :           1260 :             off += cattr->attlen;
                                330                 :                :         }
                                331                 :                : 
                                332                 :                :         /* Calculate the offset for any remaining columns. */
                                333         [ +  + ]:          47927 :         for (; i < attnum; i++)
                                334                 :                :         {
                                335         [ -  + ]:            528 :             Assert(hasnulls);
                                336                 :                : 
                                337         [ +  - ]:            528 :             if (att_isnull(i, bp))
                                338                 :            528 :                 continue;
                                339                 :                : 
   50 drowley@postgresql.o      340                 :UNC           0 :             cattr = TupleDescCompactAttr(tupleDesc, i);
                                341                 :                : 
                                342         [ #  # ]:              0 :             Assert(cattr->attlen > 0);
                                343                 :              0 :             off = att_nominal_alignby(off, cattr->attalignby);
                                344                 :              0 :             off += cattr->attlen;
                                345                 :                :         }
                                346                 :                :     }
                                347                 :                : 
   50 drowley@postgresql.o      348                 :GNC    33043439 :     cattr = TupleDescCompactAttr(tupleDesc, attnum);
                                349   [ +  +  +  + ]:       33043439 :     off = att_pointer_alignby(off, cattr->attalignby,
                                350                 :                :                               cattr->attlen, tp + off);
                                351                 :       33043439 :     return fetchatt(cattr, tp + off);
                                352                 :                : }
                                353                 :                : 
                                354                 :                : /*
                                355                 :                :  * Convert an index tuple into Datum/isnull arrays.
                                356                 :                :  *
                                357                 :                :  * The caller must allocate sufficient storage for the output arrays.
                                358                 :                :  * (INDEX_MAX_KEYS entries should be enough.)
                                359                 :                :  *
                                360                 :                :  * This is nearly the same as heap_deform_tuple(), but for IndexTuples.
                                361                 :                :  * One difference is that the tuple should never have any missing columns.
                                362                 :                :  */
                                363                 :                : void
 6121 tgl@sss.pgh.pa.us         364                 :CBC     2871521 : index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor,
                                365                 :                :                    Datum *values, bool *isnull)
                                366                 :                : {
                                367                 :                :     char       *tp;             /* ptr to tuple data */
                                368                 :                :     uint8      *bp;             /* ptr to null bitmap in tuple */
                                369                 :                : 
                                370                 :                :     /* XXX "knows" t_bits are just after fixed tuple header! */
   36 nathan@postgresql.or      371                 :GNC     2871521 :     bp = (uint8 *) ((char *) tup + sizeof(IndexTupleData));
                                372                 :                : 
 2620 tgl@sss.pgh.pa.us         373                 :CBC     2871521 :     tp = (char *) tup + IndexInfoFindDataOffset(tup->t_info);
                                374                 :                : 
 1856                           375                 :        2871521 :     index_deform_tuple_internal(tupleDescriptor, values, isnull,
                                376                 :        2871521 :                                 tp, bp, IndexTupleHasNulls(tup));
                                377                 :        2871521 : }
                                378                 :                : 
                                379                 :                : /*
                                380                 :                :  * Convert an index tuple into Datum/isnull arrays,
                                381                 :                :  * without assuming any specific layout of the index tuple header.
                                382                 :                :  *
                                383                 :                :  * Caller must supply pointer to data area, pointer to nulls bitmap
                                384                 :                :  * (which can be NULL if !hasnulls), and hasnulls flag.
                                385                 :                :  */
                                386                 :                : void
                                387                 :        2912264 : index_deform_tuple_internal(TupleDesc tupleDescriptor,
                                388                 :                :                             Datum *values, bool *isnull,
                                389                 :                :                             char *tp, uint8 *bp, int hasnulls)
                                390                 :                : {
                                391                 :                :     CompactAttribute *cattr;
                                392                 :        2912264 :     int         natts = tupleDescriptor->natts; /* number of atts to extract */
   50 drowley@postgresql.o      393                 :GNC     2912264 :     int         attnum = 0;
                                394                 :        2912264 :     uint32      off = 0;        /* offset in tuple data */
                                395                 :                :     int         firstNonCacheOffsetAttr;
                                396                 :                :     int         firstNullAttr;
                                397                 :                : 
                                398                 :                :     /* Assert to protect callers who allocate fixed-size arrays */
 1856 tgl@sss.pgh.pa.us         399         [ -  + ]:CBC     2912264 :     Assert(natts <= INDEX_MAX_KEYS);
                                400                 :                : 
                                401                 :                :     /* Did someone forget to call TupleDescFinalize()? */
   50 drowley@postgresql.o      402         [ -  + ]:GNC     2912264 :     Assert(tupleDescriptor->firstNonCachedOffsetAttr >= 0);
                                403                 :                : 
                                404                 :        2912264 :     firstNonCacheOffsetAttr = Min(tupleDescriptor->firstNonCachedOffsetAttr, natts);
                                405                 :                : 
                                406         [ +  + ]:        2912264 :     if (hasnulls)
                                407                 :                :     {
                                408                 :           2688 :         firstNullAttr = first_null_attr(bp, natts);
                                409                 :           2688 :         firstNonCacheOffsetAttr = Min(firstNonCacheOffsetAttr, firstNullAttr);
                                410                 :                :     }
                                411                 :                :     else
                                412                 :        2909576 :         firstNullAttr = natts;
                                413                 :                : 
                                414         [ +  + ]:        2912264 :     if (firstNonCacheOffsetAttr > 0)
                                415                 :                :     {
                                416                 :                : #ifdef USE_ASSERT_CHECKING
                                417                 :                :         /* In Assert enabled builds, verify attcacheoff is correct */
                                418                 :        2855649 :         off = 0;
                                419                 :                : #endif
                                420                 :                : 
                                421                 :                :         do
                                422                 :                :         {
                                423                 :        3923992 :             isnull[attnum] = false;
                                424                 :        3923992 :             cattr = TupleDescCompactAttr(tupleDescriptor, attnum);
                                425                 :                : 
                                426                 :                : #ifdef USE_ASSERT_CHECKING
                                427                 :        3923992 :             off = att_nominal_alignby(off, cattr->attalignby);
                                428         [ -  + ]:        3923992 :             Assert(off == cattr->attcacheoff);
                                429                 :        3923992 :             off += cattr->attlen;
                                430                 :                : #endif
                                431                 :                : 
                                432                 :        7847984 :             values[attnum] = fetch_att_noerr(tp + cattr->attcacheoff, cattr->attbyval,
                                433                 :        3923992 :                                              cattr->attlen);
                                434         [ +  + ]:        3923992 :         } while (++attnum < firstNonCacheOffsetAttr);
                                435                 :                : 
                                436                 :        2855649 :         off = cattr->attcacheoff + cattr->attlen;
                                437                 :                :     }
                                438                 :                : 
                                439         [ +  + ]:        2988509 :     for (; attnum < firstNullAttr; attnum++)
                                440                 :                :     {
                                441                 :          76245 :         isnull[attnum] = false;
                                442                 :          76245 :         cattr = TupleDescCompactAttr(tupleDescriptor, attnum);
                                443                 :                : 
                                444                 :                :         /* align 'off', fetch the datum, and increment off beyond the datum */
                                445                 :          76245 :         values[attnum] = align_fetch_then_add(tp,
                                446                 :                :                                               &off,
                                447                 :          76245 :                                               cattr->attbyval,
                                448                 :          76245 :                                               cattr->attlen,
                                449                 :          76245 :                                               cattr->attalignby);
                                450                 :                :     }
                                451                 :                : 
                                452         [ +  + ]:        2917429 :     for (; attnum < natts; attnum++)
                                453                 :                :     {
                                454         [ -  + ]:           5165 :         Assert(hasnulls);
                                455                 :                : 
                                456         [ +  + ]:           5165 :         if (att_isnull(attnum, bp))
                                457                 :                :         {
                                458                 :           2704 :             values[attnum] = (Datum) 0;
                                459                 :           2704 :             isnull[attnum] = true;
                                460                 :           2704 :             continue;
                                461                 :                :         }
                                462                 :                : 
                                463                 :           2461 :         isnull[attnum] = false;
                                464                 :           2461 :         cattr = TupleDescCompactAttr(tupleDescriptor, attnum);
                                465                 :                : 
                                466                 :                :         /* align 'off', fetch the attr's value, and increment off beyond it */
                                467                 :           2461 :         values[attnum] = align_fetch_then_add(tp,
                                468                 :                :                                               &off,
                                469                 :           2461 :                                               cattr->attbyval,
                                470                 :           2461 :                                               cattr->attlen,
                                471                 :           2461 :                                               cattr->attalignby);
                                472                 :                :     }
 6121 tgl@sss.pgh.pa.us         473                 :CBC     2912264 : }
                                474                 :                : 
                                475                 :                : /*
                                476                 :                :  * Create a palloc'd copy of an index tuple.
                                477                 :                :  */
                                478                 :                : IndexTuple
 8472                           479                 :        3471187 : CopyIndexTuple(IndexTuple source)
                                480                 :                : {
                                481                 :                :     IndexTuple  result;
                                482                 :                :     Size        size;
                                483                 :                : 
10467 bruce@momjian.us          484                 :        3471187 :     size = IndexTupleSize(source);
 8472 tgl@sss.pgh.pa.us         485                 :        3471187 :     result = (IndexTuple) palloc(size);
                                486                 :        3471187 :     memcpy(result, source, size);
                                487                 :        3471187 :     return result;
                                488                 :                : }
                                489                 :                : 
                                490                 :                : /*
                                491                 :                :  * Create a palloc'd copy of an index tuple, leaving only the first
                                492                 :                :  * leavenatts attributes remaining.
                                493                 :                :  *
                                494                 :                :  * Truncation is guaranteed to result in an index tuple that is no
                                495                 :                :  * larger than the original.  It is safe to use the IndexTuple with
                                496                 :                :  * the original tuple descriptor, but caller must avoid actually
                                497                 :                :  * accessing truncated attributes from returned tuple!  In practice
                                498                 :                :  * this means that index_getattr() must be called with special care,
                                499                 :                :  * and that the truncated tuple should only ever be accessed by code
                                500                 :                :  * under caller's direct control.
                                501                 :                :  *
                                502                 :                :  * It's safe to call this function with a buffer lock held, since it
                                503                 :                :  * never performs external table access.  If it ever became possible
                                504                 :                :  * for index tuples to contain EXTERNAL TOAST values, then this would
                                505                 :                :  * have to be revisited.
                                506                 :                :  */
                                507                 :                : IndexTuple
 2938 teodor@sigaev.ru          508                 :          40547 : index_truncate_tuple(TupleDesc sourceDescriptor, IndexTuple source,
                                509                 :                :                      int leavenatts)
                                510                 :                : {
                                511                 :                :     TupleDesc   truncdesc;
                                512                 :                :     Datum       values[INDEX_MAX_KEYS];
                                513                 :                :     bool        isnull[INDEX_MAX_KEYS];
                                514                 :                :     IndexTuple  truncated;
                                515                 :                : 
 2603 pg@bowt.ie                516         [ -  + ]:          40547 :     Assert(leavenatts <= sourceDescriptor->natts);
                                517                 :                : 
                                518                 :                :     /* Easy case: no truncation actually required */
                                519         [ +  + ]:          40547 :     if (leavenatts == sourceDescriptor->natts)
                                520                 :          24078 :         return CopyIndexTuple(source);
                                521                 :                : 
                                522                 :                :     /* Create temporary truncated tuple descriptor */
  501 drowley@postgresql.o      523                 :          16469 :     truncdesc = CreateTupleDescTruncatedCopy(sourceDescriptor, leavenatts);
                                524                 :                : 
                                525                 :                :     /* Deform, form copy of tuple with fewer attributes */
 2938 teodor@sigaev.ru          526                 :          16469 :     index_deform_tuple(source, truncdesc, values, isnull);
                                527                 :          16469 :     truncated = index_form_tuple(truncdesc, values, isnull);
                                528                 :          16469 :     truncated->t_tid = source->t_tid;
                                529         [ -  + ]:          16469 :     Assert(IndexTupleSize(truncated) <= IndexTupleSize(source));
                                530                 :                : 
                                531                 :                :     /*
                                532                 :                :      * Cannot leak memory here, TupleDescCopy() doesn't allocate any inner
                                533                 :                :      * structure, so, plain pfree() should clean all allocated memory
                                534                 :                :      */
                                535                 :          16469 :     pfree(truncdesc);
                                536                 :                : 
                                537                 :          16469 :     return truncated;
                                538                 :                : }
        

Generated by: LCOV version 2.5.0-beta