LCOV - differential code coverage report
Current view: top level - src/backend/executor - tstoreReceiver.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 99.0 % 99 98 1 98
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 8 8 8
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * tstoreReceiver.c
       4                 :  *    An implementation of DestReceiver that stores the result tuples in
       5                 :  *    a Tuplestore.
       6                 :  *
       7                 :  * Optionally, we can force detoasting (but not decompression) of out-of-line
       8                 :  * toasted values.  This is to support cursors WITH HOLD, which must retain
       9                 :  * data even if the underlying table is dropped.
      10                 :  *
      11                 :  * Also optionally, we can apply a tuple conversion map before storing.
      12                 :  *
      13                 :  *
      14                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
      15                 :  * Portions Copyright (c) 1994, Regents of the University of California
      16                 :  *
      17                 :  * IDENTIFICATION
      18                 :  *    src/backend/executor/tstoreReceiver.c
      19                 :  *
      20                 :  *-------------------------------------------------------------------------
      21                 :  */
      22                 : 
      23                 : #include "postgres.h"
      24                 : 
      25                 : #include "access/detoast.h"
      26                 : #include "access/tupconvert.h"
      27                 : #include "executor/tstoreReceiver.h"
      28                 : 
      29                 : 
      30                 : typedef struct
      31                 : {
      32                 :     DestReceiver pub;
      33                 :     /* parameters: */
      34                 :     Tuplestorestate *tstore;    /* where to put the data */
      35                 :     MemoryContext cxt;          /* context containing tstore */
      36                 :     bool        detoast;        /* were we told to detoast? */
      37                 :     TupleDesc   target_tupdesc; /* target tupdesc, or NULL if none */
      38                 :     const char *map_failure_msg;    /* tupdesc mapping failure message */
      39                 :     /* workspace: */
      40                 :     Datum      *outvalues;      /* values array for result tuple */
      41                 :     Datum      *tofree;         /* temp values to be pfree'd */
      42                 :     TupleConversionMap *tupmap; /* conversion map, if needed */
      43                 :     TupleTableSlot *mapslot;    /* slot for mapped tuples */
      44                 : } TStoreState;
      45                 : 
      46                 : 
      47                 : static bool tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self);
      48                 : static bool tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self);
      49                 : static bool tstoreReceiveSlot_tupmap(TupleTableSlot *slot, DestReceiver *self);
      50                 : 
      51                 : 
      52                 : /*
      53                 :  * Prepare to receive tuples from executor.
      54                 :  */
      55                 : static void
      56 CBC       20166 : tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
      57                 : {
      58           20166 :     TStoreState *myState = (TStoreState *) self;
      59           20166 :     bool        needtoast = false;
      60           20166 :     int         natts = typeinfo->natts;
      61                 :     int         i;
      62                 : 
      63                 :     /* Check if any columns require detoast work */
      64           20166 :     if (myState->detoast)
      65                 :     {
      66             171 :         for (i = 0; i < natts; i++)
      67                 :         {
      68             140 :             Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
      69                 : 
      70             140 :             if (attr->attisdropped)
      71 UBC           0 :                 continue;
      72 CBC         140 :             if (attr->attlen == -1)
      73                 :             {
      74              10 :                 needtoast = true;
      75              10 :                 break;
      76                 :             }
      77                 :         }
      78                 :     }
      79                 : 
      80                 :     /* Check if tuple conversion is needed */
      81           20166 :     if (myState->target_tupdesc)
      82            1327 :         myState->tupmap = convert_tuples_by_position(typeinfo,
      83                 :                                                      myState->target_tupdesc,
      84                 :                                                      myState->map_failure_msg);
      85                 :     else
      86           18839 :         myState->tupmap = NULL;
      87                 : 
      88                 :     /* Set up appropriate callback */
      89           20166 :     if (needtoast)
      90                 :     {
      91              10 :         Assert(!myState->tupmap);
      92              10 :         myState->pub.receiveSlot = tstoreReceiveSlot_detoast;
      93                 :         /* Create workspace */
      94              10 :         myState->outvalues = (Datum *)
      95              10 :             MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
      96              10 :         myState->tofree = (Datum *)
      97              10 :             MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
      98              10 :         myState->mapslot = NULL;
      99                 :     }
     100           20156 :     else if (myState->tupmap)
     101                 :     {
     102              18 :         myState->pub.receiveSlot = tstoreReceiveSlot_tupmap;
     103              18 :         myState->outvalues = NULL;
     104              18 :         myState->tofree = NULL;
     105              18 :         myState->mapslot = MakeSingleTupleTableSlot(myState->target_tupdesc,
     106                 :                                                     &TTSOpsVirtual);
     107                 :     }
     108                 :     else
     109                 :     {
     110           20138 :         myState->pub.receiveSlot = tstoreReceiveSlot_notoast;
     111           20138 :         myState->outvalues = NULL;
     112           20138 :         myState->tofree = NULL;
     113           20138 :         myState->mapslot = NULL;
     114                 :     }
     115           20166 : }
     116                 : 
     117                 : /*
     118                 :  * Receive a tuple from the executor and store it in the tuplestore.
     119                 :  * This is for the easy case where we don't have to detoast nor map anything.
     120                 :  */
     121                 : static bool
     122          228037 : tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
     123                 : {
     124          228037 :     TStoreState *myState = (TStoreState *) self;
     125                 : 
     126          228037 :     tuplestore_puttupleslot(myState->tstore, slot);
     127                 : 
     128          228037 :     return true;
     129                 : }
     130                 : 
     131                 : /*
     132                 :  * Receive a tuple from the executor and store it in the tuplestore.
     133                 :  * This is for the case where we have to detoast any toasted values.
     134                 :  */
     135                 : static bool
     136              23 : tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
     137                 : {
     138              23 :     TStoreState *myState = (TStoreState *) self;
     139              23 :     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
     140              23 :     int         natts = typeinfo->natts;
     141                 :     int         nfree;
     142                 :     int         i;
     143                 :     MemoryContext oldcxt;
     144                 : 
     145                 :     /* Make sure the tuple is fully deconstructed */
     146              23 :     slot_getallattrs(slot);
     147                 : 
     148                 :     /*
     149                 :      * Fetch back any out-of-line datums.  We build the new datums array in
     150                 :      * myState->outvalues[] (but we can re-use the slot's isnull array). Also,
     151                 :      * remember the fetched values to free afterwards.
     152                 :      */
     153              23 :     nfree = 0;
     154              64 :     for (i = 0; i < natts; i++)
     155                 :     {
     156              41 :         Datum       val = slot->tts_values[i];
     157              41 :         Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
     158                 : 
     159              41 :         if (!attr->attisdropped && attr->attlen == -1 && !slot->tts_isnull[i])
     160                 :         {
     161              20 :             if (VARATT_IS_EXTERNAL(DatumGetPointer(val)))
     162                 :             {
     163               5 :                 val = PointerGetDatum(detoast_external_attr((struct varlena *)
     164               5 :                                                             DatumGetPointer(val)));
     165               5 :                 myState->tofree[nfree++] = val;
     166                 :             }
     167                 :         }
     168                 : 
     169              41 :         myState->outvalues[i] = val;
     170                 :     }
     171                 : 
     172                 :     /*
     173                 :      * Push the modified tuple into the tuplestore.
     174                 :      */
     175              23 :     oldcxt = MemoryContextSwitchTo(myState->cxt);
     176              23 :     tuplestore_putvalues(myState->tstore, typeinfo,
     177                 :                          myState->outvalues, slot->tts_isnull);
     178              23 :     MemoryContextSwitchTo(oldcxt);
     179                 : 
     180                 :     /* And release any temporary detoasted values */
     181              28 :     for (i = 0; i < nfree; i++)
     182               5 :         pfree(DatumGetPointer(myState->tofree[i]));
     183                 : 
     184              23 :     return true;
     185                 : }
     186                 : 
     187                 : /*
     188                 :  * Receive a tuple from the executor and store it in the tuplestore.
     189                 :  * This is for the case where we must apply a tuple conversion map.
     190                 :  */
     191                 : static bool
     192              36 : tstoreReceiveSlot_tupmap(TupleTableSlot *slot, DestReceiver *self)
     193                 : {
     194              36 :     TStoreState *myState = (TStoreState *) self;
     195                 : 
     196              36 :     execute_attr_map_slot(myState->tupmap->attrMap, slot, myState->mapslot);
     197              36 :     tuplestore_puttupleslot(myState->tstore, myState->mapslot);
     198                 : 
     199              36 :     return true;
     200                 : }
     201                 : 
     202                 : /*
     203                 :  * Clean up at end of an executor run
     204                 :  */
     205                 : static void
     206           20098 : tstoreShutdownReceiver(DestReceiver *self)
     207                 : {
     208           20098 :     TStoreState *myState = (TStoreState *) self;
     209                 : 
     210                 :     /* Release workspace if any */
     211           20098 :     if (myState->outvalues)
     212              10 :         pfree(myState->outvalues);
     213           20098 :     myState->outvalues = NULL;
     214           20098 :     if (myState->tofree)
     215              10 :         pfree(myState->tofree);
     216           20098 :     myState->tofree = NULL;
     217           20098 :     if (myState->tupmap)
     218              18 :         free_conversion_map(myState->tupmap);
     219           20098 :     myState->tupmap = NULL;
     220           20098 :     if (myState->mapslot)
     221              18 :         ExecDropSingleTupleTableSlot(myState->mapslot);
     222           20098 :     myState->mapslot = NULL;
     223           20098 : }
     224                 : 
     225                 : /*
     226                 :  * Destroy receiver when done with it
     227                 :  */
     228                 : static void
     229           20098 : tstoreDestroyReceiver(DestReceiver *self)
     230                 : {
     231           20098 :     pfree(self);
     232           20098 : }
     233                 : 
     234                 : /*
     235                 :  * Initially create a DestReceiver object.
     236                 :  */
     237                 : DestReceiver *
     238           20283 : CreateTuplestoreDestReceiver(void)
     239                 : {
     240           20283 :     TStoreState *self = (TStoreState *) palloc0(sizeof(TStoreState));
     241                 : 
     242           20283 :     self->pub.receiveSlot = tstoreReceiveSlot_notoast;   /* might change */
     243           20283 :     self->pub.rStartup = tstoreStartupReceiver;
     244           20283 :     self->pub.rShutdown = tstoreShutdownReceiver;
     245           20283 :     self->pub.rDestroy = tstoreDestroyReceiver;
     246           20283 :     self->pub.mydest = DestTuplestore;
     247                 : 
     248                 :     /* private fields will be set by SetTuplestoreDestReceiverParams */
     249                 : 
     250           20283 :     return (DestReceiver *) self;
     251                 : }
     252                 : 
     253                 : /*
     254                 :  * Set parameters for a TuplestoreDestReceiver
     255                 :  *
     256                 :  * tStore: where to store the tuples
     257                 :  * tContext: memory context containing tStore
     258                 :  * detoast: forcibly detoast contained data?
     259                 :  * target_tupdesc: if not NULL, forcibly convert tuples to this rowtype
     260                 :  * map_failure_msg: error message to use if mapping to target_tupdesc fails
     261                 :  *
     262                 :  * We don't currently support both detoast and target_tupdesc at the same
     263                 :  * time, just because no existing caller needs that combination.
     264                 :  */
     265                 : void
     266           20283 : SetTuplestoreDestReceiverParams(DestReceiver *self,
     267                 :                                 Tuplestorestate *tStore,
     268                 :                                 MemoryContext tContext,
     269                 :                                 bool detoast,
     270                 :                                 TupleDesc target_tupdesc,
     271                 :                                 const char *map_failure_msg)
     272                 : {
     273           20283 :     TStoreState *myState = (TStoreState *) self;
     274                 : 
     275           20283 :     Assert(!(detoast && target_tupdesc));
     276                 : 
     277           20283 :     Assert(myState->pub.mydest == DestTuplestore);
     278           20283 :     myState->tstore = tStore;
     279           20283 :     myState->cxt = tContext;
     280           20283 :     myState->detoast = detoast;
     281           20283 :     myState->target_tupdesc = target_tupdesc;
     282           20283 :     myState->map_failure_msg = map_failure_msg;
     283           20283 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a