⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 printtup.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
字号:
/*------------------------------------------------------------------------- * * printtup.c *	  Routines to print out tuples to the destination (binary or non-binary *	  portals, frontend/interactive backend, etc.). * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.47.2.1 1999/08/02 05:24:25 scrappy Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "access/printtup.h"#include "catalog/pg_type.h"#include "libpq/pqformat.h"#include "utils/syscache.h"static void printtup_setup(DestReceiver *self, TupleDesc typeinfo);static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);static void printtup_cleanup(DestReceiver *self);/* ---------------------------------------------------------------- *		printtup / debugtup support * ---------------------------------------------------------------- *//* ---------------- *		getTypeOutAndElem -- get both typoutput and typelem for a type * * We used to fetch these with two separate function calls, * typtoout() and gettypelem(), which each called SearchSysCacheTuple. * This way takes half the time. * ---------------- */intgetTypeOutAndElem(Oid type, Oid *typOutput, Oid *typElem){	HeapTuple	typeTuple;	typeTuple = SearchSysCacheTuple(TYPOID,									ObjectIdGetDatum(type),									0, 0, 0);	if (HeapTupleIsValid(typeTuple))	{		Form_pg_type pt = (Form_pg_type) GETSTRUCT(typeTuple);		*typOutput = (Oid) pt->typoutput;		*typElem = (Oid) pt->typelem;		return OidIsValid(*typOutput);	}	elog(ERROR, "getTypeOutAndElem: Cache lookup of type %u failed", type);	*typOutput = InvalidOid;	*typElem = InvalidOid;	return 0;}/* ---------------- *		Private state for a printtup destination object * ---------------- */typedef struct{								/* Per-attribute information */	Oid			typoutput;		/* Oid for the attribute's type output fn */	Oid			typelem;		/* typelem value to pass to the output fn */	FmgrInfo	finfo;			/* Precomputed call info for typoutput */} PrinttupAttrInfo;typedef struct{	DestReceiver pub;			/* publicly-known function pointers */	TupleDesc	attrinfo;		/* The attr info we are set up for */	int			nattrs;	PrinttupAttrInfo *myinfo;	/* Cached info about each attr */} DR_printtup;/* ---------------- *		Initialize: create a DestReceiver for printtup * ---------------- */DestReceiver *printtup_create_DR(){	DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup));	self->pub.receiveTuple = printtup;	self->pub.setup = printtup_setup;	self->pub.cleanup = printtup_cleanup;	self->attrinfo = NULL;	self->nattrs = 0;	self->myinfo = NULL;	return (DestReceiver *) self;}static voidprinttup_setup(DestReceiver *self, TupleDesc typeinfo){	/* ----------------	 * We could set up the derived attr info at this time, but we postpone it	 * until the first call of printtup, for 3 reasons:	 * 1. We don't waste time (compared to the old way) if there are no	 *	  tuples at all to output.	 * 2. Checking in printtup allows us to handle the case that the tuples	 *	  change type midway through (although this probably can't happen in	 *	  the current executor).	 * 3. Right now, ExecutorRun passes a NULL for typeinfo anyway :-(	 * ----------------	 */}static voidprinttup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs){	int			i;	if (myState->myinfo)		pfree(myState->myinfo); /* get rid of any old data */	myState->myinfo = NULL;	myState->attrinfo = typeinfo;	myState->nattrs = numAttrs;	if (numAttrs <= 0)		return;	myState->myinfo = (PrinttupAttrInfo *)		palloc(numAttrs * sizeof(PrinttupAttrInfo));	for (i = 0; i < numAttrs; i++)	{		PrinttupAttrInfo *thisState = myState->myinfo + i;		if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,							  &thisState->typoutput, &thisState->typelem))			fmgr_info(thisState->typoutput, &thisState->finfo);	}}/* ---------------- *		printtup * ---------------- */static voidprinttup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self){	DR_printtup *myState = (DR_printtup *) self;	StringInfoData buf;	int			i,				j,				k;	char	   *outputstr;	Datum		attr;	bool		isnull;	/* Set or update my derived attribute info, if needed */	if (myState->attrinfo != typeinfo ||		myState->nattrs != tuple->t_data->t_natts)		printtup_prepare_info(myState, typeinfo, tuple->t_data->t_natts);	/* ----------------	 *	tell the frontend to expect new tuple data (in ASCII style)	 * ----------------	 */	pq_beginmessage(&buf);	pq_sendbyte(&buf, 'D');	/* ----------------	 *	send a bitmap of which attributes are not null	 * ----------------	 */	j = 0;	k = 1 << 7;	for (i = 0; i < tuple->t_data->t_natts; ++i)	{		if (!heap_attisnull(tuple, i + 1))			j |= k;				/* set bit if not null */		k >>= 1;		if (k == 0)				/* end of byte? */		{			pq_sendint(&buf, j, 1);			j = 0;			k = 1 << 7;		}	}	if (k != (1 << 7))			/* flush last partial byte */		pq_sendint(&buf, j, 1);	/* ----------------	 *	send the attributes of this tuple	 * ----------------	 */	for (i = 0; i < tuple->t_data->t_natts; ++i)	{		PrinttupAttrInfo *thisState = myState->myinfo + i;		attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);		if (isnull)			continue;		if (OidIsValid(thisState->typoutput))		{			outputstr = (char *) (*fmgr_faddr(&thisState->finfo))				(attr, thisState->typelem, typeinfo->attrs[i]->atttypmod);			pq_sendcountedtext(&buf, outputstr, strlen(outputstr));			pfree(outputstr);		}		else		{			outputstr = "<unprintable>";			pq_sendcountedtext(&buf, outputstr, strlen(outputstr));		}	}	pq_endmessage(&buf);}/* ---------------- *		printtup_cleanup * ---------------- */static voidprinttup_cleanup(DestReceiver *self){	DR_printtup *myState = (DR_printtup *) self;	if (myState->myinfo)		pfree(myState->myinfo);	pfree(myState);}/* ---------------- *		printatt * ---------------- */static voidprintatt(unsigned attributeId,		 Form_pg_attribute attributeP,		 char *value){	printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, typmod = %d, byval = %c)\n",		   attributeId,		   attributeP->attname.data,		   value != NULL ? " = \"" : "",		   value != NULL ? value : "",		   value != NULL ? "\"" : "",		   (unsigned int) (attributeP->atttypid),		   attributeP->attlen,		   attributeP->atttypmod,		   attributeP->attbyval ? 't' : 'f');}/* ---------------- *		showatts * ---------------- */voidshowatts(char *name, TupleDesc tupleDesc){	int			i;	int			natts = tupleDesc->natts;	Form_pg_attribute *attinfo = tupleDesc->attrs;	puts(name);	for (i = 0; i < natts; ++i)		printatt((unsigned) i + 1, attinfo[i], (char *) NULL);	printf("\t----\n");}/* ---------------- *		debugtup * ---------------- */voiddebugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self){	int			i;	Datum		attr;	char	   *value;	bool		isnull;	Oid			typoutput,				typelem;	for (i = 0; i < tuple->t_data->t_natts; ++i)	{		attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);		if (isnull)			continue;		if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,							  &typoutput, &typelem))		{			value = fmgr(typoutput, attr, typelem,						 typeinfo->attrs[i]->atttypmod);			printatt((unsigned) i + 1, typeinfo->attrs[i], value);			pfree(value);		}	}	printf("\t----\n");}/* ---------------- *		printtup_internal *		We use a different data prefix, e.g. 'B' instead of 'D' to *		indicate a tuple in internal (binary) form. * *		This is same as printtup, except we don't use the typout func, *		and therefore have no need for persistent state. * ---------------- */voidprinttup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self){	StringInfoData buf;	int			i,				j,				k;	Datum		attr;	bool		isnull;	/* ----------------	 *	tell the frontend to expect new tuple data (in binary style)	 * ----------------	 */	pq_beginmessage(&buf);	pq_sendbyte(&buf, 'B');	/* ----------------	 *	send a bitmap of which attributes are not null	 * ----------------	 */	j = 0;	k = 1 << 7;	for (i = 0; i < tuple->t_data->t_natts; ++i)	{		if (!heap_attisnull(tuple, i + 1))			j |= k;				/* set bit if not null */		k >>= 1;		if (k == 0)				/* end of byte? */		{			pq_sendint(&buf, j, 1);			j = 0;			k = 1 << 7;		}	}	if (k != (1 << 7))			/* flush last partial byte */		pq_sendint(&buf, j, 1);	/* ----------------	 *	send the attributes of this tuple	 * ----------------	 */#ifdef IPORTAL_DEBUG	fprintf(stderr, "sending tuple with %d atts\n", tuple->t_data->t_natts);#endif	for (i = 0; i < tuple->t_data->t_natts; ++i)	{		int32		len = typeinfo->attrs[i]->attlen;		attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);		if (!isnull)		{			/* # of bytes, and opaque data */			if (len == -1)			{				/* variable length, assume a varlena structure */				len = VARSIZE(attr) - VARHDRSZ;				pq_sendint(&buf, len, VARHDRSZ);				pq_sendbytes(&buf, VARDATA(attr), len);#ifdef IPORTAL_DEBUG				{					char	   *d = VARDATA(attr);					fprintf(stderr, "length %d data %x%x%x%x\n",							len, *d, *(d + 1), *(d + 2), *(d + 3));				}#endif			}			else			{				/* fixed size */				if (typeinfo->attrs[i]->attbyval)				{					int8		i8;					int16		i16;					int32		i32;					pq_sendint(&buf, len, sizeof(int32));					switch (len)					{						case sizeof(int8):							i8 = DatumGetChar(attr);							pq_sendbytes(&buf, (char *) &i8, len);							break;						case sizeof(int16):							i16 = DatumGetInt16(attr);							pq_sendbytes(&buf, (char *) &i16, len);							break;						case sizeof(int32):							i32 = DatumGetInt32(attr);							pq_sendbytes(&buf, (char *) &i32, len);							break;					}#ifdef IPORTAL_DEBUG					fprintf(stderr, "byval length %d data %d\n", len, attr);#endif				}				else				{					pq_sendint(&buf, len, sizeof(int32));					pq_sendbytes(&buf, DatumGetPointer(attr), len);#ifdef IPORTAL_DEBUG					fprintf(stderr, "byref length %d data %x\n", len,							DatumGetPointer(attr));#endif				}			}		}	}	pq_endmessage(&buf);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -