LCOV - code coverage report
Current view: top level - src/backend/access/common - printtup.c (source / functions) Hit Total Coverage
Test: PostgreSQL 11devel Lines: 154 245 62.9 %
Date: 2017-11-22 12:18:04 Functions: 12 15 80.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 49 102 48.0 %

           Branch data     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-2017, 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 bool printtup_20(TupleTableSlot *slot, DestReceiver *self);
      31                 :            : static bool printtup_internal_20(TupleTableSlot *slot, DestReceiver *self);
      32                 :            : static void printtup_shutdown(DestReceiver *self);
      33                 :            : static void printtup_destroy(DestReceiver *self);
      34                 :            : 
      35                 :            : static void SendRowDescriptionCols_2(StringInfo buf, TupleDesc typeinfo,
      36                 :            :                          List *targetlist, int16 *formats);
      37                 :            : static void SendRowDescriptionCols_3(StringInfo buf, TupleDesc typeinfo,
      38                 :            :                          List *targetlist, int16 *formats);
      39                 :            : 
      40                 :            : /* ----------------------------------------------------------------
      41                 :            :  *      printtup / debugtup support
      42                 :            :  * ----------------------------------------------------------------
      43                 :            :  */
      44                 :            : 
      45                 :            : /* ----------------
      46                 :            :  *      Private state for a printtup destination object
      47                 :            :  *
      48                 :            :  * NOTE: finfo is the lookup info for either typoutput or typsend, whichever
      49                 :            :  * we are using for this column.
      50                 :            :  * ----------------
      51                 :            :  */
      52                 :            : typedef struct
      53                 :            : {                               /* Per-attribute information */
      54                 :            :     Oid         typoutput;      /* Oid for the type's text output fn */
      55                 :            :     Oid         typsend;        /* Oid for the type's binary output fn */
      56                 :            :     bool        typisvarlena;   /* is it varlena (ie possibly toastable)? */
      57                 :            :     int16       format;         /* format code for this column */
      58                 :            :     FmgrInfo    finfo;          /* Precomputed call info for output fn */
      59                 :            : } PrinttupAttrInfo;
      60                 :            : 
      61                 :            : typedef struct
      62                 :            : {
      63                 :            :     DestReceiver pub;           /* publicly-known function pointers */
      64                 :            :     StringInfoData buf;         /* output buffer */
      65                 :            :     Portal      portal;         /* the Portal we are printing from */
      66                 :            :     bool        sendDescrip;    /* send RowDescription at startup? */
      67                 :            :     TupleDesc   attrinfo;       /* The attr info we are set up for */
      68                 :            :     int         nattrs;
      69                 :            :     PrinttupAttrInfo *myinfo;   /* Cached info about each attr */
      70                 :            :     MemoryContext tmpcontext;   /* Memory context for per-row workspace */
      71                 :            : } DR_printtup;
      72                 :            : 
      73                 :            : /* ----------------
      74                 :            :  *      Initialize: create a DestReceiver for printtup
      75                 :            :  * ----------------
      76                 :            :  */
      77                 :            : DestReceiver *
      78                 :     265238 : printtup_create_DR(CommandDest dest)
      79                 :            : {
      80                 :     265238 :     DR_printtup *self = (DR_printtup *) palloc0(sizeof(DR_printtup));
      81                 :            : 
      82                 :     265238 :     self->pub.receiveSlot = printtup;    /* might get changed later */
      83                 :     265238 :     self->pub.rStartup = printtup_startup;
      84                 :     265238 :     self->pub.rShutdown = printtup_shutdown;
      85                 :     265238 :     self->pub.rDestroy = printtup_destroy;
      86                 :     265238 :     self->pub.mydest = dest;
      87                 :            : 
      88                 :            :     /*
      89                 :            :      * Send T message automatically if DestRemote, but not if
      90                 :            :      * DestRemoteExecute
      91                 :            :      */
      92                 :     265238 :     self->sendDescrip = (dest == DestRemote);
      93                 :            : 
      94                 :     265238 :     self->attrinfo = NULL;
      95                 :     265238 :     self->nattrs = 0;
      96                 :     265238 :     self->myinfo = NULL;
      97                 :     265238 :     self->tmpcontext = NULL;
      98                 :            : 
      99                 :     265238 :     return (DestReceiver *) self;
     100                 :            : }
     101                 :            : 
     102                 :            : /*
     103                 :            :  * Set parameters for a DestRemote (or DestRemoteExecute) receiver
     104                 :            :  */
     105                 :            : void
     106                 :     265238 : SetRemoteDestReceiverParams(DestReceiver *self, Portal portal)
     107                 :            : {
     108                 :     265238 :     DR_printtup *myState = (DR_printtup *) self;
     109                 :            : 
     110                 :            :     Assert(myState->pub.mydest == DestRemote ||
     111                 :            :            myState->pub.mydest == DestRemoteExecute);
     112                 :            : 
     113                 :     265238 :     myState->portal = portal;
     114                 :            : 
     115         [ -  + ]:     265238 :     if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
     116                 :            :     {
     117                 :            :         /*
     118                 :            :          * In protocol 2.0 the Bind message does not exist, so there is no way
     119                 :            :          * for the columns to have different print formats; it's sufficient to
     120                 :            :          * look at the first one.
     121                 :            :          */
     122 [ #  # ][ #  # ]:          0 :         if (portal->formats && portal->formats[0] != 0)
     123                 :          0 :             myState->pub.receiveSlot = printtup_internal_20;
     124                 :            :         else
     125                 :          0 :             myState->pub.receiveSlot = printtup_20;
     126                 :            :     }
     127                 :     265238 : }
     128                 :            : 
     129                 :            : static void
     130                 :     123156 : printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
     131                 :            : {
     132                 :     123156 :     DR_printtup *myState = (DR_printtup *) self;
     133                 :     123156 :     Portal      portal = myState->portal;
     134                 :            : 
     135                 :            :     /* create buffer to be used for all messages */
     136                 :     123156 :     initStringInfo(&myState->buf);
     137                 :            : 
     138                 :            :     /*
     139                 :            :      * Create a temporary memory context that we can reset once per row to
     140                 :            :      * recover palloc'd memory.  This avoids any problems with leaks inside
     141                 :            :      * datatype output routines, and should be faster than retail pfree's
     142                 :            :      * anyway.
     143                 :            :      */
     144                 :     123156 :     myState->tmpcontext = AllocSetContextCreate(CurrentMemoryContext,
     145                 :            :                                                 "printtup",
     146                 :            :                                                 ALLOCSET_DEFAULT_SIZES);
     147                 :            : 
     148         [ -  + ]:     123156 :     if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
     149                 :            :     {
     150                 :            :         /*
     151                 :            :          * Send portal name to frontend (obsolete cruft, gone in proto 3.0)
     152                 :            :          *
     153                 :            :          * If portal name not specified, use "blank" portal.
     154                 :            :          */
     155                 :          0 :         const char *portalName = portal->name;
     156                 :            : 
     157 [ #  # ][ #  # ]:          0 :         if (portalName == NULL || portalName[0] == '\0')
     158                 :          0 :             portalName = "blank";
     159                 :            : 
     160                 :          0 :         pq_puttextmessage('P', portalName);
     161                 :            :     }
     162                 :            : 
     163                 :            :     /*
     164                 :            :      * If we are supposed to emit row descriptions, then send the tuple
     165                 :            :      * descriptor of the tuples.
     166                 :            :      */
     167         [ +  + ]:     123156 :     if (myState->sendDescrip)
     168                 :     106474 :         SendRowDescriptionMessage(&myState->buf,
     169                 :            :                                   typeinfo,
     170                 :            :                                   FetchPortalTargetList(portal),
     171                 :            :                                   portal->formats);
     172                 :            : 
     173                 :            :     /* ----------------
     174                 :            :      * We could set up the derived attr info at this time, but we postpone it
     175                 :            :      * until the first call of printtup, for 2 reasons:
     176                 :            :      * 1. We don't waste time (compared to the old way) if there are no
     177                 :            :      *    tuples at all to output.
     178                 :            :      * 2. Checking in printtup allows us to handle the case that the tuples
     179                 :            :      *    change type midway through (although this probably can't happen in
     180                 :            :      *    the current executor).
     181                 :            :      * ----------------
     182                 :            :      */
     183                 :     123156 : }
     184                 :            : 
     185                 :            : /*
     186                 :            :  * SendRowDescriptionMessage --- send a RowDescription message to the frontend
     187                 :            :  *
     188                 :            :  * Notes: the TupleDesc has typically been manufactured by ExecTypeFromTL()
     189                 :            :  * or some similar function; it does not contain a full set of fields.
     190                 :            :  * The targetlist will be NIL when executing a utility function that does
     191                 :            :  * not have a plan.  If the targetlist isn't NIL then it is a Query node's
     192                 :            :  * targetlist; it is up to us to ignore resjunk columns in it.  The formats[]
     193                 :            :  * array pointer might be NULL (if we are doing Describe on a prepared stmt);
     194                 :            :  * send zeroes for the format codes in that case.
     195                 :            :  */
     196                 :            : void
     197                 :     123224 : SendRowDescriptionMessage(StringInfo buf, TupleDesc typeinfo,
     198                 :            :                           List *targetlist, int16 *formats)
     199                 :            : {
     200                 :     123224 :     int         natts = typeinfo->natts;
     201                 :     123224 :     int         proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
     202                 :            : 
     203                 :            :     /* tuple descriptor message type */
     204                 :     123224 :     pq_beginmessage_reuse(buf, 'T');
     205                 :            :     /* # of attrs in tuples */
     206                 :     123224 :     pq_sendint16(buf, natts);
     207                 :            : 
     208         [ +  - ]:     123224 :     if (proto >= 3)
     209                 :     123224 :         SendRowDescriptionCols_3(buf, typeinfo, targetlist, formats);
     210                 :            :     else
     211                 :          0 :         SendRowDescriptionCols_2(buf, typeinfo, targetlist, formats);
     212                 :            : 
     213                 :     123224 :     pq_endmessage_reuse(buf);
     214                 :     123224 : }
     215                 :            : 
     216                 :            : /*
     217                 :            :  * Send description for each column when using v3+ protocol
     218                 :            :  */
     219                 :            : static void
     220                 :     123224 : SendRowDescriptionCols_3(StringInfo buf, TupleDesc typeinfo, List *targetlist, int16 *formats)
     221                 :            : {
     222                 :     123224 :     int         natts = typeinfo->natts;
     223                 :            :     int         i;
     224                 :     123224 :     ListCell   *tlist_item = list_head(targetlist);
     225                 :            : 
     226                 :            :     /*
     227                 :            :      * Preallocate memory for the entire message to be sent. That allows to
     228                 :            :      * use the significantly faster inline pqformat.h functions and to avoid
     229                 :            :      * reallocations.
     230                 :            :      *
     231                 :            :      * Have to overestimate the size of the column-names, to account for
     232                 :            :      * character set overhead.
     233                 :            :      */
     234                 :     123224 :     enlargeStringInfo(buf, (NAMEDATALEN * MAX_CONVERSION_GROWTH /* attname */
     235                 :            :                             + sizeof(Oid)   /* resorigtbl */
     236                 :            :                             + sizeof(AttrNumber)    /* resorigcol */
     237                 :            :                             + sizeof(Oid)   /* atttypid */
     238                 :            :                             + sizeof(int16) /* attlen */
     239                 :            :                             + sizeof(int32) /* attypmod */
     240                 :            :                             + sizeof(int16) /* format */
     241                 :     123224 :                             ) * natts);
     242                 :            : 
     243         [ +  + ]:     528760 :     for (i = 0; i < natts; ++i)
     244                 :            :     {
     245                 :     405536 :         Form_pg_attribute att = TupleDescAttr(typeinfo, i);
     246                 :     405536 :         Oid         atttypid = att->atttypid;
     247                 :     405536 :         int32       atttypmod = att->atttypmod;
     248                 :            :         Oid         resorigtbl;
     249                 :            :         AttrNumber  resorigcol;
     250                 :            :         int16       format;
     251                 :            : 
     252                 :            :         /*
     253                 :            :          * If column is a domain, send the base type and typmod instead.
     254                 :            :          * Lookup before sending any ints, for efficiency.
     255                 :            :          */
     256                 :     405536 :         atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);
     257                 :            : 
     258                 :            :         /* Do we have a non-resjunk tlist item? */
     259 [ +  + ][ -  + ]:     405536 :         while (tlist_item &&
     260                 :     400478 :                ((TargetEntry *) lfirst(tlist_item))->resjunk)
     261                 :          0 :             tlist_item = lnext(tlist_item);
     262         [ +  + ]:     405536 :         if (tlist_item)
     263                 :            :         {
     264                 :     400478 :             TargetEntry *tle = (TargetEntry *) lfirst(tlist_item);
     265                 :            : 
     266                 :     400478 :             resorigtbl = tle->resorigtbl;
     267                 :     400478 :             resorigcol = tle->resorigcol;
     268                 :     400478 :             tlist_item = lnext(tlist_item);
     269                 :            :         }
     270                 :            :         else
     271                 :            :         {
     272                 :            :             /* No info available, so send zeroes */
     273                 :       5058 :             resorigtbl = 0;
     274                 :       5058 :             resorigcol = 0;
     275                 :            :         }
     276                 :            : 
     277         [ +  + ]:     405536 :         if (formats)
     278                 :     405360 :             format = formats[i];
     279                 :            :         else
     280                 :        176 :             format = 0;
     281                 :            : 
     282                 :     405536 :         pq_writestring(buf, NameStr(att->attname));
     283                 :     405536 :         pq_writeint32(buf, resorigtbl);
     284                 :     405536 :         pq_writeint16(buf, resorigcol);
     285                 :     405536 :         pq_writeint32(buf, atttypid);
     286                 :     405536 :         pq_writeint16(buf, att->attlen);
     287                 :     405536 :         pq_writeint32(buf, atttypmod);
     288                 :     405536 :         pq_writeint16(buf, format);
     289                 :            :     }
     290                 :     123224 : }
     291                 :            : 
     292                 :            : /*
     293                 :            :  * Send description for each column when using v2 protocol
     294                 :            :  */
     295                 :            : static void
     296                 :          0 : SendRowDescriptionCols_2(StringInfo buf, TupleDesc typeinfo, List *targetlist, int16 *formats)
     297                 :            : {
     298                 :          0 :     int         natts = typeinfo->natts;
     299                 :            :     int         i;
     300                 :            : 
     301         [ #  # ]:          0 :     for (i = 0; i < natts; ++i)
     302                 :            :     {
     303                 :          0 :         Form_pg_attribute att = TupleDescAttr(typeinfo, i);
     304                 :          0 :         Oid         atttypid = att->atttypid;
     305                 :          0 :         int32       atttypmod = att->atttypmod;
     306                 :            : 
     307                 :            :         /* If column is a domain, send the base type and typmod instead */
     308                 :          0 :         atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);
     309                 :            : 
     310                 :          0 :         pq_sendstring(buf, NameStr(att->attname));
     311                 :            :         /* column ID only info appears in protocol 3.0 and up */
     312                 :          0 :         pq_sendint32(buf, atttypid);
     313                 :          0 :         pq_sendint16(buf, att->attlen);
     314                 :          0 :         pq_sendint32(buf, atttypmod);
     315                 :            :         /* format info only appears in protocol 3.0 and up */
     316                 :            :     }
     317                 :          0 : }
     318                 :            : 
     319                 :            : /*
     320                 :            :  * Get the lookup info that printtup() needs
     321                 :            :  */
     322                 :            : static void
     323                 :     102078 : printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
     324                 :            : {
     325                 :     102078 :     int16      *formats = myState->portal->formats;
     326                 :            :     int         i;
     327                 :            : 
     328                 :            :     /* get rid of any old data */
     329         [ +  + ]:     102078 :     if (myState->myinfo)
     330                 :        452 :         pfree(myState->myinfo);
     331                 :     102078 :     myState->myinfo = NULL;
     332                 :            : 
     333                 :     102078 :     myState->attrinfo = typeinfo;
     334                 :     102078 :     myState->nattrs = numAttrs;
     335         [ +  + ]:     102078 :     if (numAttrs <= 0)
     336                 :         10 :         return;
     337                 :            : 
     338                 :     102068 :     myState->myinfo = (PrinttupAttrInfo *)
     339                 :     102068 :         palloc0(numAttrs * sizeof(PrinttupAttrInfo));
     340                 :            : 
     341         [ +  + ]:     419032 :     for (i = 0; i < numAttrs; i++)
     342                 :            :     {
     343                 :     316964 :         PrinttupAttrInfo *thisState = myState->myinfo + i;
     344         [ +  + ]:     316964 :         int16       format = (formats ? formats[i] : 0);
     345                 :     316964 :         Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
     346                 :            : 
     347                 :     316964 :         thisState->format = format;
     348         [ +  + ]:     316964 :         if (format == 0)
     349                 :            :         {
     350                 :     316916 :             getTypeOutputInfo(attr->atttypid,
     351                 :            :                               &thisState->typoutput,
     352                 :            :                               &thisState->typisvarlena);
     353                 :     316916 :             fmgr_info(thisState->typoutput, &thisState->finfo);
     354                 :            :         }
     355         [ +  - ]:         48 :         else if (format == 1)
     356                 :            :         {
     357                 :         48 :             getTypeBinaryOutputInfo(attr->atttypid,
     358                 :            :                                     &thisState->typsend,
     359                 :            :                                     &thisState->typisvarlena);
     360                 :         48 :             fmgr_info(thisState->typsend, &thisState->finfo);
     361                 :            :         }
     362                 :            :         else
     363         [ #  # ]:          0 :             ereport(ERROR,
     364                 :            :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     365                 :            :                      errmsg("unsupported format code: %d", format)));
     366                 :            :     }
     367                 :            : }
     368                 :            : 
     369                 :            : /* ----------------
     370                 :            :  *      printtup --- print a tuple in protocol 3.0
     371                 :            :  * ----------------
     372                 :            :  */
     373                 :            : static bool
     374                 :    1688552 : printtup(TupleTableSlot *slot, DestReceiver *self)
     375                 :            : {
     376                 :    1688552 :     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
     377                 :    1688552 :     DR_printtup *myState = (DR_printtup *) self;
     378                 :            :     MemoryContext oldcontext;
     379                 :    1688552 :     StringInfo  buf = &myState->buf;
     380                 :    1688552 :     int         natts = typeinfo->natts;
     381                 :            :     int         i;
     382                 :            : 
     383                 :            :     /* Set or update my derived attribute info, if needed */
     384 [ +  + ][ -  + ]:    1688552 :     if (myState->attrinfo != typeinfo || myState->nattrs != natts)
     385                 :     102078 :         printtup_prepare_info(myState, typeinfo, natts);
     386                 :            : 
     387                 :            :     /* Make sure the tuple is fully deconstructed */
     388                 :    1688552 :     slot_getallattrs(slot);
     389                 :            : 
     390                 :            :     /* Switch into per-row context so we can recover memory below */
     391                 :    1688552 :     oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
     392                 :            : 
     393                 :            :     /*
     394                 :            :      * Prepare a DataRow message (note buffer is in per-row context)
     395                 :            :      */
     396                 :    1688552 :     pq_beginmessage_reuse(buf, 'D');
     397                 :            : 
     398                 :    1688552 :     pq_sendint16(buf, natts);
     399                 :            : 
     400                 :            :     /*
     401                 :            :      * send the attributes of this tuple
     402                 :            :      */
     403         [ +  + ]:   10959692 :     for (i = 0; i < natts; ++i)
     404                 :            :     {
     405                 :    9271140 :         PrinttupAttrInfo *thisState = myState->myinfo + i;
     406                 :    9271140 :         Datum       attr = slot->tts_values[i];
     407                 :            : 
     408         [ +  + ]:    9271140 :         if (slot->tts_isnull[i])
     409                 :            :         {
     410                 :     905820 :             pq_sendint32(buf, -1);
     411                 :     905820 :             continue;
     412                 :            :         }
     413                 :            : 
     414                 :            :         /*
     415                 :            :          * Here we catch undefined bytes in datums that are returned to the
     416                 :            :          * client without hitting disk; see comments at the related check in
     417                 :            :          * PageAddItem().  This test is most useful for uncompressed,
     418                 :            :          * non-external datums, but we're quite likely to see such here when
     419                 :            :          * testing new C functions.
     420                 :            :          */
     421                 :    8365320 :         if (thisState->typisvarlena)
     422                 :            :             VALGRIND_CHECK_MEM_IS_DEFINED(DatumGetPointer(attr),
     423                 :            :                                           VARSIZE_ANY(attr));
     424                 :            : 
     425         [ +  + ]:    8365320 :         if (thisState->format == 0)
     426                 :            :         {
     427                 :            :             /* Text output */
     428                 :            :             char       *outputstr;
     429                 :            : 
     430                 :    8355444 :             outputstr = OutputFunctionCall(&thisState->finfo, attr);
     431                 :    8355444 :             pq_sendcountedtext(buf, outputstr, strlen(outputstr), false);
     432                 :            :         }
     433                 :            :         else
     434                 :            :         {
     435                 :            :             /* Binary output */
     436                 :            :             bytea      *outputbytes;
     437                 :            : 
     438                 :       9876 :             outputbytes = SendFunctionCall(&thisState->finfo, attr);
     439                 :       9876 :             pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
     440                 :       9876 :             pq_sendbytes(buf, VARDATA(outputbytes),
     441                 :       9876 :                          VARSIZE(outputbytes) - VARHDRSZ);
     442                 :            :         }
     443                 :            :     }
     444                 :            : 
     445                 :    1688552 :     pq_endmessage_reuse(buf);
     446                 :            : 
     447                 :            :     /* Return to caller's context, and flush row's temporary memory */
     448                 :    1688552 :     MemoryContextSwitchTo(oldcontext);
     449                 :    1688552 :     MemoryContextReset(myState->tmpcontext);
     450                 :            : 
     451                 :    1688552 :     return true;
     452                 :            : }
     453                 :            : 
     454                 :            : /* ----------------
     455                 :            :  *      printtup_20 --- print a tuple in protocol 2.0
     456                 :            :  * ----------------
     457                 :            :  */
     458                 :            : static bool
     459                 :          0 : printtup_20(TupleTableSlot *slot, DestReceiver *self)
     460                 :            : {
     461                 :          0 :     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
     462                 :          0 :     DR_printtup *myState = (DR_printtup *) self;
     463                 :            :     MemoryContext oldcontext;
     464                 :          0 :     StringInfo  buf = &myState->buf;
     465                 :          0 :     int         natts = typeinfo->natts;
     466                 :            :     int         i,
     467                 :            :                 j,
     468                 :            :                 k;
     469                 :            : 
     470                 :            :     /* Set or update my derived attribute info, if needed */
     471 [ #  # ][ #  # ]:          0 :     if (myState->attrinfo != typeinfo || myState->nattrs != natts)
     472                 :          0 :         printtup_prepare_info(myState, typeinfo, natts);
     473                 :            : 
     474                 :            :     /* Make sure the tuple is fully deconstructed */
     475                 :          0 :     slot_getallattrs(slot);
     476                 :            : 
     477                 :            :     /* Switch into per-row context so we can recover memory below */
     478                 :          0 :     oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
     479                 :            : 
     480                 :            :     /*
     481                 :            :      * tell the frontend to expect new tuple data (in ASCII style)
     482                 :            :      */
     483                 :          0 :     pq_beginmessage_reuse(buf, 'D');
     484                 :            : 
     485                 :            :     /*
     486                 :            :      * send a bitmap of which attributes are not null
     487                 :            :      */
     488                 :          0 :     j = 0;
     489                 :          0 :     k = 1 << 7;
     490         [ #  # ]:          0 :     for (i = 0; i < natts; ++i)
     491                 :            :     {
     492         [ #  # ]:          0 :         if (!slot->tts_isnull[i])
     493                 :          0 :             j |= k;             /* set bit if not null */
     494                 :          0 :         k >>= 1;
     495         [ #  # ]:          0 :         if (k == 0)             /* end of byte? */
     496                 :            :         {
     497                 :          0 :             pq_sendint8(buf, j);
     498                 :          0 :             j = 0;
     499                 :          0 :             k = 1 << 7;
     500                 :            :         }
     501                 :            :     }
     502         [ #  # ]:          0 :     if (k != (1 << 7))            /* flush last partial byte */
     503                 :          0 :         pq_sendint8(buf, j);
     504                 :            : 
     505                 :            :     /*
     506                 :            :      * send the attributes of this tuple
     507                 :            :      */
     508         [ #  # ]:          0 :     for (i = 0; i < natts; ++i)
     509                 :            :     {
     510                 :          0 :         PrinttupAttrInfo *thisState = myState->myinfo + i;
     511                 :          0 :         Datum       attr = slot->tts_values[i];
     512                 :            :         char       *outputstr;
     513                 :            : 
     514         [ #  # ]:          0 :         if (slot->tts_isnull[i])
     515                 :          0 :             continue;
     516                 :            : 
     517                 :            :         Assert(thisState->format == 0);
     518                 :            : 
     519                 :          0 :         outputstr = OutputFunctionCall(&thisState->finfo, attr);
     520                 :          0 :         pq_sendcountedtext(buf, outputstr, strlen(outputstr), true);
     521                 :            :     }
     522                 :            : 
     523                 :          0 :     pq_endmessage_reuse(buf);
     524                 :            : 
     525                 :            :     /* Return to caller's context, and flush row's temporary memory */
     526                 :          0 :     MemoryContextSwitchTo(oldcontext);
     527                 :          0 :     MemoryContextReset(myState->tmpcontext);
     528                 :            : 
     529                 :          0 :     return true;
     530                 :            : }
     531                 :            : 
     532                 :            : /* ----------------
     533                 :            :  *      printtup_shutdown
     534                 :            :  * ----------------
     535                 :            :  */
     536                 :            : static void
     537                 :     120932 : printtup_shutdown(DestReceiver *self)
     538                 :            : {
     539                 :     120932 :     DR_printtup *myState = (DR_printtup *) self;
     540                 :            : 
     541         [ +  + ]:     120932 :     if (myState->myinfo)
     542                 :     101506 :         pfree(myState->myinfo);
     543                 :     120932 :     myState->myinfo = NULL;
     544                 :            : 
     545                 :     120932 :     myState->attrinfo = NULL;
     546                 :            : 
     547         [ +  - ]:     120932 :     if (myState->tmpcontext)
     548                 :     120932 :         MemoryContextDelete(myState->tmpcontext);
     549                 :     120932 :     myState->tmpcontext = NULL;
     550                 :     120932 : }
     551                 :            : 
     552                 :            : /* ----------------
     553                 :            :  *      printtup_destroy
     554                 :            :  * ----------------
     555                 :            :  */
     556                 :            : static void
     557                 :     255558 : printtup_destroy(DestReceiver *self)
     558                 :            : {
     559                 :     255558 :     pfree(self);
     560                 :     255558 : }
     561                 :            : 
     562                 :            : /* ----------------
     563                 :            :  *      printatt
     564                 :            :  * ----------------
     565                 :            :  */
     566                 :            : static void
     567                 :        524 : printatt(unsigned attributeId,
     568                 :            :          Form_pg_attribute attributeP,
     569                 :            :          char *value)
     570                 :            : {
     571 [ +  - ][ +  + ]:        524 :     printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
         [ +  + ][ +  + ]
     572                 :            :            attributeId,
     573                 :        524 :            NameStr(attributeP->attname),
     574                 :            :            value != NULL ? " = \"" : "",
     575                 :            :            value != NULL ? value : "",
     576                 :            :            value != NULL ? "\"" : "",
     577                 :        524 :            (unsigned int) (attributeP->atttypid),
     578                 :        524 :            attributeP->attlen,
     579                 :            :            attributeP->atttypmod,
     580                 :        524 :            attributeP->attbyval ? 't' : 'f');
     581                 :        524 : }
     582                 :            : 
     583                 :            : /* ----------------
     584                 :            :  *      debugStartup - prepare to print tuples for an interactive backend
     585                 :            :  * ----------------
     586                 :            :  */
     587                 :            : void
     588                 :        262 : debugStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
     589                 :            : {
     590                 :        262 :     int         natts = typeinfo->natts;
     591                 :            :     int         i;
     592                 :            : 
     593                 :            :     /*
     594                 :            :      * show the return type of the tuples
     595                 :            :      */
     596         [ +  + ]:        524 :     for (i = 0; i < natts; ++i)
     597                 :        262 :         printatt((unsigned) i + 1, TupleDescAttr(typeinfo, i), NULL);
     598                 :        262 :     printf("\t----\n");
     599                 :        262 : }
     600                 :            : 
     601                 :            : /* ----------------
     602                 :            :  *      debugtup - print one tuple for an interactive backend
     603                 :            :  * ----------------
     604                 :            :  */
     605                 :            : bool
     606                 :        262 : debugtup(TupleTableSlot *slot, DestReceiver *self)
     607                 :            : {
     608                 :        262 :     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
     609                 :        262 :     int         natts = typeinfo->natts;
     610                 :            :     int         i;
     611                 :            :     Datum       attr;
     612                 :            :     char       *value;
     613                 :            :     bool        isnull;
     614                 :            :     Oid         typoutput;
     615                 :            :     bool        typisvarlena;
     616                 :            : 
     617         [ +  + ]:        524 :     for (i = 0; i < natts; ++i)
     618                 :            :     {
     619                 :        262 :         attr = slot_getattr(slot, i + 1, &isnull);
     620         [ -  + ]:        262 :         if (isnull)
     621                 :          0 :             continue;
     622                 :        262 :         getTypeOutputInfo(TupleDescAttr(typeinfo, i)->atttypid,
     623                 :            :                           &typoutput, &typisvarlena);
     624                 :            : 
     625                 :        262 :         value = OidOutputFunctionCall(typoutput, attr);
     626                 :            : 
     627                 :        262 :         printatt((unsigned) i + 1, TupleDescAttr(typeinfo, i), value);
     628                 :            :     }
     629                 :        262 :     printf("\t----\n");
     630                 :            : 
     631                 :        262 :     return true;
     632                 :            : }
     633                 :            : 
     634                 :            : /* ----------------
     635                 :            :  *      printtup_internal_20 --- print a binary tuple in protocol 2.0
     636                 :            :  *
     637                 :            :  * We use a different message type, i.e. 'B' instead of 'D' to
     638                 :            :  * indicate a tuple in internal (binary) form.
     639                 :            :  *
     640                 :            :  * This is largely same as printtup_20, except we use binary formatting.
     641                 :            :  * ----------------
     642                 :            :  */
     643                 :            : static bool
     644                 :          0 : printtup_internal_20(TupleTableSlot *slot, DestReceiver *self)
     645                 :            : {
     646                 :          0 :     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
     647                 :          0 :     DR_printtup *myState = (DR_printtup *) self;
     648                 :            :     MemoryContext oldcontext;
     649                 :          0 :     StringInfo  buf = &myState->buf;
     650                 :          0 :     int         natts = typeinfo->natts;
     651                 :            :     int         i,
     652                 :            :                 j,
     653                 :            :                 k;
     654                 :            : 
     655                 :            :     /* Set or update my derived attribute info, if needed */
     656 [ #  # ][ #  # ]:          0 :     if (myState->attrinfo != typeinfo || myState->nattrs != natts)
     657                 :          0 :         printtup_prepare_info(myState, typeinfo, natts);
     658                 :            : 
     659                 :            :     /* Make sure the tuple is fully deconstructed */
     660                 :          0 :     slot_getallattrs(slot);
     661                 :            : 
     662                 :            :     /* Switch into per-row context so we can recover memory below */
     663                 :          0 :     oldcontext = MemoryContextSwitchTo(myState->tmpcontext);
     664                 :            : 
     665                 :            :     /*
     666                 :            :      * tell the frontend to expect new tuple data (in binary style)
     667                 :            :      */
     668                 :          0 :     pq_beginmessage_reuse(buf, 'B');
     669                 :            : 
     670                 :            :     /*
     671                 :            :      * send a bitmap of which attributes are not null
     672                 :            :      */
     673                 :          0 :     j = 0;
     674                 :          0 :     k = 1 << 7;
     675         [ #  # ]:          0 :     for (i = 0; i < natts; ++i)
     676                 :            :     {
     677         [ #  # ]:          0 :         if (!slot->tts_isnull[i])
     678                 :          0 :             j |= k;             /* set bit if not null */
     679                 :          0 :         k >>= 1;
     680         [ #  # ]:          0 :         if (k == 0)             /* end of byte? */
     681                 :            :         {
     682                 :          0 :             pq_sendint8(buf, j);
     683                 :          0 :             j = 0;
     684                 :          0 :             k = 1 << 7;
     685                 :            :         }
     686                 :            :     }
     687         [ #  # ]:          0 :     if (k != (1 << 7))            /* flush last partial byte */
     688                 :          0 :         pq_sendint8(buf, j);
     689                 :            : 
     690                 :            :     /*
     691                 :            :      * send the attributes of this tuple
     692                 :            :      */
     693         [ #  # ]:          0 :     for (i = 0; i < natts; ++i)
     694                 :            :     {
     695                 :          0 :         PrinttupAttrInfo *thisState = myState->myinfo + i;
     696                 :          0 :         Datum       attr = slot->tts_values[i];
     697                 :            :         bytea      *outputbytes;
     698                 :            : 
     699         [ #  # ]:          0 :         if (slot->tts_isnull[i])
     700                 :          0 :             continue;
     701                 :            : 
     702                 :            :         Assert(thisState->format == 1);
     703                 :            : 
     704                 :          0 :         outputbytes = SendFunctionCall(&thisState->finfo, attr);
     705                 :          0 :         pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
     706                 :          0 :         pq_sendbytes(buf, VARDATA(outputbytes),
     707                 :          0 :                      VARSIZE(outputbytes) - VARHDRSZ);
     708                 :            :     }
     709                 :            : 
     710                 :          0 :     pq_endmessage_reuse(buf);
     711                 :            : 
     712                 :            :     /* Return to caller's context, and flush row's temporary memory */
     713                 :          0 :     MemoryContextSwitchTo(oldcontext);
     714                 :          0 :     MemoryContextReset(myState->tmpcontext);
     715                 :            : 
     716                 :          0 :     return true;
     717                 :            : }

Generated by: LCOV version 1.13