printtup.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:10k
- /*-------------------------------------------------------------------------
- *
- * 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.
- * ----------------
- */
- int
- getTypeOutAndElem(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 void
- printtup_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 void
- printtup_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 void
- printtup(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 void
- printtup_cleanup(DestReceiver *self)
- {
- DR_printtup *myState = (DR_printtup *) self;
- if (myState->myinfo)
- pfree(myState->myinfo);
- pfree(myState);
- }
- /* ----------------
- * printatt
- * ----------------
- */
- static void
- printatt(unsigned attributeId,
- Form_pg_attribute attributeP,
- char *value)
- {
- printf("t%2d: %s%s%s%st(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
- * ----------------
- */
- void
- showatts(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
- * ----------------
- */
- void
- debugtup(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.
- * ----------------
- */
- void
- printtup_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 attsn", 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%xn",
- 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 %dn", 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 %xn", len,
- DatumGetPointer(attr));
- #endif
- }
- }
- }
- }
- pq_endmessage(&buf);
- }