Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/backend/access/common/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 12 kB image not shown  

Quelle  printtup.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * printtup.c
 *   Routines to print out tuples to the destination (both frontend
 *   clients and standalone backends are supported here).
 *
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *   src/backend/access/common/printtup.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/printtup.h"
#include "libpq/pqformat.h"
#include "libpq/protocol.h"
#include "tcop/pquery.h"
#include "utils/lsyscache.h"
#include "utils/memdebug.h"
#include "utils/memutils.h"


static void printtup_startup(DestReceiver *self, int operation,
        TupleDesc typeinfo);
static bool printtup(TupleTableSlot *slot, DestReceiver *self);
static void printtup_shutdown(DestReceiver *self);
static void printtup_destroy(DestReceiver *self);

/* ----------------------------------------------------------------
 *  printtup / debugtup support
 * ----------------------------------------------------------------
 */


/* ----------------
 *  Private state for a printtup destination object
 *
 * NOTE: finfo is the lookup info for either typoutput or typsend, whichever
 * we are using for this column.
 * ----------------
 */

typedef struct
{        /* Per-attribute information */
 Oid   typoutput;  /* Oid for the type's text output fn */
 Oid   typsend;  /* Oid for the type's binary output fn */
 bool  typisvarlena; /* is it varlena (ie possibly toastable)? */
 int16  format;   /* format code for this column */
 FmgrInfo finfo;   /* Precomputed call info for output fn */
} PrinttupAttrInfo;

typedef struct
{
 DestReceiver pub;   /* publicly-known function pointers */
 Portal  portal;   /* the Portal we are printing from */
 bool  sendDescrip; /* send RowDescription at startup? */
 TupleDesc attrinfo;  /* The attr info we are set up for */
 int   nattrs;
 PrinttupAttrInfo *myinfo; /* Cached info about each attr */
 StringInfoData buf;   /* output buffer (*not* in tmpcontext) */
 MemoryContext tmpcontext; /* Memory context for per-row workspace */
} DR_printtup;

/* ----------------
 *  Initialize: create a DestReceiver for printtup
 * ----------------
 */

DestReceiver *
printtup_create_DR(CommandDest dest)
{
 DR_printtup *self = (DR_printtup *) palloc0(sizeof(DR_printtup));

 self->pub.receiveSlot = printtup; /* might get changed later */
 self->pub.rStartup = printtup_startup;
 self->pub.rShutdown = printtup_shutdown;
 self->pub.rDestroy = printtup_destroy;
 self->pub.mydest = dest;

 /*
  * Send T message automatically if DestRemote, but not if
  * DestRemoteExecute
 */

 self->sendDescrip = (dest == DestRemote);

 self->attrinfo = NULL;
 self->nattrs = 0;
 self->myinfo = NULL;
 self->buf.data = NULL;
 self->tmpcontext = NULL;

 return (DestReceiver *) self;
}

/*
 * Set parameters for a DestRemote (or DestRemoteExecute) receiver
 */

void
SetRemoteDestReceiverParams(DestReceiver *self, Portal portal)
{
 DR_printtup *myState = (DR_printtup *) self;

 Assert(myState->pub.mydest == DestRemote ||
     myState->pub.mydest == DestRemoteExecute);

 myState->portal = portal;
}

static void
printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
{
 DR_printtup *myState = (DR_printtup *) self;
 Portal  portal = myState->portal;

 /*
  * Create I/O buffer to be used for all messages.  This cannot be inside
  * tmpcontext, since we want to re-use it across rows.
 */

 initStringInfo(&myState->buf);

 /*
  * Create a temporary memory context that we can reset once per row to
  * recover palloc'd memory.  This avoids any problems with leaks inside
  * datatype output routines, and should be faster than retail pfree's
  * anyway.
 */

 myState->tmpcontext = AllocSetContextCreate(CurrentMemoryContext,
            "printtup",
            ALLOCSET_DEFAULT_SIZES);

 /*
  * If we are supposed to emit row descriptions, then send the tuple
  * descriptor of the tuples.
 */

 if (myState->sendDescrip)
  SendRowDescriptionMessage(&myState->buf,
          typeinfo,
          FetchPortalTargetList(portal),
          portal->formats);

 /* ----------------
  * We could set up the derived attr info at this time, but we postpone it
  * until the first call of printtup, for 2 reasons:
  * 1. We don't waste time (compared to the old way) if there are no
  *   tuples at all to output.
  * 2. Checking in printtup allows us to handle the case that the tuples
  *   change type midway through (although this probably can't happen in
  *   the current executor).
  * ----------------
 */

}

