LCOV - code coverage report
Current view: top level - src/backend/executor - execJunk.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 90.4 % 73 66
Test Date: 2026-02-28 23:15:01 Functions: 80.0 % 5 4
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * execJunk.c
       4              :  *    Junk attribute support stuff....
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/backend/executor/execJunk.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : #include "postgres.h"
      16              : 
      17              : #include "executor/executor.h"
      18              : 
      19              : /*-------------------------------------------------------------------------
      20              :  *      XXX this stuff should be rewritten to take advantage
      21              :  *          of ExecProject() and the ProjectionInfo node.
      22              :  *          -cim 6/3/91
      23              :  *
      24              :  * An attribute of a tuple living inside the executor, can be
      25              :  * either a normal attribute or a "junk" attribute. "junk" attributes
      26              :  * never make it out of the executor, i.e. they are never printed,
      27              :  * returned or stored on disk. Their only purpose in life is to
      28              :  * store some information useful only to the executor, mainly the values
      29              :  * of system attributes like "ctid", or sort key columns that are not to
      30              :  * be output.
      31              :  *
      32              :  * The general idea is the following: A target list consists of a list of
      33              :  * TargetEntry nodes containing expressions. Each TargetEntry has a field
      34              :  * called 'resjunk'. If the value of this field is true then the
      35              :  * corresponding attribute is a "junk" attribute.
      36              :  *
      37              :  * When we initialize a plan we call ExecInitJunkFilter to create a filter.
      38              :  *
      39              :  * We then execute the plan, treating the resjunk attributes like any others.
      40              :  *
      41              :  * Finally, when at the top level we get back a tuple, we can call
      42              :  * ExecFindJunkAttribute/ExecGetJunkAttribute to retrieve the values of the
      43              :  * junk attributes we are interested in, and ExecFilterJunk to remove all the
      44              :  * junk attributes from a tuple.  This new "clean" tuple is then printed,
      45              :  * inserted, or updated.
      46              :  *
      47              :  *-------------------------------------------------------------------------
      48              :  */
      49              : 
      50              : /*
      51              :  * ExecInitJunkFilter
      52              :  *
      53              :  * Initialize the Junk filter.
      54              :  *
      55              :  * The source targetlist is passed in.  The output tuple descriptor is
      56              :  * built from the non-junk tlist entries.
      57              :  * An optional resultSlot can be passed as well; otherwise, we create one.
      58              :  */
      59              : JunkFilter *
      60        30633 : ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
      61              : {
      62              :     JunkFilter *junkfilter;
      63              :     TupleDesc   cleanTupType;
      64              :     int         cleanLength;
      65              :     AttrNumber *cleanMap;
      66              : 
      67              :     /*
      68              :      * Compute the tuple descriptor for the cleaned tuple.
      69              :      */
      70        30633 :     cleanTupType = ExecCleanTypeFromTL(targetList);
      71              : 
      72              :     /*
      73              :      * Use the given slot, or make a new slot if we weren't given one.
      74              :      */
      75        30633 :     if (slot)
      76        30633 :         ExecSetSlotDescriptor(slot, cleanTupType);
      77              :     else
      78            0 :         slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
      79              : 
      80              :     /*
      81              :      * Now calculate the mapping between the original tuple's attributes and
      82              :      * the "clean" tuple's attributes.
      83              :      *
      84              :      * The "map" is an array of "cleanLength" attribute numbers, i.e. one
      85              :      * entry for every attribute of the "clean" tuple. The value of this entry
      86              :      * is the attribute number of the corresponding attribute of the
      87              :      * "original" tuple.  (Zero indicates a NULL output attribute, but we do
      88              :      * not use that feature in this routine.)
      89              :      */
      90        30633 :     cleanLength = cleanTupType->natts;
      91        30633 :     if (cleanLength > 0)
      92              :     {
      93              :         AttrNumber  cleanResno;
      94              :         ListCell   *t;
      95              : 
      96        30633 :         cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
      97        30633 :         cleanResno = 0;
      98       109864 :         foreach(t, targetList)
      99              :         {
     100        79231 :             TargetEntry *tle = lfirst(t);
     101              : 
     102        79231 :             if (!tle->resjunk)
     103              :             {
     104        62381 :                 cleanMap[cleanResno] = tle->resno;
     105        62381 :                 cleanResno++;
     106              :             }
     107              :         }
     108              :         Assert(cleanResno == cleanLength);
     109              :     }
     110              :     else
     111            0 :         cleanMap = NULL;
     112              : 
     113              :     /*
     114              :      * Finally create and initialize the JunkFilter struct.
     115              :      */
     116        30633 :     junkfilter = makeNode(JunkFilter);
     117              : 
     118        30633 :     junkfilter->jf_targetList = targetList;
     119        30633 :     junkfilter->jf_cleanTupType = cleanTupType;
     120        30633 :     junkfilter->jf_cleanMap = cleanMap;
     121        30633 :     junkfilter->jf_resultSlot = slot;
     122              : 
     123        30633 :     return junkfilter;
     124              : }
     125              : 
     126              : /*
     127              :  * ExecInitJunkFilterConversion
     128              :  *
     129              :  * Initialize a JunkFilter for rowtype conversions.
     130              :  *
     131              :  * Here, we are given the target "clean" tuple descriptor rather than
     132              :  * inferring it from the targetlist.  The target descriptor can contain
     133              :  * deleted columns.  It is assumed that the caller has checked that the
     134              :  * non-deleted columns match up with the non-junk columns of the targetlist.
     135              :  */
     136              : JunkFilter *
     137          802 : ExecInitJunkFilterConversion(List *targetList,
     138              :                              TupleDesc cleanTupType,
     139              :                              TupleTableSlot *slot)
     140              : {
     141              :     JunkFilter *junkfilter;
     142              :     int         cleanLength;
     143              :     AttrNumber *cleanMap;
     144              :     ListCell   *t;
     145              :     int         i;
     146              : 
     147              :     /*
     148              :      * Use the given slot, or make a new slot if we weren't given one.
     149              :      */
     150          802 :     if (slot)
     151          802 :         ExecSetSlotDescriptor(slot, cleanTupType);
     152              :     else
     153            0 :         slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
     154              : 
     155              :     /*
     156              :      * Calculate the mapping between the original tuple's attributes and the
     157              :      * "clean" tuple's attributes.
     158              :      *
     159              :      * The "map" is an array of "cleanLength" attribute numbers, i.e. one
     160              :      * entry for every attribute of the "clean" tuple. The value of this entry
     161              :      * is the attribute number of the corresponding attribute of the
     162              :      * "original" tuple.  We store zero for any deleted attributes, marking
     163              :      * that a NULL is needed in the output tuple.
     164              :      */
     165          802 :     cleanLength = cleanTupType->natts;
     166          802 :     if (cleanLength > 0)
     167              :     {
     168          802 :         cleanMap = (AttrNumber *) palloc0(cleanLength * sizeof(AttrNumber));
     169          802 :         t = list_head(targetList);
     170         2774 :         for (i = 0; i < cleanLength; i++)
     171              :         {
     172         1972 :             if (TupleDescCompactAttr(cleanTupType, i)->attisdropped)
     173           33 :                 continue;       /* map entry is already zero */
     174              :             for (;;)
     175            0 :             {
     176         1939 :                 TargetEntry *tle = lfirst(t);
     177              : 
     178         1939 :                 t = lnext(targetList, t);
     179         1939 :                 if (!tle->resjunk)
     180              :                 {
     181         1939 :                     cleanMap[i] = tle->resno;
     182         1939 :                     break;
     183              :                 }
     184              :             }
     185              :         }
     186              :     }
     187              :     else
     188            0 :         cleanMap = NULL;
     189              : 
     190              :     /*
     191              :      * Finally create and initialize the JunkFilter struct.
     192              :      */
     193          802 :     junkfilter = makeNode(JunkFilter);
     194              : 
     195          802 :     junkfilter->jf_targetList = targetList;
     196          802 :     junkfilter->jf_cleanTupType = cleanTupType;
     197          802 :     junkfilter->jf_cleanMap = cleanMap;
     198          802 :     junkfilter->jf_resultSlot = slot;
     199              : 
     200          802 :     return junkfilter;
     201              : }
     202              : 
     203              : /*
     204              :  * ExecFindJunkAttribute
     205              :  *
     206              :  * Locate the specified junk attribute in the junk filter's targetlist,
     207              :  * and return its resno.  Returns InvalidAttrNumber if not found.
     208              :  */
     209              : AttrNumber
     210            0 : ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
     211              : {
     212            0 :     return ExecFindJunkAttributeInTlist(junkfilter->jf_targetList, attrName);
     213              : }
     214              : 
     215              : /*
     216              :  * ExecFindJunkAttributeInTlist
     217              :  *
     218              :  * Find a junk attribute given a subplan's targetlist (not necessarily
     219              :  * part of a JunkFilter).
     220              :  */
     221              : AttrNumber
     222        85215 : ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
     223              : {
     224              :     ListCell   *t;
     225              : 
     226       240266 :     foreach(t, targetlist)
     227              :     {
     228       181766 :         TargetEntry *tle = lfirst(t);
     229              : 
     230       181766 :         if (tle->resjunk && tle->resname &&
     231        47735 :             (strcmp(tle->resname, attrName) == 0))
     232              :         {
     233              :             /* We found it ! */
     234        26715 :             return tle->resno;
     235              :         }
     236              :     }
     237              : 
     238        58500 :     return InvalidAttrNumber;
     239              : }
     240              : 
     241              : /*
     242              :  * ExecFilterJunk
     243              :  *
     244              :  * Construct and return a slot with all the junk attributes removed.
     245              :  */
     246              : TupleTableSlot *
     247       233760 : ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
     248              : {
     249              :     TupleTableSlot *resultSlot;
     250              :     AttrNumber *cleanMap;
     251              :     TupleDesc   cleanTupType;
     252              :     int         cleanLength;
     253              :     int         i;
     254              :     Datum      *values;
     255              :     bool       *isnull;
     256              :     Datum      *old_values;
     257              :     bool       *old_isnull;
     258              : 
     259              :     /*
     260              :      * Extract all the values of the old tuple.
     261              :      */
     262       233760 :     slot_getallattrs(slot);
     263       233760 :     old_values = slot->tts_values;
     264       233760 :     old_isnull = slot->tts_isnull;
     265              : 
     266              :     /*
     267              :      * get info from the junk filter
     268              :      */
     269       233760 :     cleanTupType = junkfilter->jf_cleanTupType;
     270       233760 :     cleanLength = cleanTupType->natts;
     271       233760 :     cleanMap = junkfilter->jf_cleanMap;
     272       233760 :     resultSlot = junkfilter->jf_resultSlot;
     273              : 
     274              :     /*
     275              :      * Prepare to build a virtual result tuple.
     276              :      */
     277       233760 :     ExecClearTuple(resultSlot);
     278       233760 :     values = resultSlot->tts_values;
     279       233760 :     isnull = resultSlot->tts_isnull;
     280              : 
     281              :     /*
     282              :      * Transpose data into proper fields of the new tuple.
     283              :      */
     284       776881 :     for (i = 0; i < cleanLength; i++)
     285              :     {
     286       543121 :         int         j = cleanMap[i];
     287              : 
     288       543121 :         if (j == 0)
     289              :         {
     290           60 :             values[i] = (Datum) 0;
     291           60 :             isnull[i] = true;
     292              :         }
     293              :         else
     294              :         {
     295       543061 :             values[i] = old_values[j - 1];
     296       543061 :             isnull[i] = old_isnull[j - 1];
     297              :         }
     298              :     }
     299              : 
     300              :     /*
     301              :      * And return the virtual tuple.
     302              :      */
     303       233760 :     return ExecStoreVirtualTuple(resultSlot);
     304              : }
        

Generated by: LCOV version 2.0-1