LCOV - code coverage report
Current view: top level - src/backend/executor - execJunk.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 67 73 91.8 %
Date: 2024-03-28 08:11:21 Functions: 4 5 80.0 %
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-2024, 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       58638 : 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       58638 :     cleanTupType = ExecCleanTypeFromTL(targetList);
      71             : 
      72             :     /*
      73             :      * Use the given slot, or make a new slot if we weren't given one.
      74             :      */
      75       58638 :     if (slot)
      76       58638 :         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       58638 :     cleanLength = cleanTupType->natts;
      91       58638 :     if (cleanLength > 0)
      92             :     {
      93             :         AttrNumber  cleanResno;
      94             :         ListCell   *t;
      95             : 
      96       58566 :         cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
      97       58566 :         cleanResno = 0;
      98      193134 :         foreach(t, targetList)
      99             :         {
     100      134568 :             TargetEntry *tle = lfirst(t);
     101             : 
     102      134568 :             if (!tle->resjunk)
     103             :             {
     104      105948 :                 cleanMap[cleanResno] = tle->resno;
     105      105948 :                 cleanResno++;
     106             :             }
     107             :         }
     108             :         Assert(cleanResno == cleanLength);
     109             :     }
     110             :     else
     111          72 :         cleanMap = NULL;
     112             : 
     113             :     /*
     114             :      * Finally create and initialize the JunkFilter struct.
     115             :      */
     116       58638 :     junkfilter = makeNode(JunkFilter);
     117             : 
     118       58638 :     junkfilter->jf_targetList = targetList;
     119       58638 :     junkfilter->jf_cleanTupType = cleanTupType;
     120       58638 :     junkfilter->jf_cleanMap = cleanMap;
     121       58638 :     junkfilter->jf_resultSlot = slot;
     122             : 
     123       58638 :     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        1236 : 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        1236 :     if (slot)
     151        1236 :         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        1236 :     cleanLength = cleanTupType->natts;
     166        1236 :     if (cleanLength > 0)
     167             :     {
     168        1236 :         cleanMap = (AttrNumber *) palloc0(cleanLength * sizeof(AttrNumber));
     169        1236 :         t = list_head(targetList);
     170        4492 :         for (i = 0; i < cleanLength; i++)
     171             :         {
     172        3256 :             if (TupleDescAttr(cleanTupType, i)->attisdropped)
     173          66 :                 continue;       /* map entry is already zero */
     174             :             for (;;)
     175           0 :             {
     176        3190 :                 TargetEntry *tle = lfirst(t);
     177             : 
     178        3190 :                 t = lnext(targetList, t);
     179        3190 :                 if (!tle->resjunk)
     180             :                 {
     181        3190 :                     cleanMap[i] = tle->resno;
     182        3190 :                     break;
     183             :                 }
     184             :             }
     185             :         }
     186             :     }
     187             :     else
     188           0 :         cleanMap = NULL;
     189             : 
     190             :     /*
     191             :      * Finally create and initialize the JunkFilter struct.
     192             :      */
     193        1236 :     junkfilter = makeNode(JunkFilter);
     194             : 
     195        1236 :     junkfilter->jf_targetList = targetList;
     196        1236 :     junkfilter->jf_cleanTupType = cleanTupType;
     197        1236 :     junkfilter->jf_cleanMap = cleanMap;
     198        1236 :     junkfilter->jf_resultSlot = slot;
     199             : 
     200        1236 :     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      157818 : ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
     223             : {
     224             :     ListCell   *t;
     225             : 
     226      438142 :     foreach(t, targetlist)
     227             :     {
     228      324190 :         TargetEntry *tle = lfirst(t);
     229             : 
     230      324190 :         if (tle->resjunk && tle->resname &&
     231       82166 :             (strcmp(tle->resname, attrName) == 0))
     232             :         {
     233             :             /* We found it ! */
     234       43866 :             return tle->resno;
     235             :         }
     236             :     }
     237             : 
     238      113952 :     return InvalidAttrNumber;
     239             : }
     240             : 
     241             : /*
     242             :  * ExecFilterJunk
     243             :  *
     244             :  * Construct and return a slot with all the junk attributes removed.
     245             :  */
     246             : TupleTableSlot *
     247      474288 : 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      474288 :     slot_getallattrs(slot);
     263      474288 :     old_values = slot->tts_values;
     264      474288 :     old_isnull = slot->tts_isnull;
     265             : 
     266             :     /*
     267             :      * get info from the junk filter
     268             :      */
     269      474288 :     cleanTupType = junkfilter->jf_cleanTupType;
     270      474288 :     cleanLength = cleanTupType->natts;
     271      474288 :     cleanMap = junkfilter->jf_cleanMap;
     272      474288 :     resultSlot = junkfilter->jf_resultSlot;
     273             : 
     274             :     /*
     275             :      * Prepare to build a virtual result tuple.
     276             :      */
     277      474288 :     ExecClearTuple(resultSlot);
     278      474288 :     values = resultSlot->tts_values;
     279      474288 :     isnull = resultSlot->tts_isnull;
     280             : 
     281             :     /*
     282             :      * Transpose data into proper fields of the new tuple.
     283             :      */
     284     1479724 :     for (i = 0; i < cleanLength; i++)
     285             :     {
     286     1005436 :         int         j = cleanMap[i];
     287             : 
     288     1005436 :         if (j == 0)
     289             :         {
     290         120 :             values[i] = (Datum) 0;
     291         120 :             isnull[i] = true;
     292             :         }
     293             :         else
     294             :         {
     295     1005316 :             values[i] = old_values[j - 1];
     296     1005316 :             isnull[i] = old_isnull[j - 1];
     297             :         }
     298             :     }
     299             : 
     300             :     /*
     301             :      * And return the virtual tuple.
     302             :      */
     303      474288 :     return ExecStoreVirtualTuple(resultSlot);
     304             : }

Generated by: LCOV version 1.14