LCOV - code coverage report
Current view: top level - src/backend/access/common - tupconvert.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 90 90 100.0 %
Date: 2025-10-10 18:17:38 Functions: 7 7 100.0 %
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-2025, 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        9624 : 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        9624 :     attrMap = build_attrmap_by_position(indesc, outdesc, msg);
      70             : 
      71        9590 :     if (attrMap == NULL)
      72             :     {
      73             :         /* runtime conversion is not needed */
      74        9494 :         return NULL;
      75             :     }
      76             : 
      77             :     /* Prepare the map structure */
      78          96 :     map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
      79          96 :     map->indesc = indesc;
      80          96 :     map->outdesc = outdesc;
      81          96 :     map->attrMap = attrMap;
      82             :     /* preallocate workspace for Datum arrays */
      83          96 :     n = outdesc->natts + 1;      /* +1 for NULL */
      84          96 :     map->outvalues = (Datum *) palloc(n * sizeof(Datum));
      85          96 :     map->outisnull = (bool *) palloc(n * sizeof(bool));
      86          96 :     n = indesc->natts + 1;       /* +1 for NULL */
      87          96 :     map->invalues = (Datum *) palloc(n * sizeof(Datum));
      88          96 :     map->inisnull = (bool *) palloc(n * sizeof(bool));
      89          96 :     map->invalues[0] = (Datum) 0;    /* set up the NULL entry */
      90          96 :     map->inisnull[0] = true;
      91             : 
      92          96 :     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        3774 : convert_tuples_by_name(TupleDesc indesc,
     104             :                        TupleDesc outdesc)
     105             : {
     106             :     AttrMap    *attrMap;
     107             : 
     108             :     /* Verify compatibility and prepare attribute-number map */
     109        3774 :     attrMap = build_attrmap_by_name_if_req(indesc, outdesc, false);
     110             : 
     111        3774 :     if (attrMap == NULL)
     112             :     {
     113             :         /* runtime conversion is not needed */
     114        2954 :         return NULL;
     115             :     }
     116             : 
     117         820 :     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        2296 : convert_tuples_by_name_attrmap(TupleDesc indesc,
     126             :                                TupleDesc outdesc,
     127             :                                AttrMap *attrMap)
     128             : {
     129        2296 :     int         n = outdesc->natts;
     130             :     TupleConversionMap *map;
     131             : 
     132             :     Assert(attrMap != NULL);
     133             : 
     134             :     /* Prepare the map structure */
     135        2296 :     map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
     136        2296 :     map->indesc = indesc;
     137        2296 :     map->outdesc = outdesc;
     138        2296 :     map->attrMap = attrMap;
     139             :     /* preallocate workspace for Datum arrays */
     140        2296 :     map->outvalues = (Datum *) palloc(n * sizeof(Datum));
     141        2296 :     map->outisnull = (bool *) palloc(n * sizeof(bool));
     142        2296 :     n = indesc->natts + 1;       /* +1 for NULL */
     143        2296 :     map->invalues = (Datum *) palloc(n * sizeof(Datum));
     144        2296 :     map->inisnull = (bool *) palloc(n * sizeof(bool));
     145        2296 :     map->invalues[0] = (Datum) 0;    /* set up the NULL entry */
     146        2296 :     map->inisnull[0] = true;
     147             : 
     148        2296 :     return map;
     149             : }
     150             : 
     151             : /*
     152             :  * Perform conversion of a tuple according to the map.
     153             :  */
     154             : HeapTuple
     155      107106 : execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
     156             : {
     157      107106 :     AttrMap    *attrMap = map->attrMap;
     158      107106 :     Datum      *invalues = map->invalues;
     159      107106 :     bool       *inisnull = map->inisnull;
     160      107106 :     Datum      *outvalues = map->outvalues;
     161      107106 :     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      107106 :     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      426482 :     for (i = 0; i < attrMap->maplen; i++)
     176             :     {
     177      319376 :         int         j = attrMap->attnums[i];
     178             : 
     179      319376 :         outvalues[i] = invalues[j];
     180      319376 :         outisnull[i] = inisnull[j];
     181             :     }
     182             : 
     183             :     /*
     184             :      * Now form the new tuple.
     185             :      */
     186      107106 :     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      143732 : 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      143732 :     outnatts = out_slot->tts_tupleDescriptor->natts;
     210             : 
     211             :     /* Extract all the values of the in slot. */
     212      143732 :     slot_getallattrs(in_slot);
     213             : 
     214             :     /* Before doing the mapping, clear any old contents from the out slot */
     215      143732 :     ExecClearTuple(out_slot);
     216             : 
     217      143732 :     invalues = in_slot->tts_values;
     218      143732 :     inisnull = in_slot->tts_isnull;
     219      143732 :     outvalues = out_slot->tts_values;
     220      143732 :     outisnull = out_slot->tts_isnull;
     221             : 
     222             :     /* Transpose into proper fields of the out slot. */
     223      579638 :     for (i = 0; i < outnatts; i++)
     224             :     {
     225      435906 :         int         j = attrMap->attnums[i] - 1;
     226             : 
     227             :         /* attrMap->attnums[i] == 0 means it's a NULL datum. */
     228      435906 :         if (j == -1)
     229             :         {
     230        2602 :             outvalues[i] = (Datum) 0;
     231        2602 :             outisnull[i] = true;
     232             :         }
     233             :         else
     234             :         {
     235      433304 :             outvalues[i] = invalues[j];
     236      433304 :             outisnull[i] = inisnull[j];
     237             :         }
     238             :     }
     239             : 
     240      143732 :     ExecStoreVirtualTuple(out_slot);
     241             : 
     242      143732 :     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         494 : 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         494 :     if (in_cols == NULL)
     260           4 :         return NULL;
     261             : 
     262             :     /*
     263             :      * For each output column, check which input column it corresponds to.
     264             :      */
     265         490 :     out_cols = NULL;
     266             : 
     267         490 :     for (out_attnum = FirstLowInvalidHeapAttributeNumber;
     268        6248 :          out_attnum <= attrMap->maplen;
     269        5758 :          out_attnum++)
     270             :     {
     271             :         int         in_attnum;
     272             : 
     273        5758 :         if (out_attnum < 0)
     274             :         {
     275             :             /* System column. No mapping. */
     276        3430 :             in_attnum = out_attnum;
     277             :         }
     278        2328 :         else if (out_attnum == 0)
     279         490 :             continue;
     280             :         else
     281             :         {
     282             :             /* normal user column */
     283        1838 :             in_attnum = attrMap->attnums[out_attnum - 1];
     284             : 
     285        1838 :             if (in_attnum == 0)
     286         142 :                 continue;
     287             :         }
     288             : 
     289        5126 :         if (bms_is_member(in_attnum - FirstLowInvalidHeapAttributeNumber, in_cols))
     290         532 :             out_cols = bms_add_member(out_cols, out_attnum - FirstLowInvalidHeapAttributeNumber);
     291             :     }
     292             : 
     293         490 :     return out_cols;
     294             : }
     295             : 
     296             : /*
     297             :  * Free a TupleConversionMap structure.
     298             :  */
     299             : void
     300         170 : free_conversion_map(TupleConversionMap *map)
     301             : {
     302             :     /* indesc and outdesc are not ours to free */
     303         170 :     free_attrmap(map->attrMap);
     304         170 :     pfree(map->invalues);
     305         170 :     pfree(map->inisnull);
     306         170 :     pfree(map->outvalues);
     307         170 :     pfree(map->outisnull);
     308         170 :     pfree(map);
     309         170 : }

Generated by: LCOV version 1.16