LCOV - differential code coverage report
Current view: top level - src/backend/access/common - printtup.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 98.0 % 149 146 3 146
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 11 11 11
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * printtup.c
       4                 :  *    Routines to print out tuples to the destination (both frontend
       5                 :  *    clients and standalone backends are supported here).
       6                 :  *
       7                 :  *
       8                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       9                 :  * Portions Copyright (c) 1994, Regents of the University of California
      10                 :  *
      11                 :  * IDENTIFICATION
      12                 :  *    src/backend/access/common/printtup.c
      13                 :  *
      14                 :  *-------------------------------------------------------------------------
      15                 :  */
      16                 : #include "postgres.h"
      17                 : 
      18                 : #include "access/printtup.h"
      19                 : #include "libpq/libpq.h"
      20                 : #include "libpq/pqformat.h"
      21                 : #include "tcop/pquery.h"
      22                 : #include "utils/lsyscache.h"
      23                 : #include "utils/memdebug.h"
      24                 : #include "utils/memutils.h"
      25                 : 
      26                 : 
      27                 : static void printtup_startup(DestReceiver *self, int operation,
      28                 :                              TupleDesc typeinfo);
      29                 : static bool printtup(TupleTableSlot *slot, DestReceiver *self);
      30                 : static void printtup_shutdown(DestReceiver *self);
      31                 : static void printtup_destroy(DestReceiver *self);
      32                 : 
      33                 : /* ----------------------------------------------------------------
      34                 :  *      printtup / debugtup support
      35                 :  * ----------------------------------------------------------------
      36                 :  */
      37                 : 
      38                 : /* ----------------
      39                 :  *      Private state for a printtup destination object
      40                 :  *
      41                 :  * NOTE: finfo is the lookup info for either typoutput or typsend, whichever
      42                 :  * we are using for this column.
      43                 :  * ----------------
      44                 :  */
      45                 : typedef struct
      46                 : {                               /* Per-attribute information */
      47                 :     Oid         typoutput;      /* Oid for the type's text output fn */
      48                 :     Oid         typsend;        /* Oid for the type's binary output fn */
      49                 :     bool        typisvarlena;   /* is it varlena (ie possibly toastable)? */
      50                 :     int16       format;         /* format code for this column */
      51                 :     FmgrInfo    finfo;          /* Precomputed call info for output fn */
      52                 : } PrinttupAttrInfo;
      53                 : 
      54                 : typedef struct
      55                 : {
      56                 :     DestReceiver pub;           /* publicly-known function pointers */
      57                 :     Portal      portal;         /* the Portal we are printing from */
      58                 :     bool        sendDescrip;    /* send RowDescription at startup? */
      59                 :     TupleDesc   attrinfo;       /* The attr info we are set up for */
      60                 :     int         nattrs;
      61                 :     PrinttupAttrInfo *myinfo;   /* Cached info about each attr */
      62                 :     StringInfoData buf;         /* output buffer (*not* in tmpcontext) */
      63                 :     MemoryContext tmpcontext;   /* Memory context for per-row workspace */
      64                 : } DR_printtup;
      65                 : 
      66                 : /* ----------------
      67                 :  *      Initialize: create a DestReceiver for printtup
      68                 :  * ----------------
      69                 :  */
      70                 : DestReceiver *
      71 CBC      247017 : printtup_create_DR(CommandDest dest)
      72                 : {
      73          247017 :     DR_printtup *self = (DR_printtup *) palloc0(sizeof(DR_printtup));
      74                 : 
      75          247017 :     self->pub.receiveSlot = printtup;    /* might get changed later */
      76          247017 :     self->pub.rStartup = printtup_startup;
      77          247017 :     self->pub.rShutdown = printtup_shutdown;
      78          247017 :     self->pub.rDestroy = printtup_destroy;
      79          247017 :     self->pub.mydest = dest;
      80                 : 
      81                 :     /*
      82                 :      * Send T message automatically if DestRemote, but not if
      83                 :      * DestRemoteExecute
      84                 :      */
      85          247017 :     self->sendDescrip = (dest == DestRemote);
      86                 : 
      87          247017 :     self->attrinfo = NULL;
      88          247017 :     self->nattrs = 0;
      89          247017 :     self->myinfo = NULL;
      90          247017 :     self->buf.data = NULL;
      91          247017 :     self->tmpcontext = NULL;
      92                 : 
      93          247017 :     return (DestReceiver *) self;
      94                 : }
      95                 : 
      96                 : /*
      97                 :  * Set parameters for a DestRemote (or DestRemoteExecute) receiver
      98                 :  */
      99                 : void
     100          247017 : SetRemoteDestReceiverParams(DestReceiver *self, Portal portal)
     101                 : {
     102          247017 :     DR_printtup *myState = (DR_printtup *) self;
     103                 : 
     104          247017 :     Assert(myState->pub.mydest == DestRemote ||
     105                 :            myState->pub.mydest == DestRemoteExecute);
     106                 : 
     107          247017 :     myState->portal = portal;
     108          247017 : }
     109                 : 
     110                 : static void
     111          115049 : printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
     112                 : {
     113          115049 :     DR_printtup *myState = (DR_printtup *) self;
     114          115049 :     Portal      portal = myState->portal;
     115                 : 
     116                 :     /*
     117                 :      * Create I/O buffer to be used for all messages.  This cannot be inside
     118                 :      * tmpcontext, since we want to re-use it across rows.
     119                 :      */
     120          115049 :     initStringInfo(&myState->buf);
     121                 : 
     122                 :     /*
     123                 :      * Create a temporary memory context that we can reset once per row to
     124                 :      * recover palloc'd memory.  This avoids any problems with leaks inside
     125                 :      * datatype output routines, and should be faster than retail pfree's
     126                 :      * anyway.
     127                 :      */
     128          115049 :     myState->tmpcontext = AllocSetContextCreate(CurrentMemoryContext,
     129                 :                                                 "printtup",
     130                 :                                                 ALLOCSET_DEFAULT_SIZES);
     131                 : 
     132                 :     /*
     133                 :      * If we are supposed to emit row descriptions, then send the tuple
     134                 :      * descriptor of the tuples.
     135                 :      */
     136          115049 :     if (myState->sendDescrip)
     137          109465 :         SendRowDescriptionMessage(&myState->buf,
     138                 :                                   typeinfo,
     139                 :                                   FetchPortalTargetList(portal),
     140                 :                                   portal->formats);
     141                 : 
     142                 :     /* ----------------
     143                 :      * We could set up the derived attr info at this time, but we postpone it
     144                 :      * until the first call of printtup, for 2 reasons:
     145                 :      * 1. We don't waste time (compared to the old way) if there are no
     146                 :      *    tuples at all to output.
     147                 :      * 2. Checking in printtup allows us to handle the case that the tuples
     148                 :      *    change type midway through (although this probably can't happen in
     149                 :      *    the current executor).
     150                 :      * ----------------
     151                 :      */
     152          115049 : }
     153                 : 
     154                 : /*
     155                 :  * SendRowDescriptionMessage --- send a RowDescription message to the frontend
     156                 :  *
     157                 :  * Notes: the TupleDesc has typically been manufactured by ExecTypeFromTL()
     158                 :  * or some similar function; it does not contain a full set of fields.
     159                 :  * The targetlist will be NIL when executing a utility function that does
     160                 :  * not have a plan.  If the targetlist isn't NIL then it is a Query node's
     161                 :  * targetlist; it is up to us to ignore resjunk columns in it.  The formats[]
     162                 :  * array pointer might be NULL (if we are doing Describe on a prepared stmt);
     163                 :  * send zeroes for the format codes in that case.
     164                 :  */
     165                 : void
     166          115095 : SendRowDescriptionMessage(StringInfo buf, TupleDesc typeinfo,
     167                 :                           List *targetlist, int16 *formats)
     168                 : {
     169          115095 :     int         natts = typeinfo->natts;
     170                 :     int         i;
     171          115095 :     ListCell   *tlist_item = list_head(targetlist);
     172                 : 
     173                 :     /* tuple descriptor message type */
     174          115095 :     pq_beginmessage_reuse(buf, 'T');
     175                 :     /* # of attrs in tuples */
     176          115095 :     pq_sendint16(buf, natts);
     177                 : 
     178                 :     /*
     179                 :      * Preallocate memory for the entire message to be sent. That allows to
     180                 :      * use the significantly faster inline pqformat.h functions and to avoid
     181                 :      * reallocations.
     182                 :      *
     183                 :      * Have to overestimate the size of the column-names, to account for
     184                 :      * character set overhead.
     185                 :      */
     186          115095 :     enlargeStringInfo(buf, (NAMEDATALEN * MAX_CONVERSION_GROWTH /* attname */
     187                 :                             + sizeof(Oid)   /* resorigtbl */
     188                 :                             + sizeof(AttrNumber)    /* resorigcol */
     189                 :                             + sizeof(Oid)   /* atttypid */
     190                 :                             + sizeof(int16) /* attlen */
     191                 :                             + sizeof(int32) /* attypmod */
     192                 :                             + sizeof(int16) /* format */
     193                 :                             ) * natts);
     194                 : 
     195          449531 :     for (i = 0; i < natts; ++i)
     196                 :     {
     197          334436 :         Form_pg_attribute att = TupleDescAttr(typeinfo, i);
     198          334436 :         Oid         atttypid = att->atttypid;
     199          334436 :         int32       atttypmod = att->atttypmod;
     200                 :         Oid         resorigtbl;
     201                 :         AttrNumber  resorigcol;
     202                 :         int16       format;
     203                 : 
     204                 :         /*
     205                 :          * If column is a domain, send the base type and typmod instead.
     206                 :          * Lookup before sending any ints, for efficiency.
     207                 :          */
     208          334436 :         atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);
     209                 : 
     210                 :         /* Do we have a non-resjunk tlist item? */
     211          334436 :         while (tlist_item &&
     212          328096 :                ((TargetEntry *) lfirst(tlist_item))->resjunk)
     213 UBC           0 :             tlist_item = lnext(targetlist, tlist_item);
     214 CBC      334436 :         if (tlist_item)
     215                 :         {
     216          328096 :             TargetEntry *tle = (TargetEntry *) lfirst(tlist_item);
     217                 : 
     218          328096 :             resorigtbl = tle->resorigtbl;
     219          328096 :             resorigcol = tle->resorigcol;
     220          328096 :             tlist_item = lnext(targetlist, tlist_item);
     221                 :         }
     222                 :         else
     223                 :         {
     224                 :             /* No info available, so send zeroes */
     225            6340 :             resorigtbl = 0;
     226            6340 :             resorigcol = 0;
     227                 :         }
     228                 : 
     229          334436 :         if (formats)
     230          334301 :             format = formats[i];
     231                 :         else
     232             135 :             format = 0;
     233                 : 
     234          334436 :         pq_writestring(buf, NameStr(att->attname));
     235          334436 :         pq_writeint32(buf, resorigtbl);
     236          334436 :         pq_writeint16(buf, resorigcol);
     237          334436 :         pq_writeint32(buf, atttypid);
     238          334436 :         pq_writeint16(buf, att->attlen);
     239          334436 :         pq_writeint32(buf, atttypmod);
     240          334436 :         pq_writeint16(buf, format);
     241                 :     }
     242                 : 
     243          115095 :     pq_endmessage_reuse(buf);
     244          115095 : }
     245                 : 
     246                 : /*
     247                 :  * Get the lookup info that printtup() needs
     248                 :  */
     249                 : static void
     250           98935 : printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
     251                 : {
     252           98935 :     int16      *formats = myState->portal->formats;
     253                 :     int         i;
     254                 : 
     255                 :     /* get rid of any old data */
     256           98935 :     if (myState->myinfo)
     257             535 :         pfree(myState->myinfo);
     258           98935 :     myState->myinfo = NULL;
     259                 : 
     260           98935 :     myState->attrinfo = typeinfo;
     261           98935 :     myState->nattrs = numAttrs;
     262           98935 :     if (numAttrs <= 0)
     263              53 :         return;
     264                 : 
     265           98882 :     myState->myinfo = (PrinttupAttrInfo *)
     266           98882 :         palloc0(numAttrs * sizeof(PrinttupAttrInfo));
     267                 : 
     268          370517 :     for (i = 0; i < numAttrs; i++)
     269                 :     {
     270          271635 :         PrinttupAttrInfo *thisState = myState->myinfo + i;
     271          271635 :         int16       format = (formats ? formats[i] : 0);
     272          271635 :         Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
     273                 : 
     274          271635 :         thisState->format = format;
     275          271635 :         if (format == 0)
     276                 :         {
     277          271596 :             getTypeOutputInfo(attr->atttypid,
     278                 :                               &thisState->typoutput,
     279                 :                               &thisState->typisvarlena);
     280          271596 :             fmgr_info(thisState->typoutput, &thisState->finfo);
     281                 :         }
     282              39 :         else if (format == 1)
     283                 :         {
     284              39 :             getTypeBinaryOutputInfo(attr->atttypid,
     285                 :                                     &thisState->typsend,
     286                 :                                     &thisState->typisvarlena);
     287              39 :             fmgr_info(thisState->typsend, &thisState->finfo);
     288                 :         }
     289                 :         else
     290 UBC           0 :             ereport(ERROR,
     291                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     292                 :                      errmsg("unsupported format code: %d", format)));
     293                 :     }
     294                 : }
     295                 : 
     296                 : /* ----------------
     297                 :  *      printtup --- send a tuple to the client
     298                 :  * ----------------
     299                 :  */
     300                 : static bool
     301 CBC     3817486 : printtup(TupleTableSlot *slot, DestReceiver *self)
     302                 : {
     303         3817486 :     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
     304         3817486 :     DR_printtup *myState = (DR_printtup *) self;
     305                 :     MemoryContext oldcontext;
     306         3817486 :     StringInfo  buf = &myState->buf;
     307         3817486 :     int         natts = typeinfo->natts;
     308                 :     int         i;
     309                 : 
     310                 :     /* Set or update my derived attribute info, if needed */
     311         3817486 :     if (myState->attrinfo != typeinfo || myState->nattrs != natts)
     312           98935 :         printtup_prepare_info(myState, typeinfo, natts);
     313                 : 
     314                 :     /* Make sure the tuple is fully deconstructed */
     315         3817486 :     slot_getallattrs(slot);
     316                 : 
     317                 :     /* Switch into per-row context so we can recover memory below */
     318         3817486 :     oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
     319                 : 
     320                 :     /*
     321                 :      * Prepare a DataRow message (note buffer is in per-row context)
     322                 :      */
     323         3817486 :     pq_beginmessage_reuse(buf, 'D');
     324                 : 
     325         3817486 :     pq_sendint16(buf, natts);
     326                 : 
     327                 :     /*
     328                 :      * send the attributes of this tuple
     329                 :      */
     330        17588431 :     for (i = 0; i < natts; ++i)
     331                 :     {
     332        13770945 :         PrinttupAttrInfo *thisState = myState->myinfo + i;
     333        13770945 :         Datum       attr = slot->tts_values[i];
     334                 : 
     335        13770945 :         if (slot->tts_isnull[i])
     336                 :         {
     337          515039 :             pq_sendint32(buf, -1);
     338          515039 :             continue;
     339                 :         }
     340                 : 
     341                 :         /*
     342                 :          * Here we catch undefined bytes in datums that are returned to the
     343                 :          * client without hitting disk; see comments at the related check in
     344                 :          * PageAddItem().  This test is most useful for uncompressed,
     345                 :          * non-external datums, but we're quite likely to see such here when
     346                 :          * testing new C functions.
     347                 :          */
     348        13255906 :         if (thisState->typisvarlena)
     349                 :             VALGRIND_CHECK_MEM_IS_DEFINED(DatumGetPointer(attr),
     350                 :                                           VARSIZE_ANY(attr));
     351                 : 
     352        13255906 :         if (thisState->format == 0)
     353                 :         {
     354                 :             /* Text output */
     355                 :             char       *outputstr;
     356                 : 
     357        13248622 :             outputstr = OutputFunctionCall(&thisState->finfo, attr);
     358        13248622 :             pq_sendcountedtext(buf, outputstr, strlen(outputstr), false);
     359                 :         }
     360                 :         else
     361                 :         {
     362                 :             /* Binary output */
     363                 :             bytea      *outputbytes;
     364                 : 
     365            7284 :             outputbytes = SendFunctionCall(&thisState->finfo, attr);
     366            7284 :             pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
     367            7284 :             pq_sendbytes(buf, VARDATA(outputbytes),
     368            7284 :                          VARSIZE(outputbytes) - VARHDRSZ);
     369                 :         }
     370                 :     }
     371                 : 
     372         3817486 :     pq_endmessage_reuse(buf);
     373                 : 
     374                 :     /* Return to caller's context, and flush row's temporary memory */
     375         3817486 :     MemoryContextSwitchTo(oldcontext);
     376         3817486 :     MemoryContextReset(myState->tmpcontext);
     377                 : 
     378         3817486 :     return true;
     379                 : }
     380                 : 
     381                 : /* ----------------
     382                 :  *      printtup_shutdown
     383                 :  * ----------------
     384                 :  */
     385                 : static void
     386          112598 : printtup_shutdown(DestReceiver *self)
     387                 : {
     388          112598 :     DR_printtup *myState = (DR_printtup *) self;
     389                 : 
     390          112598 :     if (myState->myinfo)
     391           98269 :         pfree(myState->myinfo);
     392          112598 :     myState->myinfo = NULL;
     393                 : 
     394          112598 :     myState->attrinfo = NULL;
     395                 : 
     396          112598 :     if (myState->buf.data)
     397          112598 :         pfree(myState->buf.data);
     398          112598 :     myState->buf.data = NULL;
     399                 : 
     400          112598 :     if (myState->tmpcontext)
     401          112598 :         MemoryContextDelete(myState->tmpcontext);
     402          112598 :     myState->tmpcontext = NULL;
     403          112598 : }
     404                 : 
     405                 : /* ----------------
     406                 :  *      printtup_destroy
     407                 :  * ----------------
     408                 :  */
     409                 : static void
     410          235789 : printtup_destroy(DestReceiver *self)
     411                 : {
     412          235789 :     pfree(self);
     413          235789 : }
     414                 : 
     415                 : /* ----------------
     416                 :  *      printatt
     417                 :  * ----------------
     418                 :  */
     419                 : static void
     420            1212 : printatt(unsigned attributeId,
     421                 :          Form_pg_attribute attributeP,
     422                 :          char *value)
     423                 : {
     424            1212 :     printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
     425                 :            attributeId,
     426                 :            NameStr(attributeP->attname),
     427                 :            value != NULL ? " = \"" : "",
     428                 :            value != NULL ? value : "",
     429                 :            value != NULL ? "\"" : "",
     430                 :            (unsigned int) (attributeP->atttypid),
     431                 :            attributeP->attlen,
     432                 :            attributeP->atttypmod,
     433                 :            attributeP->attbyval ? 't' : 'f');
     434            1212 : }
     435                 : 
     436                 : /* ----------------
     437                 :  *      debugStartup - prepare to print tuples for an interactive backend
     438                 :  * ----------------
     439                 :  */
     440                 : void
     441             606 : debugStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
     442                 : {
     443             606 :     int         natts = typeinfo->natts;
     444                 :     int         i;
     445                 : 
     446                 :     /*
     447                 :      * show the return type of the tuples
     448                 :      */
     449            1212 :     for (i = 0; i < natts; ++i)
     450             606 :         printatt((unsigned) i + 1, TupleDescAttr(typeinfo, i), NULL);
     451             606 :     printf("\t----\n");
     452             606 : }
     453                 : 
     454                 : /* ----------------
     455                 :  *      debugtup - print one tuple for an interactive backend
     456                 :  * ----------------
     457                 :  */
     458                 : bool
     459             606 : debugtup(TupleTableSlot *slot, DestReceiver *self)
     460                 : {
     461             606 :     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
     462             606 :     int         natts = typeinfo->natts;
     463                 :     int         i;
     464                 :     Datum       attr;
     465                 :     char       *value;
     466                 :     bool        isnull;
     467                 :     Oid         typoutput;
     468                 :     bool        typisvarlena;
     469                 : 
     470            1212 :     for (i = 0; i < natts; ++i)
     471                 :     {
     472             606 :         attr = slot_getattr(slot, i + 1, &isnull);
     473             606 :         if (isnull)
     474 UBC           0 :             continue;
     475 CBC         606 :         getTypeOutputInfo(TupleDescAttr(typeinfo, i)->atttypid,
     476                 :                           &typoutput, &typisvarlena);
     477                 : 
     478             606 :         value = OidOutputFunctionCall(typoutput, attr);
     479                 : 
     480             606 :         printatt((unsigned) i + 1, TupleDescAttr(typeinfo, i), value);
     481                 :     }
     482             606 :     printf("\t----\n");
     483                 : 
     484             606 :     return true;
     485                 : }
        

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