printtup.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:10k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * printtup.c
  4.  *   Routines to print out tuples to the destination (binary or non-binary
  5.  *   portals, frontend/interactive backend, etc.).
  6.  *
  7.  * Copyright (c) 1994, Regents of the University of California
  8.  *
  9.  *
  10.  * IDENTIFICATION
  11.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.47.2.1 1999/08/02 05:24:25 scrappy Exp $
  12.  *
  13.  *-------------------------------------------------------------------------
  14.  */
  15. #include "postgres.h"
  16. #include "access/heapam.h"
  17. #include "access/printtup.h"
  18. #include "catalog/pg_type.h"
  19. #include "libpq/pqformat.h"
  20. #include "utils/syscache.h"
  21. static void printtup_setup(DestReceiver *self, TupleDesc typeinfo);
  22. static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
  23. static void printtup_cleanup(DestReceiver *self);
  24. /* ----------------------------------------------------------------
  25.  * printtup / debugtup support
  26.  * ----------------------------------------------------------------
  27.  */
  28. /* ----------------
  29.  * getTypeOutAndElem -- get both typoutput and typelem for a type
  30.  *
  31.  * We used to fetch these with two separate function calls,
  32.  * typtoout() and gettypelem(), which each called SearchSysCacheTuple.
  33.  * This way takes half the time.
  34.  * ----------------
  35.  */
  36. int
  37. getTypeOutAndElem(Oid type, Oid *typOutput, Oid *typElem)
  38. {
  39. HeapTuple typeTuple;
  40. typeTuple = SearchSysCacheTuple(TYPOID,
  41. ObjectIdGetDatum(type),
  42. 0, 0, 0);
  43. if (HeapTupleIsValid(typeTuple))
  44. {
  45. Form_pg_type pt = (Form_pg_type) GETSTRUCT(typeTuple);
  46. *typOutput = (Oid) pt->typoutput;
  47. *typElem = (Oid) pt->typelem;
  48. return OidIsValid(*typOutput);
  49. }
  50. elog(ERROR, "getTypeOutAndElem: Cache lookup of type %u failed", type);
  51. *typOutput = InvalidOid;
  52. *typElem = InvalidOid;
  53. return 0;
  54. }
  55. /* ----------------
  56.  * Private state for a printtup destination object
  57.  * ----------------
  58.  */
  59. typedef struct
  60. { /* Per-attribute information */
  61. Oid typoutput; /* Oid for the attribute's type output fn */
  62. Oid typelem; /* typelem value to pass to the output fn */
  63. FmgrInfo finfo; /* Precomputed call info for typoutput */
  64. } PrinttupAttrInfo;
  65. typedef struct
  66. {
  67. DestReceiver pub; /* publicly-known function pointers */
  68. TupleDesc attrinfo; /* The attr info we are set up for */
  69. int nattrs;
  70. PrinttupAttrInfo *myinfo; /* Cached info about each attr */
  71. } DR_printtup;
  72. /* ----------------
  73.  * Initialize: create a DestReceiver for printtup
  74.  * ----------------
  75.  */
  76. DestReceiver *
  77. printtup_create_DR()
  78. {
  79. DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup));
  80. self->pub.receiveTuple = printtup;
  81. self->pub.setup = printtup_setup;
  82. self->pub.cleanup = printtup_cleanup;
  83. self->attrinfo = NULL;
  84. self->nattrs = 0;
  85. self->myinfo = NULL;
  86. return (DestReceiver *) self;
  87. }
  88. static void
  89. printtup_setup(DestReceiver *self, TupleDesc typeinfo)
  90. {
  91. /* ----------------
  92.  * We could set up the derived attr info at this time, but we postpone it
  93.  * until the first call of printtup, for 3 reasons:
  94.  * 1. We don't waste time (compared to the old way) if there are no
  95.  *   tuples at all to output.
  96.  * 2. Checking in printtup allows us to handle the case that the tuples
  97.  *   change type midway through (although this probably can't happen in
  98.  *   the current executor).
  99.  * 3. Right now, ExecutorRun passes a NULL for typeinfo anyway :-(
  100.  * ----------------
  101.  */
  102. }
  103. static void
  104. printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
  105. {
  106. int i;
  107. if (myState->myinfo)
  108. pfree(myState->myinfo); /* get rid of any old data */
  109. myState->myinfo = NULL;
  110. myState->attrinfo = typeinfo;
  111. myState->nattrs = numAttrs;
  112. if (numAttrs <= 0)
  113. return;
  114. myState->myinfo = (PrinttupAttrInfo *)
  115. palloc(numAttrs * sizeof(PrinttupAttrInfo));
  116. for (i = 0; i < numAttrs; i++)
  117. {
  118. PrinttupAttrInfo *thisState = myState->myinfo + i;
  119. if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
  120.   &thisState->typoutput, &thisState->typelem))
  121. fmgr_info(thisState->typoutput, &thisState->finfo);
  122. }
  123. }
  124. /* ----------------
  125.  * printtup
  126.  * ----------------
  127.  */
  128. static void
  129. printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
  130. {
  131. DR_printtup *myState = (DR_printtup *) self;
  132. StringInfoData buf;
  133. int i,
  134. j,
  135. k;
  136. char    *outputstr;
  137. Datum attr;
  138. bool isnull;
  139. /* Set or update my derived attribute info, if needed */
  140. if (myState->attrinfo != typeinfo ||
  141. myState->nattrs != tuple->t_data->t_natts)
  142. printtup_prepare_info(myState, typeinfo, tuple->t_data->t_natts);
  143. /* ----------------
  144.  * tell the frontend to expect new tuple data (in ASCII style)
  145.  * ----------------
  146.  */
  147. pq_beginmessage(&buf);
  148. pq_sendbyte(&buf, 'D');
  149. /* ----------------
  150.  * send a bitmap of which attributes are not null
  151.  * ----------------
  152.  */
  153. j = 0;
  154. k = 1 << 7;
  155. for (i = 0; i < tuple->t_data->t_natts; ++i)
  156. {
  157. if (!heap_attisnull(tuple, i + 1))
  158. j |= k; /* set bit if not null */
  159. k >>= 1;
  160. if (k == 0) /* end of byte? */
  161. {
  162. pq_sendint(&buf, j, 1);
  163. j = 0;
  164. k = 1 << 7;
  165. }
  166. }
  167. if (k != (1 << 7)) /* flush last partial byte */
  168. pq_sendint(&buf, j, 1);
  169. /* ----------------
  170.  * send the attributes of this tuple
  171.  * ----------------
  172.  */
  173. for (i = 0; i < tuple->t_data->t_natts; ++i)
  174. {
  175. PrinttupAttrInfo *thisState = myState->myinfo + i;
  176. attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
  177. if (isnull)
  178. continue;
  179. if (OidIsValid(thisState->typoutput))
  180. {
  181. outputstr = (char *) (*fmgr_faddr(&thisState->finfo))
  182. (attr, thisState->typelem, typeinfo->attrs[i]->atttypmod);
  183. pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
  184. pfree(outputstr);
  185. }
  186. else
  187. {
  188. outputstr = "<unprintable>";
  189. pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
  190. }
  191. }
  192. pq_endmessage(&buf);
  193. }
  194. /* ----------------
  195.  * printtup_cleanup
  196.  * ----------------
  197.  */
  198. static void
  199. printtup_cleanup(DestReceiver *self)
  200. {
  201. DR_printtup *myState = (DR_printtup *) self;
  202. if (myState->myinfo)
  203. pfree(myState->myinfo);
  204. pfree(myState);
  205. }
  206. /* ----------------
  207.  * printatt
  208.  * ----------------
  209.  */
  210. static void
  211. printatt(unsigned attributeId,
  212.  Form_pg_attribute attributeP,
  213.  char *value)
  214. {
  215. printf("t%2d: %s%s%s%st(typeid = %u, len = %d, typmod = %d, byval = %c)n",
  216.    attributeId,
  217.    attributeP->attname.data,
  218.    value != NULL ? " = "" : "",
  219.    value != NULL ? value : "",
  220.    value != NULL ? """ : "",
  221.    (unsigned int) (attributeP->atttypid),
  222.    attributeP->attlen,
  223.    attributeP->atttypmod,
  224.    attributeP->attbyval ? 't' : 'f');
  225. }
  226. /* ----------------
  227.  * showatts
  228.  * ----------------
  229.  */
  230. void
  231. showatts(char *name, TupleDesc tupleDesc)
  232. {
  233. int i;
  234. int natts = tupleDesc->natts;
  235. Form_pg_attribute *attinfo = tupleDesc->attrs;
  236. puts(name);
  237. for (i = 0; i < natts; ++i)
  238. printatt((unsigned) i + 1, attinfo[i], (char *) NULL);
  239. printf("t----n");
  240. }
  241. /* ----------------
  242.  * debugtup
  243.  * ----------------
  244.  */
  245. void
  246. debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
  247. {
  248. int i;
  249. Datum attr;
  250. char    *value;
  251. bool isnull;
  252. Oid typoutput,
  253. typelem;
  254. for (i = 0; i < tuple->t_data->t_natts; ++i)
  255. {
  256. attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
  257. if (isnull)
  258. continue;
  259. if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
  260.   &typoutput, &typelem))
  261. {
  262. value = fmgr(typoutput, attr, typelem,
  263.  typeinfo->attrs[i]->atttypmod);
  264. printatt((unsigned) i + 1, typeinfo->attrs[i], value);
  265. pfree(value);
  266. }
  267. }
  268. printf("t----n");
  269. }
  270. /* ----------------
  271.  * printtup_internal
  272.  * We use a different data prefix, e.g. 'B' instead of 'D' to
  273.  * indicate a tuple in internal (binary) form.
  274.  *
  275.  * This is same as printtup, except we don't use the typout func,
  276.  * and therefore have no need for persistent state.
  277.  * ----------------
  278.  */
  279. void
  280. printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
  281. {
  282. StringInfoData buf;
  283. int i,
  284. j,
  285. k;
  286. Datum attr;
  287. bool isnull;
  288. /* ----------------
  289.  * tell the frontend to expect new tuple data (in binary style)
  290.  * ----------------
  291.  */
  292. pq_beginmessage(&buf);
  293. pq_sendbyte(&buf, 'B');
  294. /* ----------------
  295.  * send a bitmap of which attributes are not null
  296.  * ----------------
  297.  */
  298. j = 0;
  299. k = 1 << 7;
  300. for (i = 0; i < tuple->t_data->t_natts; ++i)
  301. {
  302. if (!heap_attisnull(tuple, i + 1))
  303. j |= k; /* set bit if not null */
  304. k >>= 1;
  305. if (k == 0) /* end of byte? */
  306. {
  307. pq_sendint(&buf, j, 1);
  308. j = 0;
  309. k = 1 << 7;
  310. }
  311. }
  312. if (k != (1 << 7)) /* flush last partial byte */
  313. pq_sendint(&buf, j, 1);
  314. /* ----------------
  315.  * send the attributes of this tuple
  316.  * ----------------
  317.  */
  318. #ifdef IPORTAL_DEBUG
  319. fprintf(stderr, "sending tuple with %d attsn", tuple->t_data->t_natts);
  320. #endif
  321. for (i = 0; i < tuple->t_data->t_natts; ++i)
  322. {
  323. int32 len = typeinfo->attrs[i]->attlen;
  324. attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
  325. if (!isnull)
  326. {
  327. /* # of bytes, and opaque data */
  328. if (len == -1)
  329. {
  330. /* variable length, assume a varlena structure */
  331. len = VARSIZE(attr) - VARHDRSZ;
  332. pq_sendint(&buf, len, VARHDRSZ);
  333. pq_sendbytes(&buf, VARDATA(attr), len);
  334. #ifdef IPORTAL_DEBUG
  335. {
  336. char    *d = VARDATA(attr);
  337. fprintf(stderr, "length %d data %x%x%x%xn",
  338. len, *d, *(d + 1), *(d + 2), *(d + 3));
  339. }
  340. #endif
  341. }
  342. else
  343. {
  344. /* fixed size */
  345. if (typeinfo->attrs[i]->attbyval)
  346. {
  347. int8 i8;
  348. int16 i16;
  349. int32 i32;
  350. pq_sendint(&buf, len, sizeof(int32));
  351. switch (len)
  352. {
  353. case sizeof(int8):
  354. i8 = DatumGetChar(attr);
  355. pq_sendbytes(&buf, (char *) &i8, len);
  356. break;
  357. case sizeof(int16):
  358. i16 = DatumGetInt16(attr);
  359. pq_sendbytes(&buf, (char *) &i16, len);
  360. break;
  361. case sizeof(int32):
  362. i32 = DatumGetInt32(attr);
  363. pq_sendbytes(&buf, (char *) &i32, len);
  364. break;
  365. }
  366. #ifdef IPORTAL_DEBUG
  367. fprintf(stderr, "byval length %d data %dn", len, attr);
  368. #endif
  369. }
  370. else
  371. {
  372. pq_sendint(&buf, len, sizeof(int32));
  373. pq_sendbytes(&buf, DatumGetPointer(attr), len);
  374. #ifdef IPORTAL_DEBUG
  375. fprintf(stderr, "byref length %d data %xn", len,
  376. DatumGetPointer(attr));
  377. #endif
  378. }
  379. }
  380. }
  381. }
  382. pq_endmessage(&buf);
  383. }