printtup.c 16.5 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * printtup.c
4
 *	  Routines to print out tuples to the destination (both frontend
5
 *	  clients and standalone backends are supported here).
6
 *
7
 *
B
Bruce Momjian 已提交
8
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
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.72 2003/05/09 18:08:48 tgl Exp $
13 14 15
 *
 *-------------------------------------------------------------------------
 */
16 17 18 19
#include "postgres.h"

#include "access/heapam.h"
#include "access/printtup.h"
20
#include "libpq/libpq.h"
21
#include "libpq/pqformat.h"
22
#include "utils/lsyscache.h"
23
#include "utils/portal.h"
24

M
Marc G. Fournier 已提交
25

26
static void printtup_startup(DestReceiver *self, int operation,
27 28 29 30 31 32 33
							 TupleDesc typeinfo);
static void printtup(HeapTuple tuple, TupleDesc typeinfo,
					 DestReceiver *self);
static void printtup_20(HeapTuple tuple, TupleDesc typeinfo,
						DestReceiver *self);
static void printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo,
								 DestReceiver *self);
34 35 36
static void printtup_shutdown(DestReceiver *self);
static void printtup_destroy(DestReceiver *self);

37

38
/* ----------------------------------------------------------------
39
 *		printtup / debugtup support
40 41 42
 * ----------------------------------------------------------------
 */

43 44
/* ----------------
 *		Private state for a printtup destination object
45 46 47
 *
 * NOTE: finfo is the lookup info for either typoutput or typsend, whichever
 * we are using for this column.
48 49
 * ----------------
 */
B
Bruce Momjian 已提交
50 51
typedef struct
{								/* Per-attribute information */
52 53
	Oid			typoutput;		/* Oid for the type's text output fn */
	Oid			typsend;		/* Oid for the type's binary output fn */
54
	Oid			typelem;		/* typelem value to pass to the output fn */
55
	bool		typisvarlena;	/* is it varlena (ie possibly toastable)? */
56 57
	int16		format;			/* format code for this column */
	FmgrInfo	finfo;			/* Precomputed call info for output fn */
58
} PrinttupAttrInfo;
59

B
Bruce Momjian 已提交
60 61 62
typedef struct
{
	DestReceiver pub;			/* publicly-known function pointers */
63
	Portal		portal;			/* the Portal we are printing from */
64
	bool		sendDescrip;	/* send RowDescription at startup? */
B
Bruce Momjian 已提交
65 66 67
	TupleDesc	attrinfo;		/* The attr info we are set up for */
	int			nattrs;
	PrinttupAttrInfo *myinfo;	/* Cached info about each attr */
68
} DR_printtup;
69 70 71 72 73

/* ----------------
 *		Initialize: create a DestReceiver for printtup
 * ----------------
 */
B
Bruce Momjian 已提交
74
DestReceiver *
75
printtup_create_DR(CommandDest dest, Portal portal)
76
{
B
Bruce Momjian 已提交
77
	DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup));
78

79 80 81
	if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
		self->pub.receiveTuple = printtup;
	else
82
	{
83 84 85 86 87 88 89 90 91
		/*
		 * In protocol 2.0 the Bind message does not exist, so there is
		 * no way for the columns to have different print formats; it's
		 * sufficient to look at the first one.
		 */
		if (portal->formats && portal->formats[0] != 0)
			self->pub.receiveTuple = printtup_internal_20;
		else
			self->pub.receiveTuple = printtup_20;
92 93 94 95 96
	}
	self->pub.startup = printtup_startup;
	self->pub.shutdown = printtup_shutdown;
	self->pub.destroy = printtup_destroy;
	self->pub.mydest = dest;
97

98 99 100 101
	self->portal = portal;

	/* Send T message automatically if Remote, but not if RemoteExecute */
	self->sendDescrip = (dest == Remote);
102

103 104 105 106
	self->attrinfo = NULL;
	self->nattrs = 0;
	self->myinfo = NULL;

B
Bruce Momjian 已提交
107
	return (DestReceiver *) self;
108 109 110
}

