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.71 2003/05/08 18:16:36 tgl Exp $
12+ * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.72 2003/05/09 18:08:48 tgl Exp $
1313 *
1414 *-------------------------------------------------------------------------
1515 */
@@ -42,14 +42,19 @@ static void printtup_destroy(DestReceiver *self);
4242
4343/* ----------------
4444 *Private state for a printtup destination object
45+ *
46+ * NOTE: finfo is the lookup info for either typoutput or typsend, whichever
47+ * we are using for this column.
4548 * ----------------
4649 */
4750typedef struct
4851{/* Per-attribute information */
49- Oid typoutput ;/* Oid for the attribute's type output fn */
52+ Oid typoutput ;/* Oid for the type's text output fn */
53+ Oid typsend ;/* Oid for the type's binary output fn */
5054Oid typelem ;/* typelem value to pass to the output fn */
5155bool typisvarlena ;/* is it varlena (ie possibly toastable)? */
52- FmgrInfo finfo ;/* Precomputed call info for typoutput */
56+ int16 format ;/* format code for this column */
57+ FmgrInfo finfo ;/* Precomputed call info for output fn */
5358}PrinttupAttrInfo ;
5459
5560typedef struct
@@ -219,9 +224,13 @@ SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist, int16 *formats)
219224pq_endmessage (& buf );
220225}
221226
227+ /*
228+ * Get the lookup info that printtup() needs
229+ */
222230static void
223231printtup_prepare_info (DR_printtup * myState ,TupleDesc typeinfo ,int numAttrs )
224232{
233+ int16 * formats = myState -> portal -> formats ;
225234int i ;
226235
227236if (myState -> myinfo )
@@ -232,15 +241,31 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
232241if (numAttrs <=0 )
233242return ;
234243myState -> myinfo = (PrinttupAttrInfo * )
235- palloc (numAttrs * sizeof (PrinttupAttrInfo ));
244+ palloc0 (numAttrs * sizeof (PrinttupAttrInfo ));
236245for (i = 0 ;i < numAttrs ;i ++ )
237246{
238247PrinttupAttrInfo * thisState = myState -> myinfo + i ;
248+ int16 format = (formats ?formats [i ] :0 );
239249
240- if (getTypeOutputInfo (typeinfo -> attrs [i ]-> atttypid ,
241- & thisState -> typoutput ,& thisState -> typelem ,
242- & thisState -> typisvarlena ))
250+ thisState -> format = format ;
251+ if (format == 0 )
252+ {
253+ getTypeOutputInfo (typeinfo -> attrs [i ]-> atttypid ,
254+ & thisState -> typoutput ,
255+ & thisState -> typelem ,
256+ & thisState -> typisvarlena );
243257fmgr_info (thisState -> typoutput ,& thisState -> finfo );
258+ }
259+ else if (format == 1 )
260+ {
261+ getTypeBinaryOutputInfo (typeinfo -> attrs [i ]-> atttypid ,
262+ & thisState -> typsend ,
263+ & thisState -> typelem ,
264+ & thisState -> typisvarlena );
265+ fmgr_info (thisState -> typsend ,& thisState -> finfo );
266+ }
267+ else
268+ elog (ERROR ,"Unsupported format code %d" ,format );
244269}
245270}
246271
@@ -252,7 +277,6 @@ static void
252277printtup (HeapTuple tuple ,TupleDesc typeinfo ,DestReceiver * self )
253278{
254279DR_printtup * myState = (DR_printtup * )self ;
255- int16 * formats = myState -> portal -> formats ;
256280StringInfoData buf ;
257281int natts = tuple -> t_data -> t_natts ;
258282int i ;
@@ -274,58 +298,56 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
274298for (i = 0 ;i < natts ;++ i )
275299{
276300PrinttupAttrInfo * thisState = myState -> myinfo + i ;
277- int16 format = (formats ?formats [i ] :0 );
278301Datum origattr ,
279302attr ;
280303bool isnull ;
281- char * outputstr ;
282304
283305origattr = heap_getattr (tuple ,i + 1 ,typeinfo ,& isnull );
284306if (isnull )
285307{
286308pq_sendint (& buf ,-1 ,4 );
287309continue ;
288310}
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 )));
306311
307- pq_sendcountedtext (& buf ,outputstr ,strlen (outputstr ), false);
312+ /*
313+ * If we have a toasted datum, forcibly detoast it here to
314+ * avoid memory leakage inside the type's output routine.
315+ */
316+ if (thisState -> typisvarlena )
317+ attr = PointerGetDatum (PG_DETOAST_DATUM (origattr ));
318+ else
319+ attr = origattr ;
308320
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+ if (thisState -> format == 0 )
321322{
322- /* XXX something similar to above */
323- elog (ERROR ,"Binary transmission not implemented yet" );
323+ /* Text output */
324+ char * outputstr ;
325+
326+ outputstr = DatumGetCString (FunctionCall3 (& thisState -> finfo ,
327+ attr ,
328+ ObjectIdGetDatum (thisState -> typelem ),
329+ Int32GetDatum (typeinfo -> attrs [i ]-> atttypmod )));
330+ pq_sendcountedtext (& buf ,outputstr ,strlen (outputstr ), false);
331+ pfree (outputstr );
324332}
325333else
326334{
327- elog (ERROR ,"Invalid format code %d" ,format );
335+ /* Binary output */
336+ bytea * outputbytes ;
337+
338+ outputbytes = DatumGetByteaP (FunctionCall2 (& thisState -> finfo ,
339+ attr ,
340+ ObjectIdGetDatum (thisState -> typelem )));
341+ /* We assume the result will not have been toasted */
342+ pq_sendint (& buf ,VARSIZE (outputbytes )- VARHDRSZ ,4 );
343+ pq_sendbytes (& buf ,VARDATA (outputbytes ),
344+ VARSIZE (outputbytes )- VARHDRSZ );
345+ pfree (outputbytes );
328346}
347+
348+ /* Clean up detoasted copy, if any */
349+ if (attr != origattr )
350+ pfree (DatumGetPointer (attr ));
329351}
330352
331353pq_endmessage (& buf );
@@ -388,34 +410,28 @@ printtup_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
388410origattr = heap_getattr (tuple ,i + 1 ,typeinfo ,& isnull );
389411if (isnull )
390412continue ;
391- if (OidIsValid (thisState -> typoutput ))
392- {
393- /*
394- * If we have a toasted datum, forcibly detoast it here to
395- * avoid memory leakage inside the type's output routine.
396- */
397- if (thisState -> typisvarlena )
398- attr = PointerGetDatum (PG_DETOAST_DATUM (origattr ));
399- else
400- attr = origattr ;
401413
402- outputstr = DatumGetCString (FunctionCall3 (& thisState -> finfo ,
403- attr ,
414+ Assert (thisState -> format == 0 );
415+
416+ /*
417+ * If we have a toasted datum, forcibly detoast it here to
418+ * avoid memory leakage inside the type's output routine.
419+ */
420+ if (thisState -> typisvarlena )
421+ attr = PointerGetDatum (PG_DETOAST_DATUM (origattr ));
422+ else
423+ attr = origattr ;
424+
425+ outputstr = DatumGetCString (FunctionCall3 (& thisState -> finfo ,
426+ attr ,
404427ObjectIdGetDatum (thisState -> typelem ),
405428Int32GetDatum (typeinfo -> attrs [i ]-> atttypmod )));
429+ pq_sendcountedtext (& buf ,outputstr ,strlen (outputstr ), true);
430+ pfree (outputstr );
406431
407- pq_sendcountedtext (& buf ,outputstr ,strlen (outputstr ), true);
408-
409- /* Clean up detoasted copy, if any */
410- if (attr != origattr )
411- pfree (DatumGetPointer (attr ));
412- pfree (outputstr );
413- }
414- else
415- {
416- outputstr = "<unprintable>" ;
417- pq_sendcountedtext (& buf ,outputstr ,strlen (outputstr ), true);
418- }
432+ /* Clean up detoasted copy, if any */
433+ if (attr != origattr )
434+ pfree (DatumGetPointer (attr ));
419435}
420436
421437pq_endmessage (& buf );
@@ -508,30 +524,29 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
508524origattr = heap_getattr (tuple ,i + 1 ,typeinfo ,& isnull );
509525if (isnull )
510526continue ;
511- if (getTypeOutputInfo (typeinfo -> attrs [i ]-> atttypid ,
512- & typoutput ,& typelem ,& typisvarlena ))
513- {
514- /*
515- * If we have a toasted datum, forcibly detoast it here to
516- * avoid memory leakage inside the type's output routine.
517- */
518- if (typisvarlena )
519- attr = PointerGetDatum (PG_DETOAST_DATUM (origattr ));
520- else
521- attr = origattr ;
527+ getTypeOutputInfo (typeinfo -> attrs [i ]-> atttypid ,
528+ & typoutput ,& typelem ,& typisvarlena );
529+ /*
530+ * If we have a toasted datum, forcibly detoast it here to
531+ * avoid memory leakage inside the type's output routine.
532+ */
533+ if (typisvarlena )
534+ attr = PointerGetDatum (PG_DETOAST_DATUM (origattr ));
535+ else
536+ attr = origattr ;
522537
523- value = DatumGetCString (OidFunctionCall3 (typoutput ,
524- attr ,
525- ObjectIdGetDatum (typelem ),
538+ value = DatumGetCString (OidFunctionCall3 (typoutput ,
539+ attr ,
540+ ObjectIdGetDatum (typelem ),
526541Int32GetDatum (typeinfo -> attrs [i ]-> atttypmod )));
527542
528- printatt ((unsigned )i + 1 ,typeinfo -> attrs [i ],value );
543+ printatt ((unsigned )i + 1 ,typeinfo -> attrs [i ],value );
529544
530- /* Clean up detoasted copy, if any */
531- if ( attr != origattr )
532- pfree ( DatumGetPointer ( attr ));
533- pfree ( value );
534- }
545+ pfree ( value );
546+
547+ /* Clean up detoasted copy, if any */
548+ if ( attr != origattr )
549+ pfree ( DatumGetPointer ( attr ));
535550}
536551printf ("\t----\n" );
537552}
@@ -542,7 +557,7 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
542557 * We use a different message type, i.e. 'B' instead of 'D' to
543558 * indicate a tuple in internal (binary) form.
544559 *
545- * This is largely same as printtup_20, except wedon't usethe typout func .
560+ * This is largely same as printtup_20, except we usebinary formatting .
546561 * ----------------
547562 */
548563static void
@@ -587,83 +602,41 @@ printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
587602/*
588603 * send the attributes of this tuple
589604 */
590- #ifdef IPORTAL_DEBUG
591- fprintf (stderr ,"sending tuple with %d atts\n" ,natts );
592- #endif
593-
594605for (i = 0 ;i < natts ;++ i )
595606{
596607PrinttupAttrInfo * thisState = myState -> myinfo + i ;
597608Datum origattr ,
598609attr ;
599610bool isnull ;
600- int32 len ;
611+ bytea * outputbytes ;
601612
602613origattr = heap_getattr (tuple ,i + 1 ,typeinfo ,& isnull );
603614if (isnull )
604615continue ;
605- /* send # of bytes, and opaque data */
606- if (thisState -> typisvarlena )
607- {
608- /*
609- * If we have a toasted datum, must detoast before sending.
610- */
611- attr = PointerGetDatum (PG_DETOAST_DATUM (origattr ));
612-
613- len = VARSIZE (attr )- VARHDRSZ ;
614616
615- pq_sendint (& buf ,len ,VARHDRSZ );
616- pq_sendbytes (& buf ,VARDATA (attr ),len );
617+ Assert (thisState -> format == 1 );
617618
618- #ifdef IPORTAL_DEBUG
619- {
620- char * d = VARDATA (attr );
621-
622- fprintf (stderr ,"length %d data %x %x %x %x\n" ,
623- len ,* d ,* (d + 1 ),* (d + 2 ),* (d + 3 ));
624- }
625- #endif
626-
627- /* Clean up detoasted copy, if any */
628- if (attr != origattr )
629- pfree (DatumGetPointer (attr ));
630- }
619+ /*
620+ * If we have a toasted datum, forcibly detoast it here to
621+ * avoid memory leakage inside the type's output routine.
622+ */
623+ if (thisState -> typisvarlena )
624+ attr = PointerGetDatum (PG_DETOAST_DATUM (origattr ));
631625else
632- {
633- /* fixed size or cstring */
634626attr = origattr ;
635- len = typeinfo -> attrs [i ]-> attlen ;
636- if (len <=0 )
637- {
638- /* it's a cstring */
639- Assert (len == -2 && !typeinfo -> attrs [i ]-> attbyval );
640- len = strlen (DatumGetCString (attr ))+ 1 ;
641- }
642- pq_sendint (& buf ,len ,sizeof (int32 ));
643- if (typeinfo -> attrs [i ]-> attbyval )
644- {
645- Datum datumBuf ;
646-
647- /*
648- * We need this horsing around because we don't know how
649- * shorter data values are aligned within a Datum.
650- */
651- store_att_byval (& datumBuf ,attr ,len );
652- pq_sendbytes (& buf , (char * )& datumBuf ,len );
653- #ifdef IPORTAL_DEBUG
654- fprintf (stderr ,"byval length %d data %ld\n" ,len ,
655- (long )attr );
656- #endif
657- }
658- else
659- {
660- pq_sendbytes (& buf ,DatumGetPointer (attr ),len );
661- #ifdef IPORTAL_DEBUG
662- fprintf (stderr ,"byref length %d data %p\n" ,len ,
663- DatumGetPointer (attr ));
664- #endif
665- }
666- }
627+
628+ outputbytes = DatumGetByteaP (FunctionCall2 (& thisState -> finfo ,
629+ attr ,
630+ ObjectIdGetDatum (thisState -> typelem )));
631+ /* We assume the result will not have been toasted */
632+ pq_sendint (& buf ,VARSIZE (outputbytes )- VARHDRSZ ,4 );
633+ pq_sendbytes (& buf ,VARDATA (outputbytes ),
634+ VARSIZE (outputbytes )- VARHDRSZ );
635+ pfree (outputbytes );
636+
637+ /* Clean up detoasted copy, if any */
638+ if (attr != origattr )
639+ pfree (DatumGetPointer (attr ));
667640}
668641
669642pq_endmessage (& buf );