99 * Portions Copyright (c) 1994, Regents of the University of California
1010 *
1111 * 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 $
1313 *
1414 *-------------------------------------------------------------------------
1515 */
2020#include "libpq/libpq.h"
2121#include "libpq/pqformat.h"
2222#include "utils/lsyscache.h"
23+ #include "utils/portal.h"
2324
2425
2526static 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 );
2934static void printtup_shutdown (DestReceiver * self );
3035static void printtup_destroy (DestReceiver * self );
3136
@@ -50,6 +55,7 @@ typedef struct
5055typedef struct
5156{
5257DestReceiver pub ;/* publicly-known function pointers */
58+ Portal portal ;/* the Portal we are printing from */
5359bool sendDescrip ;/* send RowDescription at startup? */
5460TupleDesc attrinfo ;/* The attr info we are set up for */
5561int nattrs ;
@@ -61,43 +67,33 @@ typedef struct
6167 * ----------------
6268 */
6369DestReceiver *
64- printtup_create_DR (CommandDest dest )
70+ printtup_create_DR (CommandDest dest , Portal portal )
6571{
6672DR_printtup * self = (DR_printtup * )palloc (sizeof (DR_printtup ));
67- bool isBinary ;
68- bool sendDescrip ;
6973
70- switch (dest )
74+ if (PG_PROTOCOL_MAJOR (FrontendProtocol ) >=3 )
75+ self -> pub .receiveTuple = printtup ;
76+ else
7177{
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 ;
9287}
93-
94- self -> pub .receiveTuple = isBinary ?printtup_internal :printtup ;
9588self -> pub .startup = printtup_startup ;
9689self -> pub .shutdown = printtup_shutdown ;
9790self -> pub .destroy = printtup_destroy ;
9891self -> pub .mydest = dest ;
9992
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 );
10197
10298self -> attrinfo = NULL ;
10399self -> nattrs = 0 ;
@@ -107,10 +103,10 @@ printtup_create_DR(CommandDest dest)
107103}
108104
109105static 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 )
112107{
113108DR_printtup * myState = (DR_printtup * )self ;
109+ Portal portal = myState -> portal ;
114110
115111if (PG_PROTOCOL_MAJOR (FrontendProtocol )< 3 )
116112{
@@ -119,7 +115,9 @@ printtup_startup(DestReceiver *self, int operation,
119115 *
120116 * If portal name not specified, use "blank" portal.
121117 */
122- if (portalName == NULL )
118+ const char * portalName = portal -> name ;
119+
120+ if (portalName == NULL || portalName [0 ]== '\0' )
123121portalName = "blank" ;
124122
125123pq_puttextmessage ('P' ,portalName );
@@ -130,7 +128,16 @@ printtup_startup(DestReceiver *self, int operation,
130128 * then we send back the tuple descriptor of the tuples.
131129 */
132130if (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+ }
134141
135142/* ----------------
136143 * 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,
150157 * Notes: the TupleDesc has typically been manufactured by ExecTypeFromTL()
151158 * or some similar function; it does not contain a full set of fields.
152159 * 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.
155164 */
156165void
157- SendRowDescriptionMessage (TupleDesc typeinfo ,List * targetlist )
166+ SendRowDescriptionMessage (TupleDesc typeinfo ,List * targetlist , int16 * formats )
158167{
159168Form_pg_attribute * attrs = typeinfo -> attrs ;
160169int natts = typeinfo -> natts ;
@@ -198,6 +207,14 @@ SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist)
198207if (proto >=2 )
199208pq_sendint (& buf ,attrs [i ]-> atttypmod ,
200209sizeof (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+ }
201218}
202219pq_endmessage (& buf );
203220}
@@ -228,11 +245,98 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
228245}
229246
230247/* ----------------
231- *printtup
248+ *printtup --- print a tuple in protocol 3.0
232249 * ----------------
233250 */
234251static void
235252printtup (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 )
236340{
237341DR_printtup * myState = (DR_printtup * )self ;
238342StringInfoData buf ;
@@ -300,7 +404,7 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
300404ObjectIdGetDatum (thisState -> typelem ),
301405Int32GetDatum (typeinfo -> attrs [i ]-> atttypmod )));
302406
303- pq_sendcountedtext (& buf ,outputstr ,strlen (outputstr ));
407+ pq_sendcountedtext (& buf ,outputstr ,strlen (outputstr ), true );
304408
305409/* Clean up detoasted copy, if any */
306410if (attr != origattr )
@@ -310,7 +414,7 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
310414else
311415{
312416outputstr = "<unprintable>" ;
313- pq_sendcountedtext (& buf ,outputstr ,strlen (outputstr ));
417+ pq_sendcountedtext (& buf ,outputstr ,strlen (outputstr ), true );
314418}
315419}
316420
@@ -363,38 +467,23 @@ printatt(unsigned attributeId,
363467attributeP -> attbyval ?'t' :'f' );
364468}
365469
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-
383470/* ----------------
384471 *debugStartup - prepare to print tuples for an interactive backend
385472 * ----------------
386473 */
387474void
388- debugStartup (DestReceiver * self ,int operation ,
389- const char * portalName ,TupleDesc typeinfo ,List * targetlist )
475+ debugStartup (DestReceiver * self ,int operation ,TupleDesc typeinfo )
390476{
477+ int natts = typeinfo -> natts ;
478+ Form_pg_attribute * attinfo = typeinfo -> attrs ;
479+ int i ;
480+
391481/*
392482 * show the return type of the tuples
393483 */
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" );
398487}
399488
400489/* ----------------
@@ -448,15 +537,16 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
448537}
449538
450539/* ----------------
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.
454544 *
455- * This is largely same asprinttup , except we don't use the typout func.
545+ * This is largely same asprinttup_20 , except we don't use the typout func.
456546 * ----------------
457547 */
458548static void
459- printtup_internal (HeapTuple tuple ,TupleDesc typeinfo ,DestReceiver * self )
549+ printtup_internal_20 (HeapTuple tuple ,TupleDesc typeinfo ,DestReceiver * self )
460550{
461551DR_printtup * myState = (DR_printtup * )self ;
462552StringInfoData buf ;