static void
111
printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
112
{
113
	DR_printtup *myState = (DR_printtup *) self;
114
	Portal	portal = myState->portal;
115

116 117 118 119 120 121 122
	if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
	{
		/*
		 * Send portal name to frontend (obsolete cruft, gone in proto 3.0)
		 *
		 * If portal name not specified, use "blank" portal.
		 */
123 124 125
		const char *portalName = portal->name;

		if (portalName == NULL || portalName[0] == '\0')
126 127 128 129
			portalName = "blank";

		pq_puttextmessage('P', portalName);
	}
130 131

	/*
132 133
	 * If this is a retrieve, and we are supposed to emit row descriptions,
	 * then we send back the tuple descriptor of the tuples.  
134
	 */
135
	if (operation == CMD_SELECT && myState->sendDescrip)
136 137 138 139 140 141 142 143 144 145
	{
		List	   *targetlist;

		if (portal->strategy == PORTAL_ONE_SELECT)
			targetlist = ((Query *) lfirst(portal->parseTrees))->targetList;
		else
			targetlist = NIL;

		SendRowDescriptionMessage(typeinfo, targetlist, portal->formats);
	}
146

147 148
	/* ----------------
	 * We could set up the derived attr info at this time, but we postpone it
149
	 * until the first call of printtup, for 2 reasons:
150
	 * 1. We don't waste time (compared to the old way) if there are no
B
Bruce Momjian 已提交
151
	 *	  tuples at all to output.
152
	 * 2. Checking in printtup allows us to handle the case that the tuples
B
Bruce Momjian 已提交
153 154
	 *	  change type midway through (although this probably can't happen in
	 *	  the current executor).
155 156 157 158
	 * ----------------
	 */
}

159 160
/*
 * SendRowDescriptionMessage --- send a RowDescription message to the frontend
161 162 163 164
 *
 * Notes: the TupleDesc has typically been manufactured by ExecTypeFromTL()
 * or some similar function; it does not contain a full set of fields.
 * The targetlist will be NIL when executing a utility function that does
165 166 167 168
 * not have a plan.  If the targetlist isn't NIL then it is a Query node's
 * targetlist; it is up to us to ignore resjunk columns in it.  The formats[]
 * array pointer might be NULL (if we are doing Describe on a prepared stmt);
 * send zeroes for the format codes in that case.
169 170
 */
void
171
SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist, int16 *formats)
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
{
	Form_pg_attribute *attrs = typeinfo->attrs;
	int			natts = typeinfo->natts;
	int			proto = PG_PROTOCOL_MAJOR(FrontendProtocol);
	int			i;
	StringInfoData buf;

	pq_beginmessage(&buf, 'T');		/* tuple descriptor message type */
	pq_sendint(&buf, natts, 2);		/* # of attrs in tuples */

	for (i = 0; i < natts; ++i)
	{
		pq_sendstring(&buf, NameStr(attrs[i]->attname));
		/* column ID info appears in protocol 3.0 and up */
		if (proto >= 3)
		{
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
			/* Do we have a non-resjunk tlist item? */
			while (targetlist &&
				   ((TargetEntry *) lfirst(targetlist))->resdom->resjunk)
				targetlist = lnext(targetlist);
			if (targetlist)
			{
				Resdom	   *res = ((TargetEntry *) lfirst(targetlist))->resdom;

				pq_sendint(&buf, res->resorigtbl, 4);
				pq_sendint(&buf, res->resorigcol, 2);
				targetlist = lnext(targetlist);
			}
			else
			{
				/* No info available, so send zeroes */
				pq_sendint(&buf, 0, 4);
				pq_sendint(&buf, 0, 2);
			}
206 207 208 209 210 211 212 213 214
		}
		pq_sendint(&buf, (int) attrs[i]->atttypid,
				   sizeof(attrs[i]->atttypid));
		pq_sendint(&buf, attrs[i]->attlen,
				   sizeof(attrs[i]->attlen));
		/* typmod appears in protocol 2.0 and up */
		if (proto >= 2)
			pq_sendint(&buf, attrs[i]->atttypmod,
					   sizeof(attrs[i]->atttypmod));
215 216 217 218 219 220 221 222
		/* format info appears in protocol 3.0 and up */
		if (proto >= 3)
		{
			if (formats)
				pq_sendint(&buf, formats[i], 2);
			else
				pq_sendint(&buf, 0, 2);
		}
223 224 225 226
	}
	pq_endmessage(&buf);
}

227 228 229
/*
 * Get the lookup info that printtup() needs
 */
