9
9
* Portions Copyright (c) 1994, Regents of the University of California
10
10
*
11
11
* IDENTIFICATION
12
- * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.70 2003/05/06 20:26:26 tgl Exp $
12
+ * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.71 2003/05/08 18:16:36 tgl Exp $
13
13
*
14
14
*-------------------------------------------------------------------------
15
15
*/
20
20
#include "libpq/libpq.h"
21
21
#include "libpq/pqformat.h"
22
22
#include "utils/lsyscache.h"
23
+ #include "utils/portal.h"
23
24
24
25
25
26
static void printtup_startup (DestReceiver * self , int operation ,
26
- const char * portalName , TupleDesc typeinfo , List * targetlist );
27
- static void printtup (HeapTuple tuple , TupleDesc typeinfo , DestReceiver * self );
28
- static void printtup_internal (HeapTuple tuple , TupleDesc typeinfo , DestReceiver * self );
27
+ TupleDesc typeinfo );
28
+ static void printtup (HeapTuple tuple , TupleDesc typeinfo ,
29
+ DestReceiver * self );
30
+ static void printtup_20 (HeapTuple tuple , TupleDesc typeinfo ,
31
+ DestReceiver * self );
32
+ static void printtup_internal_20 (HeapTuple tuple , TupleDesc typeinfo ,
33
+ DestReceiver * self );
29
34
static void printtup_shutdown (DestReceiver * self );
30
35
static void printtup_destroy (DestReceiver * self );
31
36
@@ -50,6 +55,7 @@ typedef struct
50
55
typedef struct
51
56
{
52
57
DestReceiver pub ; /* publicly-known function pointers */
58
+ Portal portal ; /* the Portal we are printing from */
53
59
bool sendDescrip ; /* send RowDescription at startup? */
54
60
TupleDesc attrinfo ; /* The attr info we are set up for */
55
61
int nattrs ;
@@ -61,43 +67,33 @@ typedef struct
61
67
* ----------------
62
68
*/
63
69
DestReceiver *
64
- printtup_create_DR (CommandDest dest )
70
+ printtup_create_DR (CommandDest dest , Portal portal )
65
71
{
66
72
DR_printtup * self = (DR_printtup * ) palloc (sizeof (DR_printtup ));
67
- bool isBinary ;
68
- bool sendDescrip ;
69
73
70
- switch (dest )
74
+ if (PG_PROTOCOL_MAJOR (FrontendProtocol ) >= 3 )
75
+ self -> pub .receiveTuple = printtup ;
76
+ else
71
77
{
72
- case Remote :
73
- isBinary = false;
74
- sendDescrip = true;
75
- break ;
76
- case RemoteInternal :
77
- isBinary = true;
78
- sendDescrip = true;
79
- break ;
80
- case RemoteExecute :
81
- isBinary = false;
82
- sendDescrip = false; /* no T message for Execute */
83
- break ;
84
- case RemoteExecuteInternal :
85
- isBinary = true;
86
- sendDescrip = false; /* no T message for Execute */
87
- break ;
88
-
89
- default :
90
- elog (ERROR , "printtup_create_DR: unsupported dest" );
91
- return NULL ;
78
+ /*
79
+ * In protocol 2.0 the Bind message does not exist, so there is
80
+ * no way for the columns to have different print formats; it's
81
+ * sufficient to look at the first one.
82
+ */
83
+ if (portal -> formats && portal -> formats [0 ] != 0 )
84
+ self -> pub .receiveTuple = printtup_internal_20 ;
85
+ else
86
+ self -> pub .receiveTuple = printtup_20 ;
92
87
}
93
-
94
- self -> pub .receiveTuple = isBinary ? printtup_internal : printtup ;
95
88
self -> pub .startup = printtup_startup ;
96
89
self -> pub .shutdown = printtup_shutdown ;
97
90
self -> pub .destroy = printtup_destroy ;
98
91
self -> pub .mydest = dest ;
99
92
100
- self -> sendDescrip = sendDescrip ;
93
+ self -> portal = portal ;
94
+
95
+ /* Send T message automatically if Remote, but not if RemoteExecute */
96
+ self -> sendDescrip = (dest == Remote );
101
97
102
98
self -> attrinfo = NULL ;
103
99
self -> nattrs = 0 ;
@@ -107,10 +103,10 @@ printtup_create_DR(CommandDest dest)
107
103
}
108
104
109
105
static void
110
- printtup_startup (DestReceiver * self , int operation ,
111
- const char * portalName , TupleDesc typeinfo , List * targetlist )
106
+ printtup_startup (DestReceiver * self , int operation , TupleDesc typeinfo )
112
107
{
113
108
DR_printtup * myState = (DR_printtup * ) self ;
109
+ Portal portal = myState -> portal ;
114
110
115
111
if (PG_PROTOCOL_MAJOR (FrontendProtocol ) < 3 )
116
112
{
@@ -119,7 +115,9 @@ printtup_startup(DestReceiver *self, int operation,
119
115
*
120
116
* If portal name not specified, use "blank" portal.
121
117
*/
122
- if (portalName == NULL )
118
+ const char * portalName = portal -> name ;
119
+
120
+ if (portalName == NULL || portalName [0 ] == '\0' )
123
121
portalName = "blank" ;
124
122
125
123
pq_puttextmessage ('P' , portalName );
@@ -130,7 +128,16 @@ printtup_startup(DestReceiver *self, int operation,
130
128
* then we send back the tuple descriptor of the tuples.
131
129
*/
132
130
if (operation == CMD_SELECT && myState -> sendDescrip )
133
- SendRowDescriptionMessage (typeinfo , targetlist );
131
+ {
132
+ List * targetlist ;
133
+
134
+ if (portal -> strategy == PORTAL_ONE_SELECT )
135
+ targetlist = ((Query * ) lfirst (portal -> parseTrees ))-> targetList ;
136
+ else
137
+ targetlist = NIL ;
138
+
139
+ SendRowDescriptionMessage (typeinfo , targetlist , portal -> formats );
140
+ }
134
141
135
142
/* ----------------
136
143
* We could set up the derived attr info at this time, but we postpone it
@@ -150,11 +157,13 @@ printtup_startup(DestReceiver *self, int operation,
150
157
* Notes: the TupleDesc has typically been manufactured by ExecTypeFromTL()
151
158
* or some similar function; it does not contain a full set of fields.
152
159
* The targetlist will be NIL when executing a utility function that does
153
- * not have a plan. If the targetlist isn't NIL then it is a Plan node's
154
- * targetlist; it is up to us to ignore resjunk columns in it.
160
+ * not have a plan. If the targetlist isn't NIL then it is a Query node's
161
+ * targetlist; it is up to us to ignore resjunk columns in it. The formats[]
162
+ * array pointer might be NULL (if we are doing Describe on a prepared stmt);
163
+ * send zeroes for the format codes in that case.
155
164
*/
156
165
void
157
- SendRowDescriptionMessage (TupleDesc typeinfo , List * targetlist )
166
+ SendRowDescriptionMessage (TupleDesc typeinfo , List * targetlist , int16 * formats )
158
167
{
159
168
Form_pg_attribute * attrs = typeinfo -> attrs ;
160
169
int natts = typeinfo -> natts ;
@@ -198,6 +207,14 @@ SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist)
198
207
if (proto >= 2 )
199
208
pq_sendint (& buf , attrs [i ]-> atttypmod ,
200
209
sizeof (attrs [i ]-> atttypmod ));
210
+ /* format info appears in protocol 3.0 and up */
211
+ if (proto >= 3 )
212
+ {
213
+ if (formats )
214
+ pq_sendint (& buf , formats [i ], 2 );
215
+ else
216
+ pq_sendint (& buf , 0 , 2 );
217
+ }
201
218
}
202
219
pq_endmessage (& buf );
203
220
}
@@ -228,11 +245,98 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
228
245
}
229
246
230
247
/* ----------------
231
- * printtup
248
+ * printtup --- print a tuple in protocol 3.0
232
249
* ----------------
233
250
*/
234
251
static void
235
252
printtup (HeapTuple tuple , TupleDesc typeinfo , DestReceiver * self )
253
+ {
254
+ DR_printtup * myState = (DR_printtup * ) self ;
255
+ int16 * formats = myState -> portal -> formats ;
256
+ StringInfoData buf ;
257
+ int natts = tuple -> t_data -> t_natts ;
258
+ int i ;
259
+
260
+ /* Set or update my derived attribute info, if needed */
261
+ if (myState -> attrinfo != typeinfo || myState -> nattrs != natts )
262
+ printtup_prepare_info (myState , typeinfo , natts );
263
+
264
+ /*
265
+ * Prepare a DataRow message
266
+ */
267
+ pq_beginmessage (& buf , 'D' );
268
+
269
+ pq_sendint (& buf , natts , 2 );
270
+
271
+ /*
272
+ * send the attributes of this tuple
273
+ */
274
+ for (i = 0 ; i < natts ; ++ i )
275
+ {
276
+ PrinttupAttrInfo * thisState = myState -> myinfo + i ;
277
+ int16 format = (formats ? formats [i ] : 0 );
278
+ Datum origattr ,
279
+ attr ;
280
+ bool isnull ;
281
+ char * outputstr ;
282
+
283
+ origattr = heap_getattr (tuple , i + 1 , typeinfo , & isnull );
284
+ if (isnull )
285
+ {
286
+ pq_sendint (& buf , -1 , 4 );
287
+ continue ;
288
+ }
289
+ if (format == 0 )
290
+ {
291
+ if (OidIsValid (thisState -> typoutput ))
292
+ {
293
+ /*
294
+ * If we have a toasted datum, forcibly detoast it here to
295
+ * avoid memory leakage inside the type's output routine.
296
+ */
297
+ if (thisState -> typisvarlena )
298
+ attr = PointerGetDatum (PG_DETOAST_DATUM (origattr ));
299
+ else
300
+ attr = origattr ;
301
+
302
+ outputstr = DatumGetCString (FunctionCall3 (& thisState -> finfo ,
303
+ attr ,
304
+ ObjectIdGetDatum (thisState -> typelem ),
305
+ Int32GetDatum (typeinfo -> attrs [i ]-> atttypmod )));
306
+
307
+ pq_sendcountedtext (& buf , outputstr , strlen (outputstr ), false);
308
+
309
+ /* Clean up detoasted copy, if any */
310
+ if (attr != origattr )
311
+ pfree (DatumGetPointer (attr ));
312
+ pfree (outputstr );
313
+ }
314
+ else
315
+ {
316
+ outputstr = "<unprintable>" ;
317
+ pq_sendcountedtext (& buf , outputstr , strlen (outputstr ), false);
318
+ }
319
+ }
320
+ else if (format == 1 )
321
+ {
322
+ /* XXX something similar to above */
323
+ elog (ERROR , "Binary transmission not implemented yet" );
324
+ }
325
+ else
326
+ {
327
+ elog (ERROR , "Invalid format code %d" , format );
328
+ }
329
+ }
330
+
331
+ pq_endmessage (& buf );
332
+ }
333
+
334
+ /* ----------------
335
+ * printtup_20 --- print a tuple in protocol 2.0
336
+ * ----------------
337
+ */
338
+ static void
339
+ printtup_20 (HeapTuple tuple , TupleDesc typeinfo , DestReceiver * self )
236
340
{
237
341
DR_printtup * myState = (DR_printtup * ) self ;
238
342
StringInfoData buf ;
@@ -300,7 +404,7 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
300
404
ObjectIdGetDatum (thisState -> typelem ),
301
405
Int32GetDatum (typeinfo -> attrs [i ]-> atttypmod )));
302
406
303
- pq_sendcountedtext (& buf , outputstr , strlen (outputstr ));
407
+ pq_sendcountedtext (& buf , outputstr , strlen (outputstr ), true );
304
408
305
409
/* Clean up detoasted copy, if any */
306
410
if (attr != origattr )
@@ -310,7 +414,7 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
310
414
else
311
415
{
312
416
outputstr = "<unprintable>" ;
313
- pq_sendcountedtext (& buf , outputstr , strlen (outputstr ));
417
+ pq_sendcountedtext (& buf , outputstr , strlen (outputstr ), true );
314
418
}
315
419
}
316
420
@@ -363,38 +467,23 @@ printatt(unsigned attributeId,
363
467
attributeP -> attbyval ? 't' : 'f' );
364
468
}
365
469
366
- /* ----------------
367
- * showatts
368
- * ----------------
369
- */
370
- static void
371
- showatts (const char * name , TupleDesc tupleDesc )
372
- {
373
- int natts = tupleDesc -> natts ;
374
- Form_pg_attribute * attinfo = tupleDesc -> attrs ;
375
- int i ;
376
-
377
- puts (name );
378
- for (i = 0 ; i < natts ; ++ i )
379
- printatt ((unsigned ) i + 1 , attinfo [i ], (char * ) NULL );
380
- printf ("\t----\n" );
381
- }
382
-
383
470
/* ----------------
384
471
* debugStartup - prepare to print tuples for an interactive backend
385
472
* ----------------
386
473
*/
387
474
void
388
- debugStartup (DestReceiver * self , int operation ,
389
- const char * portalName , TupleDesc typeinfo , List * targetlist )
475
+ debugStartup (DestReceiver * self , int operation , TupleDesc typeinfo )
390
476
{
477
+ int natts = typeinfo -> natts ;
478
+ Form_pg_attribute * attinfo = typeinfo -> attrs ;
479
+ int i ;
480
+
391
481
/*
392
482
* show the return type of the tuples
393
483
*/
394
- if (portalName == NULL )
395
- portalName = "blank" ;
396
-
397
- showatts (portalName , typeinfo );
484
+ for (i = 0 ; i < natts ; ++ i )
485
+ printatt ((unsigned ) i + 1 , attinfo [i ], (char * ) NULL );
486
+ printf ("\t----\n" );
398
487
}
399
488
400
489
/* ----------------
@@ -448,15 +537,16 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
448
537
}
449
538
450
539
/* ----------------
451
- * printtup_internal
452
- * We use a different data prefix, e.g. 'B' instead of 'D' to
453
- * indicate a tuple in internal (binary) form.
540
+ * printtup_internal_20 --- print a binary tuple in protocol 2.0
541
+ *
542
+ * We use a different message type, i.e. 'B' instead of 'D' to
543
+ * indicate a tuple in internal (binary) form.
454
544
*
455
- * This is largely same as printtup , except we don't use the typout func.
545
+ * This is largely same as printtup_20 , except we don't use the typout func.
456
546
* ----------------
457
547
*/
458
548
static void
459
- printtup_internal (HeapTuple tuple , TupleDesc typeinfo , DestReceiver * self )
549
+ printtup_internal_20 (HeapTuple tuple , TupleDesc typeinfo , DestReceiver * self )
460
550
{
461
551
DR_printtup * myState = (DR_printtup * ) self ;
462
552
StringInfoData buf ;
0 commit comments