]> granicus.if.org Git - postgresql/blob - src/backend/access/common/printtup.c
Add a bunch of pseudo-types to replace the behavior formerly associated
[postgresql] / src / backend / access / common / printtup.c
1 /*-------------------------------------------------------------------------
2  *
3  * printtup.c
4  *        Routines to print out tuples to the destination (both frontend
5  *        clients and interactive backends are supported here).
6  *
7  *
8  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  * IDENTIFICATION
12  *        $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.63 2002/08/22 00:01:41 tgl Exp $
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17
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"
23
24
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);
30
31 /* ----------------------------------------------------------------
32  *              printtup / debugtup support
33  * ----------------------------------------------------------------
34  */
35
36 /* ----------------
37  *              Private state for a printtup destination object
38  * ----------------
39  */
40 typedef struct
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 */
46 } PrinttupAttrInfo;
47
48 typedef struct
49 {
50         DestReceiver pub;                       /* publicly-known function pointers */
51         TupleDesc       attrinfo;               /* The attr info we are set up for */
52         int                     nattrs;
53         PrinttupAttrInfo *myinfo;       /* Cached info about each attr */
54 } DR_printtup;
55
56 /* ----------------
57  *              Initialize: create a DestReceiver for printtup
58  * ----------------
59  */
60 DestReceiver *
61 printtup_create_DR(bool isBinary)
62 {
63         DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup));
64
65         self->pub.receiveTuple = isBinary ? printtup_internal : printtup;
66         self->pub.setup = printtup_setup;
67         self->pub.cleanup = printtup_cleanup;
68
69         self->attrinfo = NULL;
70         self->nattrs = 0;
71         self->myinfo = NULL;
72
73         return (DestReceiver *) self;
74 }
75
76 static void
77 printtup_setup(DestReceiver *self, int operation,
78                            const char *portalName, TupleDesc typeinfo)
79 {
80         /*
81          * Send portal name to frontend.
82          *
83          * If portal name not specified, use "blank" portal.
84          */
85         if (portalName == NULL)
86                 portalName = "blank";
87
88         pq_puttextmessage('P', portalName);
89
90         /*
91          * if this is a retrieve, then we send back the tuple
92          * descriptor of the tuples.
93          */
94         if (operation == CMD_SELECT)
95         {
96                 Form_pg_attribute *attrs = typeinfo->attrs;
97                 int                     natts = typeinfo->natts;
98                 int                     i;
99                 StringInfoData buf;
100
101                 pq_beginmessage(&buf);
102                 pq_sendbyte(&buf, 'T'); /* tuple descriptor message type */
103                 pq_sendint(&buf, natts, 2);     /* # of attrs in tuples */
104
105                 for (i = 0; i < natts; ++i)
106                 {
107                         pq_sendstring(&buf, NameStr(attrs[i]->attname));
108                         pq_sendint(&buf, (int) attrs[i]->atttypid,
109                                            sizeof(attrs[i]->atttypid));
110                         pq_sendint(&buf, attrs[i]->attlen,
111                                            sizeof(attrs[i]->attlen));
112                         if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
113                                 pq_sendint(&buf, attrs[i]->atttypmod,
114                                                    sizeof(attrs[i]->atttypmod));
115                 }
116                 pq_endmessage(&buf);
117         }
118
119         /* ----------------
120          * We could set up the derived attr info at this time, but we postpone it
121          * until the first call of printtup, for 2 reasons:
122          * 1. We don't waste time (compared to the old way) if there are no
123          *        tuples at all to output.
124          * 2. Checking in printtup allows us to handle the case that the tuples
125          *        change type midway through (although this probably can't happen in
126          *        the current executor).
127          * ----------------
128          */
129 }
130
131 static void
132 printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
133 {
134         int                     i;
135
136         if (myState->myinfo)
137                 pfree(myState->myinfo); /* get rid of any old data */
138         myState->myinfo = NULL;
139         myState->attrinfo = typeinfo;
140         myState->nattrs = numAttrs;
141         if (numAttrs <= 0)
142                 return;
143         myState->myinfo = (PrinttupAttrInfo *)
144                 palloc(numAttrs * sizeof(PrinttupAttrInfo));
145         for (i = 0; i < numAttrs; i++)
146         {
147                 PrinttupAttrInfo *thisState = myState->myinfo + i;
148
149                 if (getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
150                                                           &thisState->typoutput, &thisState->typelem,
151                                                           &thisState->typisvarlena))
152                         fmgr_info(thisState->typoutput, &thisState->finfo);
153         }
154 }
155
156 /* ----------------
157  *              printtup
158  * ----------------
159  */
160 static void
161 printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
162 {
163         DR_printtup *myState = (DR_printtup *) self;
164         StringInfoData buf;
165         int                     natts = tuple->t_data->t_natts;
166         int                     i,
167                                 j,
168                                 k;
169
170         /* Set or update my derived attribute info, if needed */
171         if (myState->attrinfo != typeinfo || myState->nattrs != natts)
172                 printtup_prepare_info(myState, typeinfo, natts);
173
174         /*
175          * tell the frontend to expect new tuple data (in ASCII style)
176          */
177         pq_beginmessage(&buf);
178         pq_sendbyte(&buf, 'D');
179
180         /*
181          * send a bitmap of which attributes are not null
182          */
183         j = 0;
184         k = 1 << 7;
185         for (i = 0; i < natts; ++i)
186         {
187                 if (!heap_attisnull(tuple, i + 1))
188                         j |= k;                         /* set bit if not null */
189                 k >>= 1;
190                 if (k == 0)                             /* end of byte? */
191                 {
192                         pq_sendint(&buf, j, 1);
193                         j = 0;
194                         k = 1 << 7;
195                 }
196         }
197         if (k != (1 << 7))                      /* flush last partial byte */
198                 pq_sendint(&buf, j, 1);
199
200         /*
201          * send the attributes of this tuple
202          */
203         for (i = 0; i < natts; ++i)
204         {
205                 PrinttupAttrInfo *thisState = myState->myinfo + i;
206                 Datum           origattr,
207                                         attr;
208                 bool            isnull;
209                 char       *outputstr;
210
211                 origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
212                 if (isnull)
213                         continue;
214                 if (OidIsValid(thisState->typoutput))
215                 {
216                         /*
217                          * If we have a toasted datum, forcibly detoast it here to
218                          * avoid memory leakage inside the type's output routine.
219                          */
220                         if (thisState->typisvarlena)
221                                 attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
222                         else
223                                 attr = origattr;
224
225                         outputstr = DatumGetCString(FunctionCall3(&thisState->finfo,
226                                                                                                           attr,
227                                                                         ObjectIdGetDatum(thisState->typelem),
228                                                   Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
229
230                         pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
231
232                         /* Clean up detoasted copy, if any */
233                         if (attr != origattr)
234                                 pfree(DatumGetPointer(attr));
235                         pfree(outputstr);
236                 }
237                 else
238                 {
239                         outputstr = "<unprintable>";
240                         pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
241                 }
242         }
243
244         pq_endmessage(&buf);
245 }
246
247 /* ----------------
248  *              printtup_cleanup
249  * ----------------
250  */
251 static void
252 printtup_cleanup(DestReceiver *self)
253 {
254         DR_printtup *myState = (DR_printtup *) self;
255
256         if (myState->myinfo)
257                 pfree(myState->myinfo);
258         pfree(myState);
259 }
260
261 /* ----------------
262  *              printatt
263  * ----------------
264  */
265 static void
266 printatt(unsigned attributeId,
267                  Form_pg_attribute attributeP,
268                  char *value)
269 {
270         printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
271                    attributeId,
272                    NameStr(attributeP->attname),
273                    value != NULL ? " = \"" : "",
274                    value != NULL ? value : "",
275                    value != NULL ? "\"" : "",
276                    (unsigned int) (attributeP->atttypid),
277                    attributeP->attlen,
278                    attributeP->atttypmod,
279                    attributeP->attbyval ? 't' : 'f');
280 }
281
282 /* ----------------
283  *              showatts
284  * ----------------
285  */
286 static void
287 showatts(const char *name, TupleDesc tupleDesc)
288 {
289         int                     natts = tupleDesc->natts;
290         Form_pg_attribute *attinfo = tupleDesc->attrs;
291         int                     i;
292
293         puts(name);
294         for (i = 0; i < natts; ++i)
295                 printatt((unsigned) i + 1, attinfo[i], (char *) NULL);
296         printf("\t----\n");
297 }
298
299 /* ----------------
300  *              debugSetup - prepare to print tuples for an interactive backend
301  * ----------------
302  */
303 void
304 debugSetup(DestReceiver *self, int operation,
305                    const char *portalName, TupleDesc typeinfo)
306 {
307         /*
308          * show the return type of the tuples
309          */
310         if (portalName == NULL)
311                 portalName = "blank";
312
313         showatts(portalName, typeinfo);
314 }
315
316 /* ----------------
317  *              debugtup - print one tuple for an interactive backend
318  * ----------------
319  */
320 void
321 debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
322 {
323         int                     natts = tuple->t_data->t_natts;
324         int                     i;
325         Datum           origattr,
326                                 attr;
327         char       *value;
328         bool            isnull;
329         Oid                     typoutput,
330                                 typelem;
331         bool            typisvarlena;
332
333         for (i = 0; i < natts; ++i)
334         {
335                 origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
336                 if (isnull)
337                         continue;
338                 if (getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
339                                                           &typoutput, &typelem, &typisvarlena))
340                 {
341                         /*
342                          * If we have a toasted datum, forcibly detoast it here to
343                          * avoid memory leakage inside the type's output routine.
344                          */
345                         if (typisvarlena)
346                                 attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
347                         else
348                                 attr = origattr;
349
350                         value = DatumGetCString(OidFunctionCall3(typoutput,
351                                                                                                          attr,
352                                                                                            ObjectIdGetDatum(typelem),
353                                                   Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
354
355                         printatt((unsigned) i + 1, typeinfo->attrs[i], value);
356
357                         /* Clean up detoasted copy, if any */
358                         if (attr != origattr)
359                                 pfree(DatumGetPointer(attr));
360                         pfree(value);
361                 }
362         }
363         printf("\t----\n");
364 }
365
366 /* ----------------
367  *              printtup_internal
368  *              We use a different data prefix, e.g. 'B' instead of 'D' to
369  *              indicate a tuple in internal (binary) form.
370  *
371  *              This is largely same as printtup, except we don't use the typout func.
372  * ----------------
373  */
374 static void
375 printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
376 {
377         DR_printtup *myState = (DR_printtup *) self;
378         StringInfoData buf;
379         int                     natts = tuple->t_data->t_natts;
380         int                     i,
381                                 j,
382                                 k;
383
384         /* Set or update my derived attribute info, if needed */
385         if (myState->attrinfo != typeinfo || myState->nattrs != natts)
386                 printtup_prepare_info(myState, typeinfo, natts);
387
388         /*
389          * tell the frontend to expect new tuple data (in binary style)
390          */
391         pq_beginmessage(&buf);
392         pq_sendbyte(&buf, 'B');
393
394         /*
395          * send a bitmap of which attributes are not null
396          */
397         j = 0;
398         k = 1 << 7;
399         for (i = 0; i < natts; ++i)
400         {
401                 if (!heap_attisnull(tuple, i + 1))
402                         j |= k;                         /* set bit if not null */
403                 k >>= 1;
404                 if (k == 0)                             /* end of byte? */
405                 {
406                         pq_sendint(&buf, j, 1);
407                         j = 0;
408                         k = 1 << 7;
409                 }
410         }
411         if (k != (1 << 7))                      /* flush last partial byte */
412                 pq_sendint(&buf, j, 1);
413
414         /*
415          * send the attributes of this tuple
416          */
417 #ifdef IPORTAL_DEBUG
418         fprintf(stderr, "sending tuple with %d atts\n", natts);
419 #endif
420
421         for (i = 0; i < natts; ++i)
422         {
423                 PrinttupAttrInfo *thisState = myState->myinfo + i;
424                 Datum           origattr,
425                                         attr;
426                 bool            isnull;
427                 int32           len;
428
429                 origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
430                 if (isnull)
431                         continue;
432                 /* send # of bytes, and opaque data */
433                 if (thisState->typisvarlena)
434                 {
435                         /*
436                          * If we have a toasted datum, must detoast before sending.
437                          */
438                         attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
439
440                         len = VARSIZE(attr) - VARHDRSZ;
441
442                         pq_sendint(&buf, len, VARHDRSZ);
443                         pq_sendbytes(&buf, VARDATA(attr), len);
444
445 #ifdef IPORTAL_DEBUG
446                         {
447                                 char       *d = VARDATA(attr);
448
449                                 fprintf(stderr, "length %d data %x %x %x %x\n",
450                                                 len, *d, *(d + 1), *(d + 2), *(d + 3));
451                         }
452 #endif
453
454                         /* Clean up detoasted copy, if any */
455                         if (attr != origattr)
456                                 pfree(DatumGetPointer(attr));
457                 }
458                 else
459                 {
460                         /* fixed size */
461                         attr = origattr;
462                         len = typeinfo->attrs[i]->attlen;
463                         pq_sendint(&buf, len, sizeof(int32));
464                         if (typeinfo->attrs[i]->attbyval)
465                         {
466                                 Datum           datumBuf;
467
468                                 /*
469                                  * We need this horsing around because we don't know how
470                                  * shorter data values are aligned within a Datum.
471                                  */
472                                 store_att_byval(&datumBuf, attr, len);
473                                 pq_sendbytes(&buf, (char *) &datumBuf, len);
474 #ifdef IPORTAL_DEBUG
475                                 fprintf(stderr, "byval length %d data %ld\n", len,
476                                                 (long) attr);
477 #endif
478                         }
479                         else
480                         {
481                                 pq_sendbytes(&buf, DatumGetPointer(attr), len);
482 #ifdef IPORTAL_DEBUG
483                                 fprintf(stderr, "byref length %d data %p\n", len,
484                                                 DatumGetPointer(attr));
485 #endif
486                         }
487                 }
488         }
489
490         pq_endmessage(&buf);
491 }