230
static void
231
printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
232
{
233
	int16	   *formats = myState->portal->formats;
B
Bruce Momjian 已提交
234
	int			i;
235 236

	if (myState->myinfo)
B
Bruce Momjian 已提交
237
		pfree(myState->myinfo); /* get rid of any old data */
238 239 240 241 242
	myState->myinfo = NULL;
	myState->attrinfo = typeinfo;
	myState->nattrs = numAttrs;
	if (numAttrs <= 0)
		return;
B
Bruce Momjian 已提交
243
	myState->myinfo = (PrinttupAttrInfo *)
244
		palloc0(numAttrs * sizeof(PrinttupAttrInfo));
245 246
	for (i = 0; i < numAttrs; i++)
	{
B
Bruce Momjian 已提交
247
		PrinttupAttrInfo *thisState = myState->myinfo + i;
248
		int16		format = (formats ? formats[i] : 0);
B
Bruce Momjian 已提交
249

250 251 252 253 254 255 256
		thisState->format = format;
		if (format == 0)
		{
			getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
							  &thisState->typoutput,
							  &thisState->typelem,
							  &thisState->typisvarlena);
257
			fmgr_info(thisState->typoutput, &thisState->finfo);
258 259 260 261 262 263 264 265 266 267 268
		}
		else if (format == 1)
		{
			getTypeBinaryOutputInfo(typeinfo->attrs[i]->atttypid,
									&thisState->typsend,
									&thisState->typelem,
									&thisState->typisvarlena);
			fmgr_info(thisState->typsend, &thisState->finfo);
		}
		else
			elog(ERROR, "Unsupported format code %d", format);
269 270 271
	}
}

272
/* ----------------
273
 *		printtup --- print a tuple in protocol 3.0
274 275
 * ----------------
 */
