]> granicus.if.org Git - postgresql/blob - src/backend/access/common/printtup.c
New NameStr macro to convert Name to Str. No need for var.data anymore.
[postgresql] / src / backend / access / common / printtup.c
1 /*-------------------------------------------------------------------------
2  *
3  * printtup.c
4  *        Routines to print out tuples to the destination (binary or non-binary
5  *        portals, frontend/interactive backend, etc.).
6  *
7  * Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.50 1999/11/07 23:07:46 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15
16
17 #include "postgres.h"
18
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"
24
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);
28
29 /* ----------------------------------------------------------------
30  *              printtup / debugtup support
31  * ----------------------------------------------------------------
32  */
33
34 /* ----------------
35  *              getTypeOutAndElem -- get both typoutput and typelem for a type
36  *
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.
40  * ----------------
41  */
42 int
43 getTypeOutAndElem(Oid type, Oid *typOutput, Oid *typElem)
44 {
45         HeapTuple       typeTuple;
46
47         typeTuple = SearchSysCacheTuple(TYPOID,
48                                                                         ObjectIdGetDatum(type),
49                                                                         0, 0, 0);
50
51         if (HeapTupleIsValid(typeTuple))
52         {
53                 Form_pg_type pt = (Form_pg_type) GETSTRUCT(typeTuple);
54
55                 *typOutput = (Oid) pt->typoutput;
56                 *typElem = (Oid) pt->typelem;
57                 return OidIsValid(*typOutput);
58         }
59
60         elog(ERROR, "getTypeOutAndElem: Cache lookup of type %u failed", type);
61
62         *typOutput = InvalidOid;
63         *typElem = InvalidOid;
64         return 0;
65 }
66
67 /* ----------------
68  *              Private state for a printtup destination object
69  * ----------------
70  */
71 typedef struct
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 */
76 } PrinttupAttrInfo;
77
78 typedef struct
79 {
80         DestReceiver pub;                       /* publicly-known function pointers */
81         TupleDesc       attrinfo;               /* The attr info we are set up for */
82         int                     nattrs;
83         PrinttupAttrInfo *myinfo;       /* Cached info about each attr */
84 } DR_printtup;
85
86 /* ----------------
87  *              Initialize: create a DestReceiver for printtup
88  * ----------------
89  */
90 DestReceiver *
91 printtup_create_DR()
92 {
93         DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup));
94
95         self->pub.receiveTuple = printtup;
96         self->pub.setup = printtup_setup;
97         self->pub.cleanup = printtup_cleanup;
98
99         self->attrinfo = NULL;
100         self->nattrs = 0;
101         self->myinfo = NULL;
102
103         return (DestReceiver *) self;
104 }
105
106 static void
107 printtup_setup(DestReceiver *self, TupleDesc typeinfo)
108 {
109         /* ----------------
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 :-(
118          * ----------------
119          */
120 }
121
122 static void
123 printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
124 {
125         int                     i;
126
127         if (myState->myinfo)
128                 pfree(myState->myinfo); /* get rid of any old data */
129         myState->myinfo = NULL;
130         myState->attrinfo = typeinfo;
131         myState->nattrs = numAttrs;
132         if (numAttrs <= 0)
133                 return;
134         myState->myinfo = (PrinttupAttrInfo *)
135                 palloc(numAttrs * sizeof(PrinttupAttrInfo));
136         for (i = 0; i < numAttrs; i++)
137         {
138                 PrinttupAttrInfo *thisState = myState->myinfo + i;
139
140                 if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
141                                                           &thisState->typoutput, &thisState->typelem))
142                         fmgr_info(thisState->typoutput, &thisState->finfo);
143         }
144 }
145
146 /* ----------------
147  *              printtup
148  * ----------------
149  */
150 static void
151 printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
152 {
153         DR_printtup *myState = (DR_printtup *) self;
154         StringInfoData buf;
155         int                     i,
156                                 j,
157                                 k;
158         char       *outputstr;
159         Datum           attr;
160         bool            isnull;
161
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);
166
167         /* ----------------
168          *      tell the frontend to expect new tuple data (in ASCII style)
169          * ----------------
170          */
171         pq_beginmessage(&buf);
172         pq_sendbyte(&buf, 'D');
173
174         /* ----------------
175          *      send a bitmap of which attributes are not null
176          * ----------------
177          */
178         j = 0;
179         k = 1 << 7;
180         for (i = 0; i < tuple->t_data->t_natts; ++i)
181         {
182                 if (!heap_attisnull(tuple, i + 1))
183                         j |= k;                         /* set bit if not null */
184                 k >>= 1;
185                 if (k == 0)                             /* end of byte? */
186                 {
187                         pq_sendint(&buf, j, 1);
188                         j = 0;
189                         k = 1 << 7;
190                 }
191         }
192         if (k != (1 << 7))                      /* flush last partial byte */
193                 pq_sendint(&buf, j, 1);
194
195         /* ----------------
196          *      send the attributes of this tuple
197          * ----------------
198          */
199         for (i = 0; i < tuple->t_data->t_natts; ++i)
200         {
201                 PrinttupAttrInfo *thisState = myState->myinfo + i;
202
203                 attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
204                 if (isnull)
205                         continue;
206                 if (OidIsValid(thisState->typoutput))
207                 {
208                         outputstr = (char *) (*fmgr_faddr(&thisState->finfo))
209                                 (attr, thisState->typelem, typeinfo->attrs[i]->atttypmod);
210                         pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
211                         pfree(outputstr);
212                 }
213                 else
214                 {
215                         outputstr = "<unprintable>";
216                         pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
217                 }
218         }
219
220         pq_endmessage(&buf);
221 }
222
223 /* ----------------
224  *              printtup_cleanup
225  * ----------------
226  */
227 static void
228 printtup_cleanup(DestReceiver *self)
229 {
230         DR_printtup *myState = (DR_printtup *) self;
231
232         if (myState->myinfo)
233                 pfree(myState->myinfo);
234         pfree(myState);
235 }
236
237 /* ----------------
238  *              printatt
239  * ----------------
240  */
241 static void
242 printatt(unsigned attributeId,
243                  Form_pg_attribute attributeP,
244                  char *value)
245 {
246         printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
247                    attributeId,
248                    NameStr(attributeP->attname),
249                    value != NULL ? " = \"" : "",
250                    value != NULL ? value : "",
251                    value != NULL ? "\"" : "",
252                    (unsigned int) (attributeP->atttypid),
253                    attributeP->attlen,
254                    attributeP->atttypmod,
255                    attributeP->attbyval ? 't' : 'f');
256 }
257
258 /* ----------------
259  *              showatts
260  * ----------------
261  */
262 void
263 showatts(char *name, TupleDesc tupleDesc)
264 {
265         int                     i;
266         int                     natts = tupleDesc->natts;
267         Form_pg_attribute *attinfo = tupleDesc->attrs;
268
269         puts(name);
270         for (i = 0; i < natts; ++i)
271                 printatt((unsigned) i + 1, attinfo[i], (char *) NULL);
272         printf("\t----\n");
273 }
274
275 /* ----------------
276  *              debugtup
277  * ----------------
278  */
279 void
280 debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
281 {
282         int                     i;
283         Datum           attr;
284         char       *value;
285         bool            isnull;
286         Oid                     typoutput,
287                                 typelem;
288
289         for (i = 0; i < tuple->t_data->t_natts; ++i)
290         {
291                 attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
292                 if (isnull)
293                         continue;
294                 if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
295                                                           &typoutput, &typelem))
296                 {
297                         value = fmgr(typoutput, attr, typelem,
298                                                  typeinfo->attrs[i]->atttypmod);
299                         printatt((unsigned) i + 1, typeinfo->attrs[i], value);
300                         pfree(value);
301                 }
302         }
303         printf("\t----\n");
304 }
305
306 /* ----------------
307  *              printtup_internal
308  *              We use a different data prefix, e.g. 'B' instead of 'D' to
309  *              indicate a tuple in internal (binary) form.
310  *
311  *              This is same as printtup, except we don't use the typout func,
312  *              and therefore have no need for persistent state.
313  * ----------------
314  */
315 void
316 printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
317 {
318         StringInfoData buf;
319         int                     i,
320                                 j,
321                                 k;
322         Datum           attr;
323         bool            isnull;
324
325         /* ----------------
326          *      tell the frontend to expect new tuple data (in binary style)
327          * ----------------
328          */
329         pq_beginmessage(&buf);
330         pq_sendbyte(&buf, 'B');
331
332         /* ----------------
333          *      send a bitmap of which attributes are not null
334          * ----------------
335          */
336         j = 0;
337         k = 1 << 7;
338         for (i = 0; i < tuple->t_data->t_natts; ++i)
339         {
340                 if (!heap_attisnull(tuple, i + 1))
341                         j |= k;                         /* set bit if not null */
342                 k >>= 1;
343                 if (k == 0)                             /* end of byte? */
344                 {
345                         pq_sendint(&buf, j, 1);
346                         j = 0;
347                         k = 1 << 7;
348                 }
349         }
350         if (k != (1 << 7))                      /* flush last partial byte */
351                 pq_sendint(&buf, j, 1);
352
353         /* ----------------
354          *      send the attributes of this tuple
355          * ----------------
356          */
357 #ifdef IPORTAL_DEBUG
358         fprintf(stderr, "sending tuple with %d atts\n", tuple->t_data->t_natts);
359 #endif
360         for (i = 0; i < tuple->t_data->t_natts; ++i)
361         {
362                 int32           len = typeinfo->attrs[i]->attlen;
363
364                 attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
365                 if (!isnull)
366                 {
367                         /* # of bytes, and opaque data */
368                         if (len == -1)
369                         {
370                                 /* variable length, assume a varlena structure */
371                                 len = VARSIZE(attr) - VARHDRSZ;
372
373                                 pq_sendint(&buf, len, VARHDRSZ);
374                                 pq_sendbytes(&buf, VARDATA(attr), len);
375
376 #ifdef IPORTAL_DEBUG
377                                 {
378                                         char       *d = VARDATA(attr);
379
380                                         fprintf(stderr, "length %d data %x%x%x%x\n",
381                                                         len, *d, *(d + 1), *(d + 2), *(d + 3));
382                                 }
383 #endif
384                         }
385                         else
386                         {
387                                 /* fixed size */
388                                 if (typeinfo->attrs[i]->attbyval)
389                                 {
390                                         int8            i8;
391                                         int16           i16;
392                                         int32           i32;
393
394                                         pq_sendint(&buf, len, sizeof(int32));
395                                         switch (len)
396                                         {
397                                                 case sizeof(int8):
398                                                         i8 = DatumGetChar(attr);
399                                                         pq_sendbytes(&buf, (char *) &i8, len);
400                                                         break;
401                                                 case sizeof(int16):
402                                                         i16 = DatumGetInt16(attr);
403                                                         pq_sendbytes(&buf, (char *) &i16, len);
404                                                         break;
405                                                 case sizeof(int32):
406                                                         i32 = DatumGetInt32(attr);
407                                                         pq_sendbytes(&buf, (char *) &i32, len);
408                                                         break;
409                                         }
410 #ifdef IPORTAL_DEBUG
411                                         fprintf(stderr, "byval length %d data %d\n", len, attr);
412 #endif
413                                 }
414                                 else
415                                 {
416                                         pq_sendint(&buf, len, sizeof(int32));
417                                         pq_sendbytes(&buf, DatumGetPointer(attr), len);
418 #ifdef IPORTAL_DEBUG
419                                         fprintf(stderr, "byref length %d data %x\n", len,
420                                                         DatumGetPointer(attr));
421 #endif
422                                 }
423                         }
424                 }
425         }
426
427         pq_endmessage(&buf);
428 }