1 /*-------------------------------------------------------------------------
4 * Routines to print out tuples to the destination (binary or non-binary
5 * portals, frontend/interactive backend, etc.).
7 * Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.51 1999/11/22 17:55:52 momjian Exp $
13 *-------------------------------------------------------------------------
19 #include "access/heapam.h"
20 #include "access/printtup.h"
21 #include "catalog/pg_type.h"
22 #include "libpq/pqformat.h"
23 #include "utils/syscache.h"
25 static void printtup_setup(DestReceiver *self, TupleDesc typeinfo);
26 static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
27 static void printtup_cleanup(DestReceiver *self);
29 /* ----------------------------------------------------------------
30 * printtup / debugtup support
31 * ----------------------------------------------------------------
35 * getTypeOutAndElem -- get both typoutput and typelem for a type
37 * We used to fetch these with two separate function calls,
38 * typtoout() and gettypelem(), which each called SearchSysCacheTuple.
39 * This way takes half the time.
43 getTypeOutAndElem(Oid type, Oid *typOutput, Oid *typElem)
47 typeTuple = SearchSysCacheTuple(TYPEOID,
48 ObjectIdGetDatum(type),
51 if (HeapTupleIsValid(typeTuple))
53 Form_pg_type pt = (Form_pg_type) GETSTRUCT(typeTuple);
55 *typOutput = (Oid) pt->typoutput;
56 *typElem = (Oid) pt->typelem;
57 return OidIsValid(*typOutput);
60 elog(ERROR, "getTypeOutAndElem: Cache lookup of type %u failed", type);
62 *typOutput = InvalidOid;
63 *typElem = InvalidOid;
68 * Private state for a printtup destination object
72 { /* Per-attribute information */
73 Oid typoutput; /* Oid for the attribute's type output fn */
74 Oid typelem; /* typelem value to pass to the output fn */
75 FmgrInfo finfo; /* Precomputed call info for typoutput */
80 DestReceiver pub; /* publicly-known function pointers */
81 TupleDesc attrinfo; /* The attr info we are set up for */
83 PrinttupAttrInfo *myinfo; /* Cached info about each attr */
87 * Initialize: create a DestReceiver for printtup
93 DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup));
95 self->pub.receiveTuple = printtup;
96 self->pub.setup = printtup_setup;
97 self->pub.cleanup = printtup_cleanup;
99 self->attrinfo = NULL;
103 return (DestReceiver *) self;
107 printtup_setup(DestReceiver *self, TupleDesc typeinfo)
110 * We could set up the derived attr info at this time, but we postpone it
111 * until the first call of printtup, for 3 reasons:
112 * 1. We don't waste time (compared to the old way) if there are no
113 * tuples at all to output.
114 * 2. Checking in printtup allows us to handle the case that the tuples
115 * change type midway through (although this probably can't happen in
116 * the current executor).
117 * 3. Right now, ExecutorRun passes a NULL for typeinfo anyway :-(
123 printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
128 pfree(myState->myinfo); /* get rid of any old data */
129 myState->myinfo = NULL;
130 myState->attrinfo = typeinfo;
131 myState->nattrs = numAttrs;
134 myState->myinfo = (PrinttupAttrInfo *)
135 palloc(numAttrs * sizeof(PrinttupAttrInfo));
136 for (i = 0; i < numAttrs; i++)
138 PrinttupAttrInfo *thisState = myState->myinfo + i;
140 if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
141 &thisState->typoutput, &thisState->typelem))
142 fmgr_info(thisState->typoutput, &thisState->finfo);
151 printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
153 DR_printtup *myState = (DR_printtup *) self;
162 /* Set or update my derived attribute info, if needed */
163 if (myState->attrinfo != typeinfo ||
164 myState->nattrs != tuple->t_data->t_natts)
165 printtup_prepare_info(myState, typeinfo, tuple->t_data->t_natts);
168 * tell the frontend to expect new tuple data (in ASCII style)
171 pq_beginmessage(&buf);
172 pq_sendbyte(&buf, 'D');
175 * send a bitmap of which attributes are not null
180 for (i = 0; i < tuple->t_data->t_natts; ++i)
182 if (!heap_attisnull(tuple, i + 1))
183 j |= k; /* set bit if not null */
185 if (k == 0) /* end of byte? */
187 pq_sendint(&buf, j, 1);
192 if (k != (1 << 7)) /* flush last partial byte */
193 pq_sendint(&buf, j, 1);
196 * send the attributes of this tuple
199 for (i = 0; i < tuple->t_data->t_natts; ++i)
201 PrinttupAttrInfo *thisState = myState->myinfo + i;
203 attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
206 if (OidIsValid(thisState->typoutput))
208 outputstr = (char *) (*fmgr_faddr(&thisState->finfo))
209 (attr, thisState->typelem, typeinfo->attrs[i]->atttypmod);
210 pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
215 outputstr = "<unprintable>";
216 pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
228 printtup_cleanup(DestReceiver *self)
230 DR_printtup *myState = (DR_printtup *) self;
233 pfree(myState->myinfo);
242 printatt(unsigned attributeId,
243 Form_pg_attribute attributeP,
246 printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
248 NameStr(attributeP->attname),
249 value != NULL ? " = \"" : "",
250 value != NULL ? value : "",
251 value != NULL ? "\"" : "",
252 (unsigned int) (attributeP->atttypid),
254 attributeP->atttypmod,
255 attributeP->attbyval ? 't' : 'f');
263 showatts(char *name, TupleDesc tupleDesc)
266 int natts = tupleDesc->natts;
267 Form_pg_attribute *attinfo = tupleDesc->attrs;
270 for (i = 0; i < natts; ++i)
271 printatt((unsigned) i + 1, attinfo[i], (char *) NULL);
280 debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
289 for (i = 0; i < tuple->t_data->t_natts; ++i)
291 attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
294 if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
295 &typoutput, &typelem))
297 value = fmgr(typoutput, attr, typelem,
298 typeinfo->attrs[i]->atttypmod);
299 printatt((unsigned) i + 1, typeinfo->attrs[i], value);
308 * We use a different data prefix, e.g. 'B' instead of 'D' to
309 * indicate a tuple in internal (binary) form.
311 * This is same as printtup, except we don't use the typout func,
312 * and therefore have no need for persistent state.
316 printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
326 * tell the frontend to expect new tuple data (in binary style)
329 pq_beginmessage(&buf);
330 pq_sendbyte(&buf, 'B');
333 * send a bitmap of which attributes are not null
338 for (i = 0; i < tuple->t_data->t_natts; ++i)
340 if (!heap_attisnull(tuple, i + 1))
341 j |= k; /* set bit if not null */
343 if (k == 0) /* end of byte? */
345 pq_sendint(&buf, j, 1);
350 if (k != (1 << 7)) /* flush last partial byte */
351 pq_sendint(&buf, j, 1);
354 * send the attributes of this tuple
358 fprintf(stderr, "sending tuple with %d atts\n", tuple->t_data->t_natts);
360 for (i = 0; i < tuple->t_data->t_natts; ++i)
362 int32 len = typeinfo->attrs[i]->attlen;
364 attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
367 /* # of bytes, and opaque data */
370 /* variable length, assume a varlena structure */
371 len = VARSIZE(attr) - VARHDRSZ;
373 pq_sendint(&buf, len, VARHDRSZ);
374 pq_sendbytes(&buf, VARDATA(attr), len);
378 char *d = VARDATA(attr);
380 fprintf(stderr, "length %d data %x%x%x%x\n",
381 len, *d, *(d + 1), *(d + 2), *(d + 3));
388 if (typeinfo->attrs[i]->attbyval)
394 pq_sendint(&buf, len, sizeof(int32));
398 i8 = DatumGetChar(attr);
399 pq_sendbytes(&buf, (char *) &i8, len);
402 i16 = DatumGetInt16(attr);
403 pq_sendbytes(&buf, (char *) &i16, len);
406 i32 = DatumGetInt32(attr);
407 pq_sendbytes(&buf, (char *) &i32, len);
411 fprintf(stderr, "byval length %d data %d\n", len, attr);
416 pq_sendint(&buf, len, sizeof(int32));
417 pq_sendbytes(&buf, DatumGetPointer(attr), len);
419 fprintf(stderr, "byref length %d data %x\n", len,
420 DatumGetPointer(attr));