276
static void
277
printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
{
	DR_printtup *myState = (DR_printtup *) self;
	StringInfoData buf;
	int			natts = tuple->t_data->t_natts;
	int			i;

	/* Set or update my derived attribute info, if needed */
	if (myState->attrinfo != typeinfo || myState->nattrs != natts)
		printtup_prepare_info(myState, typeinfo, natts);

	/*
	 * Prepare a DataRow message
	 */
	pq_beginmessage(&buf, 'D');

	pq_sendint(&buf, natts, 2);

	/*
	 * send the attributes of this tuple
	 */
	for (i = 0; i < natts; ++i)
	{
		PrinttupAttrInfo *thisState = myState->myinfo + i;
		Datum		origattr,
					attr;
		bool		isnull;

		origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
		if (isnull)
		{
			pq_sendint(&buf, -1, 4);
			continue;
		}

312 313 314 315 316 317 318 319
		/*
		 * If we have a toasted datum, forcibly detoast it here to
		 * avoid memory leakage inside the type's output routine.
		 */
		if (thisState->typisvarlena)
			attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
		else
			attr = origattr;
320

321
		if (thisState->format == 0)
322
		{
323 324 325 326 327 328 329 330 331
			/* Text output */
			char	   *outputstr;

			outputstr = DatumGetCString(FunctionCall3(&thisState->finfo,
													  attr,
									ObjectIdGetDatum(thisState->typelem),
						  Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
			pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
			pfree(outputstr);
332 333 334
		}
		else
		{
335 336 337 338 339 340 341 342 343 344 345
			/* Binary output */
			bytea	   *outputbytes;

			outputbytes = DatumGetByteaP(FunctionCall2(&thisState->finfo,
													   attr,
									ObjectIdGetDatum(thisState->typelem)));
			/* We assume the result will not have been toasted */
			pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
			pq_sendbytes(&buf, VARDATA(outputbytes),
						 VARSIZE(outputbytes) - VARHDRSZ);
			pfree(outputbytes);
346
		}
347 348 349 350

		/* Clean up detoasted copy, if any */
		if (attr != origattr)
			pfree(DatumGetPointer(attr));
351 352 353 354 355 356 357 358 359 360 361
	}

	pq_endmessage(&buf);
}

/* ----------------
 *		printtup_20 --- print a tuple in protocol 2.0
 * ----------------
 */
static void
printtup_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
362
{
B
Bruce Momjian 已提交
363
	DR_printtup *myState = (DR_printtup *) self;
364
	StringInfoData buf;
365
	int			natts = tuple->t_data->t_natts;
366 367
	int			i,
				j,
368
				k;
369

370
	/* Set or update my derived attribute info, if needed */
371 372
	if (myState->attrinfo != typeinfo || myState->nattrs != natts)
		printtup_prepare_info(myState, typeinfo, natts);
373

374 375
	/*
	 * tell the frontend to expect new tuple data (in ASCII style)
376
	 */
377
	pq_beginmessage(&buf, 'D');
378

379 380
	/*
	 * send a bitmap of which attributes are not null
381 382 383
	 */
	j = 0;
	k = 1 << 7;
384
	for (i = 0; i < natts; ++i)
385
	{
B
Bruce Momjian 已提交
386
		if (!heap_attisnull(tuple, i + 1))
387
			j |= k;				/* set bit if not null */
388
		k >>= 1;
389
		if (k == 0)				/* end of byte? */
390
		{
391
			pq_sendint(&buf, j, 1);
392 393 394
			j = 0;
			k = 1 << 7;
		}
395
	}
396
	if (k != (1 << 7))			/* flush last partial byte */
397
		pq_sendint(&buf, j, 1);
398

399 400
	/*
	 * send the attributes of this tuple
401
	 */
402
	for (i = 0; i < natts; ++i)
403
	{
B
Bruce Momjian 已提交
404
		PrinttupAttrInfo *thisState = myState->myinfo + i;
405 406 407 408
		Datum		origattr,
					attr;
		bool		isnull;
		char	   *outputstr;
B
Bruce Momjian 已提交
409

410
		origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
M
 
Marc G. Fournier 已提交
411 412
		if (isnull)
			continue;
413

414 415 416 417 418 419 420 421 422 423 424 425 426
		Assert(thisState->format == 0);

		/*
		 * If we have a toasted datum, forcibly detoast it here to
		 * avoid memory leakage inside the type's output routine.
		 */
		if (thisState->typisvarlena)
			attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
		else
			attr = origattr;

		outputstr = DatumGetCString(FunctionCall3(&thisState->finfo,
												  attr,
B
Bruce Momjian 已提交
427 428
									ObjectIdGetDatum(thisState->typelem),
						  Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
429 430
		pq_sendcountedtext(&buf, outputstr, strlen(outputstr), true);
		pfree(outputstr);
431

432 433 434
		/* Clean up detoasted copy, if any */
		if (attr != origattr)
			pfree(DatumGetPointer(attr));
435
	}
436 437

	pq_endmessage(&buf);
438 439
}

440
/* ----------------
441
 *		printtup_shutdown
442 443 444
 * ----------------
 */
static void
445
printtup_shutdown(DestReceiver *self)
446
{
B
Bruce Momjian 已提交
447 448
	DR_printtup *myState = (DR_printtup *) self;

449 450
	if (myState->myinfo)
		pfree(myState->myinfo);
451 452 453 454 455 456 457 458 459 460 461 462
	myState->myinfo = NULL;
	myState->attrinfo = NULL;
}

/* ----------------
 *		printtup_destroy
 * ----------------
 */
static void
printtup_destroy(DestReceiver *self)
{
	pfree(self);
463 464
}

465
/* ----------------
466
 *		printatt
467 468 469 470
 * ----------------
 */
static void
printatt(unsigned attributeId,
471
		 Form_pg_attribute attributeP,
472
		 char *value)
473
{
B
Bruce Momjian 已提交
474
	printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",
475
		   attributeId,
476
		   NameStr(attributeP->attname),
477 478 479 480 481
		   value != NULL ? " = \"" : "",
		   value != NULL ? value : "",
		   value != NULL ? "\"" : "",
		   (unsigned int) (attributeP->atttypid),
		   attributeP->attlen,
B
Bruce Momjian 已提交
482
		   attributeP->atttypmod,
483
		   attributeP->attbyval ? 't' : 'f');
484 485 486
}

/* ----------------
487
 *		debugStartup - prepare to print tuples for an interactive backend
488 489 490
 * ----------------
 */
void
491
debugStartup(DestReceiver *self, int operation, TupleDesc typeinfo)
492
{
493 494 495 496
	int			natts = typeinfo->natts;
	Form_pg_attribute *attinfo = typeinfo->attrs;
	int			i;

497 498 499
	/*
	 * show the return type of the tuples
	 */
500 501 502
	for (i = 0; i < natts; ++i)
		printatt((unsigned) i + 1, attinfo[i], (char *) NULL);
	printf("\t----\n");
503 504 505 506
}

/* ----------------
 *		debugtup - print one tuple for an interactive backend
507 508 509
 * ----------------
 */
void
510
debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
511
{
512
	int			natts = tuple->t_data->t_natts;
513
	int			i;
514 515
	Datum		origattr,
				attr;
516
	char	   *value;
517
	bool		isnull;
518 519
	Oid			typoutput,
				typelem;
520
	bool		typisvarlena;
521

522
	for (i = 0; i < natts; ++i)
523
	{
524
		origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
525 526
		if (isnull)
			continue;
527 528 529 530 531 532 533 534 535 536
		getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
						  &typoutput, &typelem, &typisvarlena);
		/*
		 * If we have a toasted datum, forcibly detoast it here to
		 * avoid memory leakage inside the type's output routine.
		 */
		if (typisvarlena)
			attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
		else
			attr = origattr;
537

538 539 540
		value = DatumGetCString(OidFunctionCall3(typoutput,
												 attr,
												 ObjectIdGetDatum(typelem),
B
Bruce Momjian 已提交
541
						  Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
542

543
		printatt((unsigned) i + 1, typeinfo->attrs[i], value);
544

545 546 547 548 549
		pfree(value);

		/* Clean up detoasted copy, if any */
		if (attr != origattr)
			pfree(DatumGetPointer(attr));
550
	}
551
	printf("\t----\n");
552 553 554
}

/* ----------------
555 556 557 558
 *		printtup_internal_20 --- print a binary tuple in protocol 2.0
 *
 * We use a different message type, i.e. 'B' instead of 'D' to
 * indicate a tuple in internal (binary) form.
559
 *
560
 * This is largely same as printtup_20, except we use binary formatting.
561 562
 * ----------------
 */
563
static void
564
printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
565
{
566
	DR_printtup *myState = (DR_printtup *) self;
567
	StringInfoData buf;
568
	int			natts = tuple->t_data->t_natts;
569 570 571
	int			i,
				j,
				k;
572 573 574 575

	/* Set or update my derived attribute info, if needed */
	if (myState->attrinfo != typeinfo || myState->nattrs != natts)
		printtup_prepare_info(myState, typeinfo, natts);
576

577 578
	/*
	 * tell the frontend to expect new tuple data (in binary style)
579
	 */
580
	pq_beginmessage(&buf, 'B');
581

582 583
	/*
	 * send a bitmap of which attributes are not null
584 585 586
	 */
	j = 0;
	k = 1 << 7;
587
	for (i = 0; i < natts; ++i)
588
	{
B
Bruce Momjian 已提交
589
		if (!heap_attisnull(tuple, i + 1))
590
			j |= k;				/* set bit if not null */
591
		k >>= 1;
592
		if (k == 0)				/* end of byte? */
593
		{
594
			pq_sendint(&buf, j, 1);
595 596 597
			j = 0;
			k = 1 << 7;
		}
598
	}
599
	if (k != (1 << 7))			/* flush last partial byte */
600
		pq_sendint(&buf, j, 1);
601

602 603
	/*
	 * send the attributes of this tuple
604
	 */
605
	for (i = 0; i < natts; ++i)
606
	{
607 608 609 610
		PrinttupAttrInfo *thisState = myState->myinfo + i;
		Datum		origattr,
					attr;
		bool		isnull;
611
		bytea	   *outputbytes;
612

613 614 615
		origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
		if (isnull)
			continue;
616

617
		Assert(thisState->format == 1);
618

619 620 621 622 623 624
		/*
		 * If we have a toasted datum, forcibly detoast it here to
		 * avoid memory leakage inside the type's output routine.
		 */
		if (thisState->typisvarlena)
			attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
625 626
		else
			attr = origattr;
627 628 629 630 631 632 633 634 635 636 637 638 639

		outputbytes = DatumGetByteaP(FunctionCall2(&thisState->finfo,
												   attr,
									ObjectIdGetDatum(thisState->typelem)));
		/* We assume the result will not have been toasted */
		pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
		pq_sendbytes(&buf, VARDATA(outputbytes),
					 VARSIZE(outputbytes) - VARHDRSZ);
		pfree(outputbytes);

		/* Clean up detoasted copy, if any */
		if (attr != origattr)
			pfree(DatumGetPointer(attr));
640
	}
641 642

	pq_endmessage(&buf);
643
}