LCOV - code coverage report
Current view: top level - src/backend/access/common - tupconvert.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 99.2 % 120 119
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 7 7
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 81.8 % 33 27

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * tupconvert.c
       4                 :             :  *        Tuple conversion support.
       5                 :             :  *
       6                 :             :  * These functions provide conversion between rowtypes that are logically
       7                 :             :  * equivalent but might have columns in a different order or different sets of
       8                 :             :  * dropped columns.
       9                 :             :  *
      10                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      11                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      12                 :             :  *
      13                 :             :  *
      14                 :             :  * IDENTIFICATION
      15                 :             :  *        src/backend/access/common/tupconvert.c
      16                 :             :  *
      17                 :             :  *-------------------------------------------------------------------------
      18                 :             :  */
      19                 :             : #include "postgres.h"
      20                 :             : 
      21                 :             : #include "access/htup_details.h"
      22                 :             : #include "access/tupconvert.h"
      23                 :             : #include "executor/tuptable.h"
      24                 :             : 
      25                 :             : 
      26                 :             : /*
      27                 :             :  * The conversion setup routines have the following common API:
      28                 :             :  *
      29                 :             :  * The setup routine checks using attmap.c whether the given source and
      30                 :             :  * destination tuple descriptors are logically compatible.  If not, it throws
      31                 :             :  * an error.  If so, it returns NULL if they are physically compatible (ie, no
      32                 :             :  * conversion is needed), else a TupleConversionMap that can be used by
      33                 :             :  * execute_attr_map_tuple or execute_attr_map_slot to perform the conversion.
      34                 :             :  *
      35                 :             :  * The TupleConversionMap, if needed, is palloc'd in the caller's memory
      36                 :             :  * context.  Also, the given tuple descriptors are referenced by the map,
      37                 :             :  * so they must survive as long as the map is needed.
      38                 :             :  *
      39                 :             :  * The caller must supply a suitable primary error message to be used if
      40                 :             :  * a compatibility error is thrown.  Recommended coding practice is to use
      41                 :             :  * gettext_noop() on this string, so that it is translatable but won't
      42                 :             :  * actually be translated unless the error gets thrown.
      43                 :             :  *
      44                 :             :  *
      45                 :             :  * Implementation notes:
      46                 :             :  *
      47                 :             :  * The key component of a TupleConversionMap is an attrMap[] array with
      48                 :             :  * one entry per output column.  This entry contains the 1-based index of
      49                 :             :  * the corresponding input column, or zero to force a NULL value (for
      50                 :             :  * a dropped output column).  The TupleConversionMap also contains workspace
      51                 :             :  * arrays.
      52                 :             :  */
      53                 :             : 
      54                 :             : 
      55                 :             : /*
      56                 :             :  * Set up for tuple conversion, matching input and output columns by
      57                 :             :  * position.  (Dropped columns are ignored in both input and output.)
      58                 :             :  */
      59                 :             : TupleConversionMap *
      60                 :        1575 : convert_tuples_by_position(TupleDesc indesc,
      61                 :             :                                                    TupleDesc outdesc,
      62                 :             :                                                    const char *msg)
      63                 :             : {
      64                 :        1575 :         TupleConversionMap *map;
      65                 :        1575 :         int                     n;
      66                 :        1575 :         AttrMap    *attrMap;
      67                 :             : 
      68                 :             :         /* Verify compatibility and prepare attribute-number map */
      69                 :        1575 :         attrMap = build_attrmap_by_position(indesc, outdesc, msg);
      70                 :             : 
      71         [ +  + ]:        1575 :         if (attrMap == NULL)
      72                 :             :         {
      73                 :             :                 /* runtime conversion is not needed */
      74                 :        1562 :                 return NULL;
      75                 :             :         }
      76                 :             : 
      77                 :             :         /* Prepare the map structure */
      78                 :          13 :         map = palloc_object(TupleConversionMap);
      79                 :          13 :         map->indesc = indesc;
      80                 :          13 :         map->outdesc = outdesc;
      81                 :          13 :         map->attrMap = attrMap;
      82                 :             :         /* preallocate workspace for Datum arrays */
      83                 :          13 :         n = outdesc->natts + 1;              /* +1 for NULL */
      84                 :          13 :         map->outvalues = palloc_array(Datum, n);
      85                 :          13 :         map->outisnull = palloc_array(bool, n);
      86                 :          13 :         n = indesc->natts + 1;               /* +1 for NULL */
      87                 :          13 :         map->invalues = palloc_array(Datum, n);
      88                 :          13 :         map->inisnull = palloc_array(bool, n);
      89                 :          13 :         map->invalues[0] = (Datum) 0;        /* set up the NULL entry */
      90                 :          13 :         map->inisnull[0] = true;
      91                 :             : 
      92                 :          13 :         return map;
      93                 :        1575 : }
      94                 :             : 
      95                 :             : /*
      96                 :             :  * Set up for tuple conversion, matching input and output columns by name.
      97                 :             :  * (Dropped columns are ignored in both input and output.)      This is intended
      98                 :             :  * for use when the rowtypes are related by inheritance, so we expect an exact
      99                 :             :  * match of both type and typmod.  The error messages will be a bit unhelpful
     100                 :             :  * unless both rowtypes are named composite types.
     101                 :             :  */
     102                 :             : TupleConversionMap *
     103                 :         683 : convert_tuples_by_name(TupleDesc indesc,
     104                 :             :                                            TupleDesc outdesc)
     105                 :             : {
     106                 :         683 :         AttrMap    *attrMap;
     107                 :             : 
     108                 :             :         /* Verify compatibility and prepare attribute-number map */
     109                 :         683 :         attrMap = build_attrmap_by_name_if_req(indesc, outdesc, false);
     110                 :             : 
     111         [ +  + ]:         683 :         if (attrMap == NULL)
     112                 :             :         {
     113                 :             :                 /* runtime conversion is not needed */
     114                 :         545 :                 return NULL;
     115                 :             :         }
     116                 :             : 
     117                 :         138 :         return convert_tuples_by_name_attrmap(indesc, outdesc, attrMap);
     118                 :         683 : }
     119                 :             : 
     120                 :             : /*
     121                 :             :  * Set up tuple conversion for input and output TupleDescs using the given
     122                 :             :  * AttrMap.
     123                 :             :  */
     124                 :             : TupleConversionMap *
     125                 :         364 : convert_tuples_by_name_attrmap(TupleDesc indesc,
     126                 :             :                                                            TupleDesc outdesc,
     127                 :             :                                                            AttrMap *attrMap)
     128                 :             : {
     129                 :         364 :         int                     n = outdesc->natts;
     130                 :         364 :         TupleConversionMap *map;
     131                 :             : 
     132         [ +  - ]:         364 :         Assert(attrMap != NULL);
     133                 :             : 
     134                 :             :         /* Prepare the map structure */
     135                 :         364 :         map = palloc_object(TupleConversionMap);
     136                 :         364 :         map->indesc = indesc;
     137                 :         364 :         map->outdesc = outdesc;
     138                 :         364 :         map->attrMap = attrMap;
     139                 :             :         /* preallocate workspace for Datum arrays */
     140                 :         364 :         map->outvalues = palloc_array(Datum, n);
     141                 :         364 :         map->outisnull = palloc_array(bool, n);
     142                 :         364 :         n = indesc->natts + 1;               /* +1 for NULL */
     143                 :         364 :         map->invalues = palloc_array(Datum, n);
     144                 :         364 :         map->inisnull = palloc_array(bool, n);
     145                 :         364 :         map->invalues[0] = (Datum) 0;        /* set up the NULL entry */
     146                 :         364 :         map->inisnull[0] = true;
     147                 :             : 
     148                 :         728 :         return map;
     149                 :         364 : }
     150                 :             : 
     151                 :             : /*
     152                 :             :  * Perform conversion of a tuple according to the map.
     153                 :             :  */
     154                 :             : HeapTuple
     155                 :       17425 : execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
     156                 :             : {
     157                 :       17425 :         AttrMap    *attrMap = map->attrMap;
     158                 :       17425 :         Datum      *invalues = map->invalues;
     159                 :       17425 :         bool       *inisnull = map->inisnull;
     160                 :       17425 :         Datum      *outvalues = map->outvalues;
     161                 :       17425 :         bool       *outisnull = map->outisnull;
     162                 :       17425 :         int                     i;
     163                 :             : 
     164                 :             :         /*
     165                 :             :          * Extract all the values of the old tuple, offsetting the arrays so that
     166                 :             :          * invalues[0] is left NULL and invalues[1] is the first source attribute;
     167                 :             :          * this exactly matches the numbering convention in attrMap.
     168                 :             :          */
     169                 :       17425 :         heap_deform_tuple(tuple, map->indesc, invalues + 1, inisnull + 1);
     170                 :             : 
     171                 :             :         /*
     172                 :             :          * Transpose into proper fields of the new tuple.
     173                 :             :          */
     174         [ +  - ]:       17425 :         Assert(attrMap->maplen == map->outdesc->natts);
     175         [ +  + ]:       69743 :         for (i = 0; i < attrMap->maplen; i++)
     176                 :             :         {
     177                 :       52318 :                 int                     j = attrMap->attnums[i];
     178                 :             : 
     179                 :       52318 :                 outvalues[i] = invalues[j];
     180                 :       52318 :                 outisnull[i] = inisnull[j];
     181                 :       52318 :         }
     182                 :             : 
     183                 :             :         /*
     184                 :             :          * Now form the new tuple.
     185                 :             :          */
     186                 :       34850 :         return heap_form_tuple(map->outdesc, outvalues, outisnull);
     187                 :       17425 : }
     188                 :             : 
     189                 :             : /*
     190                 :             :  * Perform conversion of a tuple slot according to the map.
     191                 :             :  */
     192                 :             : TupleTableSlot *
     193                 :       23942 : execute_attr_map_slot(AttrMap *attrMap,
     194                 :             :                                           TupleTableSlot *in_slot,
     195                 :             :                                           TupleTableSlot *out_slot)
     196                 :             : {
     197                 :       23942 :         Datum      *invalues;
     198                 :       23942 :         bool       *inisnull;
     199                 :       23942 :         Datum      *outvalues;
     200                 :       23942 :         bool       *outisnull;
     201                 :       23942 :         int                     outnatts;
     202                 :       23942 :         int                     i;
     203                 :             : 
     204                 :             :         /* Sanity checks */
     205         [ +  - ]:       23942 :         Assert(in_slot->tts_tupleDescriptor != NULL &&
     206                 :             :                    out_slot->tts_tupleDescriptor != NULL);
     207         [ +  - ]:       23942 :         Assert(in_slot->tts_values != NULL && out_slot->tts_values != NULL);
     208                 :             : 
     209                 :       23942 :         outnatts = out_slot->tts_tupleDescriptor->natts;
     210                 :             : 
     211                 :             :         /* Extract all the values of the in slot. */
     212                 :       23942 :         slot_getallattrs(in_slot);
     213                 :             : 
     214                 :             :         /* Before doing the mapping, clear any old contents from the out slot */
     215                 :       23942 :         ExecClearTuple(out_slot);
     216                 :             : 
     217                 :       23942 :         invalues = in_slot->tts_values;
     218                 :       23942 :         inisnull = in_slot->tts_isnull;
     219                 :       23942 :         outvalues = out_slot->tts_values;
     220                 :       23942 :         outisnull = out_slot->tts_isnull;
     221                 :             : 
     222                 :             :         /* Transpose into proper fields of the out slot. */
     223         [ +  + ]:       96543 :         for (i = 0; i < outnatts; i++)
     224                 :             :         {
     225                 :       72601 :                 int                     j = attrMap->attnums[i] - 1;
     226                 :             : 
     227                 :             :                 /* attrMap->attnums[i] == 0 means it's a NULL datum. */
     228         [ +  + ]:       72601 :                 if (j == -1)
     229                 :             :                 {
     230                 :         433 :                         outvalues[i] = (Datum) 0;
     231                 :         433 :                         outisnull[i] = true;
     232                 :         433 :                 }
     233                 :             :                 else
     234                 :             :                 {
     235                 :       72168 :                         outvalues[i] = invalues[j];
     236                 :       72168 :                         outisnull[i] = inisnull[j];
     237                 :             :                 }
     238                 :       72601 :         }
     239                 :             : 
     240                 :       23942 :         ExecStoreVirtualTuple(out_slot);
     241                 :             : 
     242                 :       47884 :         return out_slot;
     243                 :       23942 : }
     244                 :             : 
     245                 :             : /*
     246                 :             :  * Perform conversion of bitmap of columns according to the map.
     247                 :             :  *
     248                 :             :  * The input and output bitmaps are offset by
     249                 :             :  * FirstLowInvalidHeapAttributeNumber to accommodate system cols, like the
     250                 :             :  * column-bitmaps in RangeTblEntry.
     251                 :             :  */
     252                 :             : Bitmapset *
     253                 :          76 : execute_attr_map_cols(AttrMap *attrMap, Bitmapset *in_cols)
     254                 :             : {
     255                 :          76 :         Bitmapset  *out_cols;
     256                 :          76 :         int                     out_attnum;
     257                 :             : 
     258                 :             :         /* fast path for the common trivial case */
     259         [ +  - ]:          76 :         if (in_cols == NULL)
     260                 :           0 :                 return NULL;
     261                 :             : 
     262                 :             :         /*
     263                 :             :          * For each output column, check which input column it corresponds to.
     264                 :             :          */
     265                 :          76 :         out_cols = NULL;
     266                 :             : 
     267         [ +  + ]:         973 :         for (out_attnum = FirstLowInvalidHeapAttributeNumber;
     268                 :         973 :                  out_attnum <= attrMap->maplen;
     269                 :         897 :                  out_attnum++)
     270                 :             :         {
     271                 :         897 :                 int                     in_attnum;
     272                 :             : 
     273         [ +  + ]:         897 :                 if (out_attnum < 0)
     274                 :             :                 {
     275                 :             :                         /* System column. No mapping. */
     276                 :         532 :                         in_attnum = out_attnum;
     277                 :         532 :                 }
     278         [ +  + ]:         365 :                 else if (out_attnum == 0)
     279                 :          76 :                         continue;
     280                 :             :                 else
     281                 :             :                 {
     282                 :             :                         /* normal user column */
     283                 :         289 :                         in_attnum = attrMap->attnums[out_attnum - 1];
     284                 :             : 
     285         [ +  + ]:         289 :                         if (in_attnum == 0)
     286                 :          20 :                                 continue;
     287                 :             :                 }
     288                 :             : 
     289         [ +  + ]:         801 :                 if (bms_is_member(in_attnum - FirstLowInvalidHeapAttributeNumber, in_cols))
     290                 :          80 :                         out_cols = bms_add_member(out_cols, out_attnum - FirstLowInvalidHeapAttributeNumber);
     291      [ -  +  + ]:         897 :         }
     292                 :             : 
     293                 :          76 :         return out_cols;
     294                 :          76 : }
     295                 :             : 
     296                 :             : /*
     297                 :             :  * Free a TupleConversionMap structure.
     298                 :             :  */
     299                 :             : void
     300                 :          33 : free_conversion_map(TupleConversionMap *map)
     301                 :             : {
     302                 :             :         /* indesc and outdesc are not ours to free */
     303                 :          33 :         free_attrmap(map->attrMap);
     304                 :          33 :         pfree(map->invalues);
     305                 :          33 :         pfree(map->inisnull);
     306                 :          33 :         pfree(map->outvalues);
     307                 :          33 :         pfree(map->outisnull);
     308                 :          33 :         pfree(map);
     309                 :          33 : }
        

Generated by: LCOV version 2.3.2-1