1/*-------------------------------------------------------------------------
4 * Routines to print out tuples to the destination (both frontend
5 * clients and standalone backends are supported here).
8 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/backend/access/common/printtup.c
14 *-------------------------------------------------------------------------
34/* ----------------------------------------------------------------
35 * printtup / debugtup support
36 * ----------------------------------------------------------------
40 * Private state for a printtup destination object
42 * NOTE: finfo is the lookup info for either typoutput or typsend, whichever
43 * we are using for this column.
47{
/* Per-attribute information */
68 * Initialize: create a DestReceiver for printtup
83 * Send T message automatically if DestRemote, but not if
98 * Set parameters for a DestRemote (or DestRemoteExecute) receiver
118 * Create I/O buffer to be used for all messages. This cannot be inside
119 * tmpcontext, since we want to re-use it across rows.
124 * Create a temporary memory context that we can reset once per row to
125 * recover palloc'd memory. This avoids any problems with leaks inside
126 * datatype output routines, and should be faster than retail pfree's
134 * If we are supposed to emit row descriptions, then send the tuple
135 * descriptor of the tuples.
144 * We could set up the derived attr info at this time, but we postpone it
145 * until the first call of printtup, for 2 reasons:
146 * 1. We don't waste time (compared to the old way) if there are no
147 * tuples at all to output.
148 * 2. Checking in printtup allows us to handle the case that the tuples
149 * change type midway through (although this probably can't happen in
150 * the current executor).
156 * SendRowDescriptionMessage --- send a RowDescription message to the frontend
158 * Notes: the TupleDesc has typically been manufactured by ExecTypeFromTL()
159 * or some similar function; it does not contain a full set of fields.
160 * The targetlist will be NIL when executing a utility function that does
161 * not have a plan. If the targetlist isn't NIL then it is a Query node's
162 * targetlist; it is up to us to ignore resjunk columns in it. The formats[]
163 * array pointer might be NULL (if we are doing Describe on a prepared stmt);
164 * send zeroes for the format codes in that case.
170 int natts = typeinfo->
natts;
174 /* tuple descriptor message type */
176 /* # of attrs in tuples */
180 * Preallocate memory for the entire message to be sent. That allows to
181 * use the significantly faster inline pqformat.h functions and to avoid
184 * Have to overestimate the size of the column-names, to account for
185 * character set overhead.
188 +
sizeof(
Oid)
/* resorigtbl */
190 +
sizeof(
Oid)
/* atttypid */
191 +
sizeof(
int16)
/* attlen */
192 +
sizeof(
int32)
/* attypmod */
193 +
sizeof(
int16)
/* format */
196 for (
i = 0;
i < natts; ++
i)
199 Oid atttypid = att->atttypid;
200 int32 atttypmod = att->atttypmod;
206 * If column is a domain, send the base type and typmod instead.
207 * Lookup before sending any ints, for efficiency.
211 /* Do we have a non-resjunk tlist item? */
214 tlist_item =
lnext(targetlist, tlist_item);
219 resorigtbl = tle->resorigtbl;
220 resorigcol = tle->resorigcol;
221 tlist_item =
lnext(targetlist, tlist_item);
225 /* No info available, so send zeroes */
248 * Get the lookup info that printtup() needs
256 /* get rid of any old data */
262 myState->
nattrs = numAttrs;
269 for (
i = 0;
i < numAttrs;
i++)
292 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
298 * printtup --- send a tuple to the client
300 * Note: if you change this function, see also serializeAnalyzeReceive
301 * in explain.c, which is meant to replicate the computations done here.
311 int natts = typeinfo->
natts;
314 /* Set or update my derived attribute info, if needed */
318 /* Make sure the tuple is fully deconstructed */
321 /* Switch into per-row context so we can recover memory below */
325 * Prepare a DataRow message (note buffer is in per-query context)
332 * send the attributes of this tuple
334 for (
i = 0;
i < natts; ++
i)
346 * Here we catch undefined bytes in datums that are returned to the
347 * client without hitting disk; see comments at the related check in
348 * PageAddItem(). This test is most useful for uncompressed,
349 * non-external datums, but we're quite likely to see such here when
350 * testing new C functions.
356 if (thisState->
format == 0)
378 /* Return to caller's context, and flush row's temporary memory */
428 printf(
"\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
431 value != NULL ?
" = \"" :
"",
433 value != NULL ?
"\"" :
"",
434 (
unsigned int) (attributeP->atttypid),
436 attributeP->atttypmod,
437 attributeP->attbyval ?
't' :
'f');
441 * debugStartup - prepare to print tuples for an interactive backend
447 int natts = typeinfo->
natts;
451 * show the return type of the tuples
453 for (
i = 0;
i < natts; ++
i)
459 * debugtup - print one tuple for an interactive backend
466 int natts = typeinfo->
natts;
474 for (
i = 0;
i < natts; ++
i)
480 &typoutput, &typisvarlena);
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
char * OidOutputFunctionCall(Oid functionId, Datum val)
bytea * SendFunctionCall(FmgrInfo *flinfo, Datum val)
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Assert(PointerIsAligned(start, uint64))
void getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Oid getBaseTypeAndTypmod(Oid typid, int32 *typmod)
void MemoryContextReset(MemoryContext context)
void pfree(void *pointer)
void * palloc0(Size size)
MemoryContext CurrentMemoryContext
void MemoryContextDelete(MemoryContext context)
#define VALGRIND_CHECK_MEM_IS_DEFINED(addr, size)
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
FormData_pg_attribute * Form_pg_attribute
static ListCell * list_head(const List *l)
static ListCell * lnext(const List *l, const ListCell *c)
#define MAX_CONVERSION_GROWTH
static Pointer DatumGetPointer(Datum X)
List * FetchPortalTargetList(Portal portal)
bool debugtup(TupleTableSlot *slot, DestReceiver *self)
static void printatt(unsigned attributeId, Form_pg_attribute attributeP, char *value)
void debugStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
static void printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
static bool printtup(TupleTableSlot *slot, DestReceiver *self)
DestReceiver * printtup_create_DR(CommandDest dest)
static void printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
void SetRemoteDestReceiverParams(DestReceiver *self, Portal portal)
void SendRowDescriptionMessage(StringInfo buf, TupleDesc typeinfo, List *targetlist, int16 *formats)
static void printtup_destroy(DestReceiver *self)
static void printtup_shutdown(DestReceiver *self)
#define PqMsg_RowDescription
void enlargeStringInfo(StringInfo str, int needed)
void initStringInfo(StringInfo str)
PrinttupAttrInfo * myinfo
TupleDesc tts_tupleDescriptor
void(* rStartup)(DestReceiver *self, int operation, TupleDesc typeinfo)
void(* rShutdown)(DestReceiver *self)
bool(* receiveSlot)(TupleTableSlot *slot, DestReceiver *self)
void(* rDestroy)(DestReceiver *self)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
static void slot_getallattrs(TupleTableSlot *slot)
static Size VARSIZE_ANY(const void *PTR)
static Size VARSIZE(const void *PTR)
static char * VARDATA(const void *PTR)