/*
 * SendRowDescriptionMessage --- send a RowDescription message to the frontend
 *
 * Notes: the TupleDesc has typically been manufactured by ExecTypeFromTL()
 * or some similar function; it does not contain a full set of fields.
 * The targetlist will be NIL when executing a utility function that does
 * not have a plan.  If the targetlist isn't NIL then it is a Query node's
 * targetlist; it is up to us to ignore resjunk columns in it.  The formats[]
 * array pointer might be NULL (if we are doing Describe on a prepared stmt);
 * send zeroes for the format codes in that case.
 */

void
SendRowDescriptionMessage(StringInfo buf, TupleDesc typeinfo,
        List *targetlist, int16 *formats)
{
 int   natts = typeinfo->natts;
 int   i;
 ListCell   *tlist_item = list_head(targetlist);

 /* tuple descriptor message type */
 pq_beginmessage_reuse(buf, PqMsg_RowDescription);
 /* # of attrs in tuples */
 pq_sendint16(buf, natts);

 /*
  * Preallocate memory for the entire message to be sent. That allows to
  * use the significantly faster inline pqformat.h functions and to avoid
  * reallocations.
  *
  * Have to overestimate the size of the column-names, to account for
  * character set overhead.
 */

 enlargeStringInfo(buf, (NAMEDATALEN * MAX_CONVERSION_GROWTH /* attname */
       + sizeof(Oid) /* resorigtbl */
       + sizeof(AttrNumber) /* resorigcol */
       + sizeof(Oid) /* atttypid */
       + sizeof(int16) /* attlen */
       + sizeof(int32) /* attypmod */
       + sizeof(int16) /* format */
       ) * natts);

 for (i = 0; i < natts; ++i)
 {
  Form_pg_attribute att = TupleDescAttr(typeinfo, i);
  Oid   atttypid = att->atttypid;
  int32  atttypmod = att->atttypmod;
  Oid   resorigtbl;
  AttrNumber resorigcol;
  int16  format;

  /*
   * If column is a domain, send the base type and typmod instead.
   * Lookup before sending any ints, for efficiency.
 */

  atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod);

  /* Do we have a non-resjunk tlist item? */
  while (tlist_item &&
      ((TargetEntry *) lfirst(tlist_item))->resjunk)
   tlist_item = lnext(targetlist, tlist_item);
  if (tlist_item)
  {
   TargetEntry *tle = (TargetEntry *) lfirst(tlist_item);

   resorigtbl = tle->resorigtbl;
   resorigcol = tle->resorigcol;
   tlist_item = lnext(targetlist, tlist_item);
  }
  else
  {
   /* No info available, so send zeroes */
   resorigtbl = 0;
   resorigcol = 0;
  }

  if (formats)
   format = formats[i];
  else
   format = 0;

  pq_writestring(buf, NameStr(att->attname));
  pq_writeint32(buf, resorigtbl);
  pq_writeint16(buf, resorigcol);
  pq_writeint32(buf, atttypid);
  pq_writeint16(buf, att->attlen);
  pq_writeint32(buf, atttypmod);
  pq_writeint16(buf, format);
 }

 pq_endmessage_reuse(buf);
}

/*
 * Get the lookup info that printtup() needs
 */

static void
printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
{
 int16    *formats = myState->portal->formats;
 int   i;

 /* get rid of any old data */
 if (myState->myinfo)
  pfree(myState->myinfo);
 myState->myinfo = NULL;

 myState->attrinfo = typeinfo;
 myState->nattrs = numAttrs;
 if (numAttrs <= 0)
  return;

 myState->myinfo = (PrinttupAttrInfo *)
  palloc0(numAttrs * sizeof(PrinttupAttrInfo));

 for (i = 0; i < numAttrs; i++)
 {
  PrinttupAttrInfo *thisState = myState->myinfo + i;
  int16  format = (formats ? formats[i] : 0);
  Form_pg_attribute attr = TupleDescAttr(typeinfo, i);

  thisState->format = format;
  if (format == 0)
  {
   getTypeOutputInfo(attr->atttypid,
         &thisState->typoutput,
         &thisState->typisvarlena);
   fmgr_info(thisState->typoutput, &thisState->finfo);
  }
  else if (format == 1)
  {
   getTypeBinaryOutputInfo(attr->atttypid,
         &thisState->typsend,
         &thisState->typisvarlena);
   fmgr_info(thisState->typsend, &thisState->finfo);
  }
  else
   ereport(ERROR,
     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      errmsg("unsupported format code: %d", format)));
 }
}

/* ----------------
 *  printtup --- send a tuple to the client
 *
 * Note: if you change this function, see also serializeAnalyzeReceive
 * in explain.c, which is meant to replicate the computations done here.
 * ----------------
 */

