1 /*-------------------------------------------------------------------------
4 * Routines to print out tuples to the destination (both frontend
5 * clients and interactive backends are supported here).
8 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
12 * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.68 2003/05/05 00:44:55 tgl Exp $
14 *-------------------------------------------------------------------------
18 #include "access/heapam.h"
19 #include "access/printtup.h"
20 #include "libpq/libpq.h"
21 #include "libpq/pqformat.h"
22 #include "utils/lsyscache.h"
25 static void printtup_setup(DestReceiver *self, int operation,
26 const char *portalName, TupleDesc typeinfo);
27 static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
28 static void printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
29 static void printtup_cleanup(DestReceiver *self);
31 /* ----------------------------------------------------------------
32 * printtup / debugtup support
33 * ----------------------------------------------------------------
37 * Private state for a printtup destination object
41 { /* Per-attribute information */
42 Oid typoutput; /* Oid for the attribute's type output fn */
43 Oid typelem; /* typelem value to pass to the output fn */
44 bool typisvarlena; /* is it varlena (ie possibly toastable)? */
45 FmgrInfo finfo; /* Precomputed call info for typoutput */
50 DestReceiver pub; /* publicly-known function pointers */
51 bool sendDescrip; /* send RowDescription at startup? */
52 TupleDesc attrinfo; /* The attr info we are set up for */
54 PrinttupAttrInfo *myinfo; /* Cached info about each attr */
58 * Initialize: create a DestReceiver for printtup
62 printtup_create_DR(bool isBinary, bool sendDescrip)
64 DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup));
66 self->pub.receiveTuple = isBinary ? printtup_internal : printtup;
67 self->pub.setup = printtup_setup;
68 self->pub.cleanup = printtup_cleanup;
70 self->sendDescrip = sendDescrip;
72 self->attrinfo = NULL;
76 return (DestReceiver *) self;
80 printtup_setup(DestReceiver *self, int operation,
81 const char *portalName, TupleDesc typeinfo)
83 DR_printtup *myState = (DR_printtup *) self;
85 if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
88 * Send portal name to frontend (obsolete cruft, gone in proto 3.0)
90 * If portal name not specified, use "blank" portal.
92 if (portalName == NULL)
95 pq_puttextmessage('P', portalName);
99 * If this is a retrieve, and we are supposed to emit row descriptions,
100 * then we send back the tuple descriptor of the tuples.
102 if (operation == CMD_SELECT && myState->sendDescrip)
103 SendRowDescriptionMessage(typeinfo);
106 * We could set up the derived attr info at this time, but we postpone it
107 * until the first call of printtup, for 2 reasons:
108 * 1. We don't waste time (compared to the old way) if there are no
109 * tuples at all to output.
110 * 2. Checking in printtup allows us to handle the case that the tuples
111 * change type midway through (although this probably can't happen in
112 * the current executor).
118 * SendRowDescriptionMessage --- send a RowDescription message to the frontend
121 SendRowDescriptionMessage(TupleDesc typeinfo)
123 Form_pg_attribute *attrs = typeinfo->attrs;
124 int natts = typeinfo->natts;
125 int proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
129 pq_beginmessage(&buf, 'T'); /* tuple descriptor message type */
130 pq_sendint(&buf, natts, 2); /* # of attrs in tuples */
132 for (i = 0; i < natts; ++i)
134 pq_sendstring(&buf, NameStr(attrs[i]->attname));
135 /* column ID info appears in protocol 3.0 and up */
138 /* XXX not yet implemented, send zeroes */
139 pq_sendint(&buf, 0, 4);
140 pq_sendint(&buf, 0, 2);
142 pq_sendint(&buf, (int) attrs[i]->atttypid,
143 sizeof(attrs[i]->atttypid));
144 pq_sendint(&buf, attrs[i]->attlen,
145 sizeof(attrs[i]->attlen));
146 /* typmod appears in protocol 2.0 and up */
148 pq_sendint(&buf, attrs[i]->atttypmod,
149 sizeof(attrs[i]->atttypmod));
155 printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
160 pfree(myState->myinfo); /* get rid of any old data */
161 myState->myinfo = NULL;
162 myState->attrinfo = typeinfo;
163 myState->nattrs = numAttrs;
166 myState->myinfo = (PrinttupAttrInfo *)
167 palloc(numAttrs * sizeof(PrinttupAttrInfo));
168 for (i = 0; i < numAttrs; i++)
170 PrinttupAttrInfo *thisState = myState->myinfo + i;
172 if (getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
173 &thisState->typoutput, &thisState->typelem,
174 &thisState->typisvarlena))
175 fmgr_info(thisState->typoutput, &thisState->finfo);
184 printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
186 DR_printtup *myState = (DR_printtup *) self;
188 int natts = tuple->t_data->t_natts;
193 /* Set or update my derived attribute info, if needed */
194 if (myState->attrinfo != typeinfo || myState->nattrs != natts)
195 printtup_prepare_info(myState, typeinfo, natts);
198 * tell the frontend to expect new tuple data (in ASCII style)
200 pq_beginmessage(&buf, 'D');
203 * send a bitmap of which attributes are not null
207 for (i = 0; i < natts; ++i)
209 if (!heap_attisnull(tuple, i + 1))
210 j |= k; /* set bit if not null */
212 if (k == 0) /* end of byte? */
214 pq_sendint(&buf, j, 1);
219 if (k != (1 << 7)) /* flush last partial byte */
220 pq_sendint(&buf, j, 1);
223 * send the attributes of this tuple
225 for (i = 0; i < natts; ++i)
227 PrinttupAttrInfo *thisState = myState->myinfo + i;
233 origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
236 if (OidIsValid(thisState->typoutput))
239 * If we have a toasted datum, forcibly detoast it here to
240 * avoid memory leakage inside the type's output routine.
242 if (thisState->typisvarlena)
243 attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
247 outputstr = DatumGetCString(FunctionCall3(&thisState->finfo,
249 ObjectIdGetDatum(thisState->typelem),
250 Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
252 pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
254 /* Clean up detoasted copy, if any */
255 if (attr != origattr)
256 pfree(DatumGetPointer(attr));
261 outputstr = "<unprintable>";
262 pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
274 printtup_cleanup(DestReceiver *self)
276 DR_printtup *myState = (DR_printtup *) self;
279 pfree(myState->myinfo);
288 printatt(unsigned attributeId,
289 Form_pg_attribute attributeP,
292 printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
294 NameStr(attributeP->attname),
295 value != NULL ? " = \"" : "",
296 value != NULL ? value : "",
297 value != NULL ? "\"" : "",
298 (unsigned int) (attributeP->atttypid),
300 attributeP->atttypmod,
301 attributeP->attbyval ? 't' : 'f');
309 showatts(const char *name, TupleDesc tupleDesc)
311 int natts = tupleDesc->natts;
312 Form_pg_attribute *attinfo = tupleDesc->attrs;
316 for (i = 0; i < natts; ++i)
317 printatt((unsigned) i + 1, attinfo[i], (char *) NULL);
322 * debugSetup - prepare to print tuples for an interactive backend
326 debugSetup(DestReceiver *self, int operation,
327 const char *portalName, TupleDesc typeinfo)
330 * show the return type of the tuples
332 if (portalName == NULL)
333 portalName = "blank";
335 showatts(portalName, typeinfo);
339 * debugtup - print one tuple for an interactive backend
343 debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
345 int natts = tuple->t_data->t_natts;
355 for (i = 0; i < natts; ++i)
357 origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
360 if (getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
361 &typoutput, &typelem, &typisvarlena))
364 * If we have a toasted datum, forcibly detoast it here to
365 * avoid memory leakage inside the type's output routine.
368 attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
372 value = DatumGetCString(OidFunctionCall3(typoutput,
374 ObjectIdGetDatum(typelem),
375 Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
377 printatt((unsigned) i + 1, typeinfo->attrs[i], value);
379 /* Clean up detoasted copy, if any */
380 if (attr != origattr)
381 pfree(DatumGetPointer(attr));
390 * We use a different data prefix, e.g. 'B' instead of 'D' to
391 * indicate a tuple in internal (binary) form.
393 * This is largely same as printtup, except we don't use the typout func.
397 printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
399 DR_printtup *myState = (DR_printtup *) self;
401 int natts = tuple->t_data->t_natts;
406 /* Set or update my derived attribute info, if needed */
407 if (myState->attrinfo != typeinfo || myState->nattrs != natts)
408 printtup_prepare_info(myState, typeinfo, natts);
411 * tell the frontend to expect new tuple data (in binary style)
413 pq_beginmessage(&buf, 'B');
416 * send a bitmap of which attributes are not null
420 for (i = 0; i < natts; ++i)
422 if (!heap_attisnull(tuple, i + 1))
423 j |= k; /* set bit if not null */
425 if (k == 0) /* end of byte? */
427 pq_sendint(&buf, j, 1);
432 if (k != (1 << 7)) /* flush last partial byte */
433 pq_sendint(&buf, j, 1);
436 * send the attributes of this tuple
439 fprintf(stderr, "sending tuple with %d atts\n", natts);
442 for (i = 0; i < natts; ++i)
444 PrinttupAttrInfo *thisState = myState->myinfo + i;
450 origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
453 /* send # of bytes, and opaque data */
454 if (thisState->typisvarlena)
457 * If we have a toasted datum, must detoast before sending.
459 attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
461 len = VARSIZE(attr) - VARHDRSZ;
463 pq_sendint(&buf, len, VARHDRSZ);
464 pq_sendbytes(&buf, VARDATA(attr), len);
468 char *d = VARDATA(attr);
470 fprintf(stderr, "length %d data %x %x %x %x\n",
471 len, *d, *(d + 1), *(d + 2), *(d + 3));
475 /* Clean up detoasted copy, if any */
476 if (attr != origattr)
477 pfree(DatumGetPointer(attr));
481 /* fixed size or cstring */
483 len = typeinfo->attrs[i]->attlen;
487 Assert(len == -2 && !typeinfo->attrs[i]->attbyval);
488 len = strlen(DatumGetCString(attr)) + 1;
490 pq_sendint(&buf, len, sizeof(int32));
491 if (typeinfo->attrs[i]->attbyval)
496 * We need this horsing around because we don't know how
497 * shorter data values are aligned within a Datum.
499 store_att_byval(&datumBuf, attr, len);
500 pq_sendbytes(&buf, (char *) &datumBuf, len);
502 fprintf(stderr, "byval length %d data %ld\n", len,
508 pq_sendbytes(&buf, DatumGetPointer(attr), len);
510 fprintf(stderr, "byref length %d data %p\n", len,
511 DatumGetPointer(attr));