Header And Logo

PostgreSQL
| The world's most advanced open source database.

printtup.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * printtup.c
00004  *    Routines to print out tuples to the destination (both frontend
00005  *    clients and standalone backends are supported here).
00006  *
00007  *
00008  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00009  * Portions Copyright (c) 1994, Regents of the University of California
00010  *
00011  * IDENTIFICATION
00012  *    src/backend/access/common/printtup.c
00013  *
00014  *-------------------------------------------------------------------------
00015  */
00016 #include "postgres.h"
00017 
00018 #include "access/printtup.h"
00019 #include "libpq/libpq.h"
00020 #include "libpq/pqformat.h"
00021 #include "tcop/pquery.h"
00022 #include "utils/lsyscache.h"
00023 
00024 
00025 static void printtup_startup(DestReceiver *self, int operation,
00026                  TupleDesc typeinfo);
00027 static void printtup(TupleTableSlot *slot, DestReceiver *self);
00028 static void printtup_20(TupleTableSlot *slot, DestReceiver *self);
00029 static void printtup_internal_20(TupleTableSlot *slot, DestReceiver *self);
00030 static void printtup_shutdown(DestReceiver *self);
00031 static void printtup_destroy(DestReceiver *self);
00032 
00033 
00034 /* ----------------------------------------------------------------
00035  *      printtup / debugtup support
00036  * ----------------------------------------------------------------
00037  */
00038 
00039 /* ----------------
00040  *      Private state for a printtup destination object
00041  *
00042  * NOTE: finfo is the lookup info for either typoutput or typsend, whichever
00043  * we are using for this column.
00044  * ----------------
00045  */
00046 typedef struct
00047 {                               /* Per-attribute information */
00048     Oid         typoutput;      /* Oid for the type's text output fn */
00049     Oid         typsend;        /* Oid for the type's binary output fn */
00050     bool        typisvarlena;   /* is it varlena (ie possibly toastable)? */
00051     int16       format;         /* format code for this column */
00052     FmgrInfo    finfo;          /* Precomputed call info for output fn */
00053 } PrinttupAttrInfo;
00054 
00055 typedef struct
00056 {
00057     DestReceiver pub;           /* publicly-known function pointers */
00058     Portal      portal;         /* the Portal we are printing from */
00059     bool        sendDescrip;    /* send RowDescription at startup? */
00060     TupleDesc   attrinfo;       /* The attr info we are set up for */
00061     int         nattrs;
00062     PrinttupAttrInfo *myinfo;   /* Cached info about each attr */
00063 } DR_printtup;
00064 
00065 /* ----------------
00066  *      Initialize: create a DestReceiver for printtup
00067  * ----------------
00068  */
00069 DestReceiver *
00070 printtup_create_DR(CommandDest dest)
00071 {
00072     DR_printtup *self = (DR_printtup *) palloc0(sizeof(DR_printtup));
00073 
00074     self->pub.receiveSlot = printtup;   /* might get changed later */
00075     self->pub.rStartup = printtup_startup;
00076     self->pub.rShutdown = printtup_shutdown;
00077     self->pub.rDestroy = printtup_destroy;
00078     self->pub.mydest = dest;
00079 
00080     /*
00081      * Send T message automatically if DestRemote, but not if
00082      * DestRemoteExecute
00083      */
00084     self->sendDescrip = (dest == DestRemote);
00085 
00086     self->attrinfo = NULL;
00087     self->nattrs = 0;
00088     self->myinfo = NULL;
00089 
00090     return (DestReceiver *) self;
00091 }
00092 
00093 /*
00094  * Set parameters for a DestRemote (or DestRemoteExecute) receiver
00095  */
00096 void
00097 SetRemoteDestReceiverParams(DestReceiver *self, Portal portal)
00098 {
00099     DR_printtup *myState = (DR_printtup *) self;
00100 
00101     Assert(myState->pub.mydest == DestRemote ||
00102            myState->pub.mydest == DestRemoteExecute);
00103 
00104     myState->portal = portal;
00105 
00106     if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
00107     {
00108         /*
00109          * In protocol 2.0 the Bind message does not exist, so there is no way
00110          * for the columns to have different print formats; it's sufficient to
00111          * look at the first one.
00112          */
00113         if (portal->formats && portal->formats[0] != 0)
00114             myState->pub.receiveSlot = printtup_internal_20;
00115         else
00116             myState->pub.receiveSlot = printtup_20;
00117     }
00118 }
00119 
00120 static void
00121 printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
00122 {
00123     DR_printtup *myState = (DR_printtup *) self;
00124     Portal      portal = myState->portal;
00125 
00126     if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
00127     {
00128         /*
00129          * Send portal name to frontend (obsolete cruft, gone in proto 3.0)
00130          *
00131          * If portal name not specified, use "blank" portal.
00132          */
00133         const char *portalName = portal->name;
00134 
00135         if (portalName == NULL || portalName[0] == '\0')
00136             portalName = "blank";
00137 
00138         pq_puttextmessage('P', portalName);
00139     }
00140 
00141     /*
00142      * If we are supposed to emit row descriptions, then send the tuple
00143      * descriptor of the tuples.
00144      */
00145     if (myState->sendDescrip)
00146         SendRowDescriptionMessage(typeinfo,
00147                                   FetchPortalTargetList(portal),
00148                                   portal->formats);
00149 
00150     /* ----------------
00151      * We could set up the derived attr info at this time, but we postpone it
00152      * until the first call of printtup, for 2 reasons:
00153      * 1. We don't waste time (compared to the old way) if there are no
00154      *    tuples at all to output.
00155      * 2. Checking in printtup allows us to handle the case that the tuples
00156      *    change type midway through (although this probably can't happen in
00157      *    the current executor).
00158      * ----------------
00159      */
00160 }
00161 
00162 /*
00163  * SendRowDescriptionMessage --- send a RowDescription message to the frontend
00164  *
00165  * Notes: the TupleDesc has typically been manufactured by ExecTypeFromTL()
00166  * or some similar function; it does not contain a full set of fields.
00167  * The targetlist will be NIL when executing a utility function that does
00168  * not have a plan.  If the targetlist isn't NIL then it is a Query node's
00169  * targetlist; it is up to us to ignore resjunk columns in it.  The formats[]
00170  * array pointer might be NULL (if we are doing Describe on a prepared stmt);
00171  * send zeroes for the format codes in that case.
00172  */
00173 void
00174 SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist, int16 *formats)
00175 {
00176     Form_pg_attribute *attrs = typeinfo->attrs;
00177     int         natts = typeinfo->natts;
00178     int         proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
00179     int         i;
00180     StringInfoData buf;
00181     ListCell   *tlist_item = list_head(targetlist);
00182 
00183     pq_beginmessage(&buf, 'T'); /* tuple descriptor message type */
00184     pq_sendint(&buf, natts, 2); /* # of attrs in tuples */
00185 
00186     for (i = 0; i < natts; ++i)
00187     {
00188         Oid         atttypid = attrs[i]->atttypid;
00189         int32       atttypmod = attrs[i]->atttypmod;
00190 
00191         pq_sendstring(&buf, NameStr(attrs[i]->attname));
00192         /* column ID info appears in protocol 3.0 and up */
00193         if (proto >= 3)
00194         {
00195             /* Do we have a non-resjunk tlist item? */
00196             while (tlist_item &&
00197                    ((TargetEntry *) lfirst(tlist_item))->resjunk)
00198                 tlist_item = lnext(tlist_item);
00199             if (tlist_item)
00200             {
00201                 TargetEntry *tle = (TargetEntry *) lfirst(tlist_item);
00202 
00203                 pq_sendint(&buf, tle->resorigtbl, 4);
00204                 pq_sendint(&buf, tle->resorigcol, 2);
00205                 tlist_item = lnext(tlist_item);
00206             }
00207             else
00208             {
00209                 /* No info available, so send zeroes */
00210                 pq_sendint(&buf, 0, 4);
00211                 pq_sendint(&buf, 0, 2);
00212             }
00213         }
00214         /* If column is a domain, send the base type and typmod instead */
00215         atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);
00216         pq_sendint(&buf, (int) atttypid, sizeof(atttypid));
00217         pq_sendint(&buf, attrs[i]->attlen, sizeof(attrs[i]->attlen));
00218         /* typmod appears in protocol 2.0 and up */
00219         if (proto >= 2)
00220             pq_sendint(&buf, atttypmod, sizeof(atttypmod));
00221         /* format info appears in protocol 3.0 and up */
00222         if (proto >= 3)
00223         {
00224             if (formats)
00225                 pq_sendint(&buf, formats[i], 2);
00226             else
00227                 pq_sendint(&buf, 0, 2);
00228         }
00229     }
00230     pq_endmessage(&buf);
00231 }
00232 
00233 /*
00234  * Get the lookup info that printtup() needs
00235  */
00236 static void
00237 printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
00238 {
00239     int16      *formats = myState->portal->formats;
00240     int         i;
00241 
00242     /* get rid of any old data */
00243     if (myState->myinfo)
00244         pfree(myState->myinfo);
00245     myState->myinfo = NULL;
00246 
00247     myState->attrinfo = typeinfo;
00248     myState->nattrs = numAttrs;
00249     if (numAttrs <= 0)
00250         return;
00251 
00252     myState->myinfo = (PrinttupAttrInfo *)
00253         palloc0(numAttrs * sizeof(PrinttupAttrInfo));
00254 
00255     for (i = 0; i < numAttrs; i++)
00256     {
00257         PrinttupAttrInfo *thisState = myState->myinfo + i;
00258         int16       format = (formats ? formats[i] : 0);
00259 
00260         thisState->format = format;
00261         if (format == 0)
00262         {
00263             getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
00264                               &thisState->typoutput,
00265                               &thisState->typisvarlena);
00266             fmgr_info(thisState->typoutput, &thisState->finfo);
00267         }
00268         else if (format == 1)
00269         {
00270             getTypeBinaryOutputInfo(typeinfo->attrs[i]->atttypid,
00271                                     &thisState->typsend,
00272                                     &thisState->typisvarlena);
00273             fmgr_info(thisState->typsend, &thisState->finfo);
00274         }
00275         else
00276             ereport(ERROR,
00277                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00278                      errmsg("unsupported format code: %d", format)));
00279     }
00280 }
00281 
00282 /* ----------------
00283  *      printtup --- print a tuple in protocol 3.0
00284  * ----------------
00285  */
00286 static void
00287 printtup(TupleTableSlot *slot, DestReceiver *self)
00288 {
00289     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
00290     DR_printtup *myState = (DR_printtup *) self;
00291     StringInfoData buf;
00292     int         natts = typeinfo->natts;
00293     int         i;
00294 
00295     /* Set or update my derived attribute info, if needed */
00296     if (myState->attrinfo != typeinfo || myState->nattrs != natts)
00297         printtup_prepare_info(myState, typeinfo, natts);
00298 
00299     /* Make sure the tuple is fully deconstructed */
00300     slot_getallattrs(slot);
00301 
00302     /*
00303      * Prepare a DataRow message
00304      */
00305     pq_beginmessage(&buf, 'D');
00306 
00307     pq_sendint(&buf, natts, 2);
00308 
00309     /*
00310      * send the attributes of this tuple
00311      */
00312     for (i = 0; i < natts; ++i)
00313     {
00314         PrinttupAttrInfo *thisState = myState->myinfo + i;
00315         Datum       origattr = slot->tts_values[i],
00316                     attr;
00317 
00318         if (slot->tts_isnull[i])
00319         {
00320             pq_sendint(&buf, -1, 4);
00321             continue;
00322         }
00323 
00324         /*
00325          * If we have a toasted datum, forcibly detoast it here to avoid
00326          * memory leakage inside the type's output routine.
00327          */
00328         if (thisState->typisvarlena)
00329             attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
00330         else
00331             attr = origattr;
00332 
00333         if (thisState->format == 0)
00334         {
00335             /* Text output */
00336             char       *outputstr;
00337 
00338             outputstr = OutputFunctionCall(&thisState->finfo, attr);
00339             pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
00340             pfree(outputstr);
00341         }
00342         else
00343         {
00344             /* Binary output */
00345             bytea      *outputbytes;
00346 
00347             outputbytes = SendFunctionCall(&thisState->finfo, attr);
00348             pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
00349             pq_sendbytes(&buf, VARDATA(outputbytes),
00350                          VARSIZE(outputbytes) - VARHDRSZ);
00351             pfree(outputbytes);
00352         }
00353 
00354         /* Clean up detoasted copy, if any */
00355         if (DatumGetPointer(attr) != DatumGetPointer(origattr))
00356             pfree(DatumGetPointer(attr));
00357     }
00358 
00359     pq_endmessage(&buf);
00360 }
00361 
00362 /* ----------------
00363  *      printtup_20 --- print a tuple in protocol 2.0
00364  * ----------------
00365  */
00366 static void
00367 printtup_20(TupleTableSlot *slot, DestReceiver *self)
00368 {
00369     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
00370     DR_printtup *myState = (DR_printtup *) self;
00371     StringInfoData buf;
00372     int         natts = typeinfo->natts;
00373     int         i,
00374                 j,
00375                 k;
00376 
00377     /* Set or update my derived attribute info, if needed */
00378     if (myState->attrinfo != typeinfo || myState->nattrs != natts)
00379         printtup_prepare_info(myState, typeinfo, natts);
00380 
00381     /* Make sure the tuple is fully deconstructed */
00382     slot_getallattrs(slot);
00383 
00384     /*
00385      * tell the frontend to expect new tuple data (in ASCII style)
00386      */
00387     pq_beginmessage(&buf, 'D');
00388 
00389     /*
00390      * send a bitmap of which attributes are not null
00391      */
00392     j = 0;
00393     k = 1 << 7;
00394     for (i = 0; i < natts; ++i)
00395     {
00396         if (!slot->tts_isnull[i])
00397             j |= k;             /* set bit if not null */
00398         k >>= 1;
00399         if (k == 0)             /* end of byte? */
00400         {
00401             pq_sendint(&buf, j, 1);
00402             j = 0;
00403             k = 1 << 7;
00404         }
00405     }
00406     if (k != (1 << 7))          /* flush last partial byte */
00407         pq_sendint(&buf, j, 1);
00408 
00409     /*
00410      * send the attributes of this tuple
00411      */
00412     for (i = 0; i < natts; ++i)
00413     {
00414         PrinttupAttrInfo *thisState = myState->myinfo + i;
00415         Datum       origattr = slot->tts_values[i],
00416                     attr;
00417         char       *outputstr;
00418 
00419         if (slot->tts_isnull[i])
00420             continue;
00421 
00422         Assert(thisState->format == 0);
00423 
00424         /*
00425          * If we have a toasted datum, forcibly detoast it here to avoid
00426          * memory leakage inside the type's output routine.
00427          */
00428         if (thisState->typisvarlena)
00429             attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
00430         else
00431             attr = origattr;
00432 
00433         outputstr = OutputFunctionCall(&thisState->finfo, attr);
00434         pq_sendcountedtext(&buf, outputstr, strlen(outputstr), true);
00435         pfree(outputstr);
00436 
00437         /* Clean up detoasted copy, if any */
00438         if (DatumGetPointer(attr) != DatumGetPointer(origattr))
00439             pfree(DatumGetPointer(attr));
00440     }
00441 
00442     pq_endmessage(&buf);
00443 }
00444 
00445 /* ----------------
00446  *      printtup_shutdown
00447  * ----------------
00448  */
00449 static void
00450 printtup_shutdown(DestReceiver *self)
00451 {
00452     DR_printtup *myState = (DR_printtup *) self;
00453 
00454     if (myState->myinfo)
00455         pfree(myState->myinfo);
00456     myState->myinfo = NULL;
00457 
00458     myState->attrinfo = NULL;
00459 }
00460 
00461 /* ----------------
00462  *      printtup_destroy
00463  * ----------------
00464  */
00465 static void
00466 printtup_destroy(DestReceiver *self)
00467 {
00468     pfree(self);
00469 }
00470 
00471 /* ----------------
00472  *      printatt
00473  * ----------------
00474  */
00475 static void
00476 printatt(unsigned attributeId,
00477          Form_pg_attribute attributeP,
00478          char *value)
00479 {
00480     printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
00481            attributeId,
00482            NameStr(attributeP->attname),
00483            value != NULL ? " = \"" : "",
00484            value != NULL ? value : "",
00485            value != NULL ? "\"" : "",
00486            (unsigned int) (attributeP->atttypid),
00487            attributeP->attlen,
00488            attributeP->atttypmod,
00489            attributeP->attbyval ? 't' : 'f');
00490 }
00491 
00492 /* ----------------
00493  *      debugStartup - prepare to print tuples for an interactive backend
00494  * ----------------
00495  */
00496 void
00497 debugStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
00498 {
00499     int         natts = typeinfo->natts;
00500     Form_pg_attribute *attinfo = typeinfo->attrs;
00501     int         i;
00502 
00503     /*
00504      * show the return type of the tuples
00505      */
00506     for (i = 0; i < natts; ++i)
00507         printatt((unsigned) i + 1, attinfo[i], NULL);
00508     printf("\t----\n");
00509 }
00510 
00511 /* ----------------
00512  *      debugtup - print one tuple for an interactive backend
00513  * ----------------
00514  */
00515 void
00516 debugtup(TupleTableSlot *slot, DestReceiver *self)
00517 {
00518     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
00519     int         natts = typeinfo->natts;
00520     int         i;
00521     Datum       origattr,
00522                 attr;
00523     char       *value;
00524     bool        isnull;
00525     Oid         typoutput;
00526     bool        typisvarlena;
00527 
00528     for (i = 0; i < natts; ++i)
00529     {
00530         origattr = slot_getattr(slot, i + 1, &isnull);
00531         if (isnull)
00532             continue;
00533         getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
00534                           &typoutput, &typisvarlena);
00535 
00536         /*
00537          * If we have a toasted datum, forcibly detoast it here to avoid
00538          * memory leakage inside the type's output routine.
00539          */
00540         if (typisvarlena)
00541             attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
00542         else
00543             attr = origattr;
00544 
00545         value = OidOutputFunctionCall(typoutput, attr);
00546 
00547         printatt((unsigned) i + 1, typeinfo->attrs[i], value);
00548 
00549         pfree(value);
00550 
00551         /* Clean up detoasted copy, if any */
00552         if (DatumGetPointer(attr) != DatumGetPointer(origattr))
00553             pfree(DatumGetPointer(attr));
00554     }
00555     printf("\t----\n");
00556 }
00557 
00558 /* ----------------
00559  *      printtup_internal_20 --- print a binary tuple in protocol 2.0
00560  *
00561  * We use a different message type, i.e. 'B' instead of 'D' to
00562  * indicate a tuple in internal (binary) form.
00563  *
00564  * This is largely same as printtup_20, except we use binary formatting.
00565  * ----------------
00566  */
00567 static void
00568 printtup_internal_20(TupleTableSlot *slot, DestReceiver *self)
00569 {
00570     TupleDesc   typeinfo = slot->tts_tupleDescriptor;
00571     DR_printtup *myState = (DR_printtup *) self;
00572     StringInfoData buf;
00573     int         natts = typeinfo->natts;
00574     int         i,
00575                 j,
00576                 k;
00577 
00578     /* Set or update my derived attribute info, if needed */
00579     if (myState->attrinfo != typeinfo || myState->nattrs != natts)
00580         printtup_prepare_info(myState, typeinfo, natts);
00581 
00582     /* Make sure the tuple is fully deconstructed */
00583     slot_getallattrs(slot);
00584 
00585     /*
00586      * tell the frontend to expect new tuple data (in binary style)
00587      */
00588     pq_beginmessage(&buf, 'B');
00589 
00590     /*
00591      * send a bitmap of which attributes are not null
00592      */
00593     j = 0;
00594     k = 1 << 7;
00595     for (i = 0; i < natts; ++i)
00596     {
00597         if (!slot->tts_isnull[i])
00598             j |= k;             /* set bit if not null */
00599         k >>= 1;
00600         if (k == 0)             /* end of byte? */
00601         {
00602             pq_sendint(&buf, j, 1);
00603             j = 0;
00604             k = 1 << 7;
00605         }
00606     }
00607     if (k != (1 << 7))          /* flush last partial byte */
00608         pq_sendint(&buf, j, 1);
00609 
00610     /*
00611      * send the attributes of this tuple
00612      */
00613     for (i = 0; i < natts; ++i)
00614     {
00615         PrinttupAttrInfo *thisState = myState->myinfo + i;
00616         Datum       origattr = slot->tts_values[i],
00617                     attr;
00618         bytea      *outputbytes;
00619 
00620         if (slot->tts_isnull[i])
00621             continue;
00622 
00623         Assert(thisState->format == 1);
00624 
00625         /*
00626          * If we have a toasted datum, forcibly detoast it here to avoid
00627          * memory leakage inside the type's output routine.
00628          */
00629         if (thisState->typisvarlena)
00630             attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
00631         else
00632             attr = origattr;
00633 
00634         outputbytes = SendFunctionCall(&thisState->finfo, attr);
00635         /* We assume the result will not have been toasted */
00636         pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
00637         pq_sendbytes(&buf, VARDATA(outputbytes),
00638                      VARSIZE(outputbytes) - VARHDRSZ);
00639         pfree(outputbytes);
00640 
00641         /* Clean up detoasted copy, if any */
00642         if (DatumGetPointer(attr) != DatumGetPointer(origattr))
00643             pfree(DatumGetPointer(attr));
00644     }
00645 
00646     pq_endmessage(&buf);
00647 }