static bool
printtup(TupleTableSlot *slot, DestReceiver *self)
{
 TupleDesc typeinfo = slot->tts_tupleDescriptor;
 DR_printtup *myState = (DR_printtup *) self;
 MemoryContext oldcontext;
 StringInfo buf = &myState->buf;
 int   natts = typeinfo->natts;
 int   i;

 /* Set or update my derived attribute info, if needed */
 if (myState->attrinfo != typeinfo || myState->nattrs != natts)
  printtup_prepare_info(myState, typeinfo, natts);

 /* Make sure the tuple is fully deconstructed */
 slot_getallattrs(slot);

 /* Switch into per-row context so we can recover memory below */
 oldcontext = MemoryContextSwitchTo(myState->tmpcontext);

 /*
  * Prepare a DataRow message (note buffer is in per-query context)
 */

 pq_beginmessage_reuse(buf, PqMsg_DataRow);

 pq_sendint16(buf, natts);

 /*
  * send the attributes of this tuple
 */

 for (i = 0; i < natts; ++i)
 {
  PrinttupAttrInfo *thisState = myState->myinfo + i;
  Datum  attr = slot->tts_values[i];

  if (slot->tts_isnull[i])
  {
   pq_sendint32(buf, -1);
   continue;
  }

  /*
   * Here we catch undefined bytes in datums that are returned to the
   * client without hitting disk; see comments at the related check in
   * PageAddItem().  This test is most useful for uncompressed,
   * non-external datums, but we're quite likely to see such here when
   * testing new C functions.
 */

  if (thisState->typisvarlena)
   VALGRIND_CHECK_MEM_IS_DEFINED(DatumGetPointer(attr),
            VARSIZE_ANY(attr));

  if (thisState->format == 0)
  {
   /* Text output */
   char    *outputstr;

   outputstr = OutputFunctionCall(&thisState->finfo, attr);
   pq_sendcountedtext(buf, outputstr, strlen(outputstr));
  }
  else
  {
   /* Binary output */
   bytea    *outputbytes;

   outputbytes = SendFunctionCall(&thisState->finfo, attr);
   pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
   pq_sendbytes(buf, VARDATA(outputbytes),
       VARSIZE(outputbytes) - VARHDRSZ);
  }
 }

 pq_endmessage_reuse(buf);

 /* Return to caller's context, and flush row's temporary memory */
 MemoryContextSwitchTo(oldcontext);
 MemoryContextReset(myState->tmpcontext);

 return true;
}

/* ----------------
 *  printtup_shutdown
 * ----------------
 */

static void
printtup_shutdown(DestReceiver *self)
{
 DR_printtup *myState = (DR_printtup *) self;

 if (myState->myinfo)
  pfree(myState->myinfo);
 myState->myinfo = NULL;

 myState->attrinfo = NULL;

 if (myState->buf.data)
  pfree(myState->buf.data);
 myState->buf.data = NULL;

 if (myState->tmpcontext)
  MemoryContextDelete(myState->tmpcontext);
 myState->tmpcontext = NULL;
}

/* ----------------
 *  printtup_destroy
 * ----------------
 */

static void
printtup_destroy(DestReceiver *self)
{
 pfree(self);
}

/* ----------------
 *  printatt
 * ----------------
 */

static void
printatt(unsigned attributeId,
   Form_pg_attribute attributeP,
   char *value)
{
 printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
     attributeId,
     NameStr(attributeP->attname),
     value != NULL ? " = \"" : "",
     value != NULL ? value : "",
     value != NULL ? "\"" : "",
     (unsigned int) (attributeP->atttypid),
     attributeP->attlen,
     attributeP->atttypmod,
     attributeP->attbyval ? 't' : 'f');
}

/* ----------------
 *  debugStartup - prepare to print tuples for an interactive backend
 * ----------------
 */

void
debugStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
{
 int   natts = typeinfo->natts;
 int   i;

 /*
  * show the return type of the tuples
 */

 for (i = 0; i < natts; ++i)
  printatt((unsigned) i + 1, TupleDescAttr(typeinfo, i), NULL);
 printf("\t----\n");
}

/* ----------------
 *  debugtup - print one tuple for an interactive backend
 * ----------------
 */

bool
debugtup(TupleTableSlot *slot, DestReceiver *self)
{
 TupleDesc typeinfo = slot->tts_tupleDescriptor;
 int   natts = typeinfo->natts;
 int   i;
 Datum  attr;
 char    *value;
 bool  isnull;
 Oid   typoutput;
 bool  typisvarlena;

 for (i = 0; i < natts; ++i)
 {
  attr = slot_getattr(slot, i + 1, &isnull);
  if (isnull)
   continue;
  getTypeOutputInfo(TupleDescAttr(typeinfo, i)->atttypid,
        &typoutput, &typisvarlena);

  value = OidOutputFunctionCall(typoutput, attr);

  printatt((unsigned) i + 1, TupleDescAttr(typeinfo, i), value);
 }
 printf("\t----\n");

 return true;
}

Messung V0.5 in Prozent
C=89 H=97 G=93

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.