LCOV - code coverage report
Current view: top level - src/backend/access/common - tupconvert.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 100.0 % 90 90
Test Date: 2026-02-17 17:20:33 Functions: 100.0 % 7 7
Legend: Lines:     hit not hit

            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         4812 : convert_tuples_by_position(TupleDesc indesc,
      61              :                            TupleDesc outdesc,
      62              :                            const char *msg)
      63              : {
      64              :     TupleConversionMap *map;
      65              :     int         n;
      66              :     AttrMap    *attrMap;
      67              : 
      68              :     /* Verify compatibility and prepare attribute-number map */
      69         4812 :     attrMap = build_attrmap_by_position(indesc, outdesc, msg);
      70              : 
      71         4795 :     if (attrMap == NULL)
      72              :     {
      73              :         /* runtime conversion is not needed */
      74         4747 :         return NULL;
      75              :     }
      76              : 
      77              :     /* Prepare the map structure */
      78           48 :     map = palloc_object(TupleConversionMap);
      79           48 :     map->indesc = indesc;
      80           48 :     map->outdesc = outdesc;
      81           48 :     map->attrMap = attrMap;
      82              :     /* preallocate workspace for Datum arrays */
      83           48 :     n = outdesc->natts + 1;      /* +1 for NULL */
      84           48 :     map->outvalues = palloc_array(Datum, n);
      85           48 :     map->outisnull = palloc_array(bool, n);
      86           48 :     n = indesc->natts + 1;       /* +1 for NULL */
      87           48 :     map->invalues = palloc_array(Datum, n);
      88           48 :     map->inisnull = palloc_array(bool, n);
      89           48 :     map->invalues[0] = (Datum) 0;    /* set up the NULL entry */
      90           48 :     map->inisnull[0] = true;
      91              : 
      92           48 :     return map;
      93              : }
      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         2175 : convert_tuples_by_name(TupleDesc indesc,
     104              :                        TupleDesc outdesc)
     105              : {
     106              :     AttrMap    *attrMap;
     107              : 
     108              :     /* Verify compatibility and prepare attribute-number map */
     109         2175 :     attrMap = build_attrmap_by_name_if_req(indesc, outdesc, false);
     110              : 
     111         2175 :     if (attrMap == NULL)
     112              :     {
     113              :         /* runtime conversion is not needed */
     114         1734 :         return NULL;
     115              :     }
     116              : 
     117          441 :     return convert_tuples_by_name_attrmap(indesc, outdesc, attrMap);
     118              : }
     119              : 
     120              : /*
     121              :  * Set up tuple conversion for input and output TupleDescs using the given
     122              :  * AttrMap.
     123              :  */
     124              : TupleConversionMap *
     125         1231 : convert_tuples_by_name_attrmap(TupleDesc indesc,
     126              :                                TupleDesc outdesc,
     127              :                                AttrMap *attrMap)
     128              : {
     129         1231 :     int         n = outdesc->natts;
     130              :     TupleConversionMap *map;
     131              : 
     132              :     Assert(attrMap != NULL);
     133              : 
     134              :     /* Prepare the map structure */
     135         1231 :     map = palloc_object(TupleConversionMap);
     136         1231 :     map->indesc = indesc;
     137         1231 :     map->outdesc = outdesc;
     138         1231 :     map->attrMap = attrMap;
     139              :     /* preallocate workspace for Datum arrays */
     140         1231 :     map->outvalues = palloc_array(Datum, n);
     141         1231 :     map->outisnull = palloc_array(bool, n);
     142         1231 :     n = indesc->natts + 1;       /* +1 for NULL */
     143         1231 :     map->invalues = palloc_array(Datum, n);
     144         1231 :     map->inisnull = palloc_array(bool, n);
     145         1231 :     map->invalues[0] = (Datum) 0;    /* set up the NULL entry */
     146         1231 :     map->inisnull[0] = true;
     147              : 
     148         1231 :     return map;
     149              : }
     150              : 
     151              : /*
     152              :  * Perform conversion of a tuple according to the map.
     153              :  */
     154              : HeapTuple
     155        53635 : execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
     156              : {
     157        53635 :     AttrMap    *attrMap = map->attrMap;
     158        53635 :     Datum      *invalues = map->invalues;
     159        53635 :     bool       *inisnull = map->inisnull;
     160        53635 :     Datum      *outvalues = map->outvalues;
     161        53635 :     bool       *outisnull = map->outisnull;
     162              :     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        53635 :     heap_deform_tuple(tuple, map->indesc, invalues + 1, inisnull + 1);
     170              : 
     171              :     /*
     172              :      * Transpose into proper fields of the new tuple.
     173              :      */
     174              :     Assert(attrMap->maplen == map->outdesc->natts);
     175       213487 :     for (i = 0; i < attrMap->maplen; i++)
     176              :     {
     177       159852 :         int         j = attrMap->attnums[i];
     178              : 
     179       159852 :         outvalues[i] = invalues[j];
     180       159852 :         outisnull[i] = inisnull[j];
     181              :     }
     182              : 
     183              :     /*
     184              :      * Now form the new tuple.
     185              :      */
     186        53635 :     return heap_form_tuple(map->outdesc, outvalues, outisnull);
     187              : }
     188              : 
     189              : /*
     190              :  * Perform conversion of a tuple slot according to the map.
     191              :  */
     192              : TupleTableSlot *
     193        72002 : execute_attr_map_slot(AttrMap *attrMap,
     194              :                       TupleTableSlot *in_slot,
     195              :                       TupleTableSlot *out_slot)
     196              : {
     197              :     Datum      *invalues;
     198              :     bool       *inisnull;
     199              :     Datum      *outvalues;
     200              :     bool       *outisnull;
     201              :     int         outnatts;
     202              :     int         i;
     203              : 
     204              :     /* Sanity checks */
     205              :     Assert(in_slot->tts_tupleDescriptor != NULL &&
     206              :            out_slot->tts_tupleDescriptor != NULL);
     207              :     Assert(in_slot->tts_values != NULL && out_slot->tts_values != NULL);
     208              : 
     209        72002 :     outnatts = out_slot->tts_tupleDescriptor->natts;
     210              : 
     211              :     /* Extract all the values of the in slot. */
     212        72002 :     slot_getallattrs(in_slot);
     213              : 
     214              :     /* Before doing the mapping, clear any old contents from the out slot */
     215        72002 :     ExecClearTuple(out_slot);
     216              : 
     217        72002 :     invalues = in_slot->tts_values;
     218        72002 :     inisnull = in_slot->tts_isnull;
     219        72002 :     outvalues = out_slot->tts_values;
     220        72002 :     outisnull = out_slot->tts_isnull;
     221              : 
     222              :     /* Transpose into proper fields of the out slot. */
     223       290254 :     for (i = 0; i < outnatts; i++)
     224              :     {
     225       218252 :         int         j = attrMap->attnums[i] - 1;
     226              : 
     227              :         /* attrMap->attnums[i] == 0 means it's a NULL datum. */
     228       218252 :         if (j == -1)
     229              :         {
     230         1337 :             outvalues[i] = (Datum) 0;
     231         1337 :             outisnull[i] = true;
     232              :         }
     233              :         else
     234              :         {
     235       216915 :             outvalues[i] = invalues[j];
     236       216915 :             outisnull[i] = inisnull[j];
     237              :         }
     238              :     }
     239              : 
     240        72002 :     ExecStoreVirtualTuple(out_slot);
     241              : 
     242        72002 :     return out_slot;
     243              : }
     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          247 : execute_attr_map_cols(AttrMap *attrMap, Bitmapset *in_cols)
     254              : {
     255              :     Bitmapset  *out_cols;
     256              :     int         out_attnum;
     257              : 
     258              :     /* fast path for the common trivial case */
     259          247 :     if (in_cols == NULL)
     260            2 :         return NULL;
     261              : 
     262              :     /*
     263              :      * For each output column, check which input column it corresponds to.
     264              :      */
     265          245 :     out_cols = NULL;
     266              : 
     267          245 :     for (out_attnum = FirstLowInvalidHeapAttributeNumber;
     268         3124 :          out_attnum <= attrMap->maplen;
     269         2879 :          out_attnum++)
     270              :     {
     271              :         int         in_attnum;
     272              : 
     273         2879 :         if (out_attnum < 0)
     274              :         {
     275              :             /* System column. No mapping. */
     276         1715 :             in_attnum = out_attnum;
     277              :         }
     278         1164 :         else if (out_attnum == 0)
     279          245 :             continue;
     280              :         else
     281              :         {
     282              :             /* normal user column */
     283          919 :             in_attnum = attrMap->attnums[out_attnum - 1];
     284              : 
     285          919 :             if (in_attnum == 0)
     286           71 :                 continue;
     287              :         }
     288              : 
     289         2563 :         if (bms_is_member(in_attnum - FirstLowInvalidHeapAttributeNumber, in_cols))
     290          266 :             out_cols = bms_add_member(out_cols, out_attnum - FirstLowInvalidHeapAttributeNumber);
     291              :     }
     292              : 
     293          245 :     return out_cols;
     294              : }
     295              : 
     296              : /*
     297              :  * Free a TupleConversionMap structure.
     298              :  */
     299              : void
     300          104 : free_conversion_map(TupleConversionMap *map)
     301              : {
     302              :     /* indesc and outdesc are not ours to free */
     303          104 :     free_attrmap(map->attrMap);
     304          104 :     pfree(map->invalues);
     305          104 :     pfree(map->inisnull);
     306          104 :     pfree(map->outvalues);
     307          104 :     pfree(map->outisnull);
     308          104 :     pfree(map);
     309          104 : }
        

Generated by: LCOV version 2.0-1