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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * indextuple.c
  4.  *    This file contains index tuple accessor and mutator routines,
  5.  *    as well as a few various tuple utilities.
  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/indextuple.c,v 1.33.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/itup.h"
  18. #include "catalog/pg_type.h"
  19. /* ----------------------------------------------------------------
  20.  *   index_ tuple interface routines
  21.  * ----------------------------------------------------------------
  22.  */
  23. /* ----------------
  24.  * index_formtuple
  25.  * ----------------
  26.  */
  27. IndexTuple
  28. index_formtuple(TupleDesc tupleDescriptor,
  29. Datum *value,
  30. char *null)
  31. {
  32. char    *tp; /* tuple pointer */
  33. IndexTuple tuple; /* return tuple */
  34. Size size,
  35. hoff;
  36. int i;
  37. unsigned short infomask = 0;
  38. bool hasnull = false;
  39. uint16 tupmask = 0;
  40. int numberOfAttributes = tupleDescriptor->natts;
  41. if (numberOfAttributes > MaxIndexAttributeNumber)
  42. elog(ERROR, "index_formtuple: numberOfAttributes of %d > %d",
  43.  numberOfAttributes, MaxIndexAttributeNumber);
  44. for (i = 0; i < numberOfAttributes && !hasnull; i++)
  45. {
  46. if (null[i] != ' ')
  47. hasnull = true;
  48. }
  49. if (hasnull)
  50. infomask |= INDEX_NULL_MASK;
  51. hoff = IndexInfoFindDataOffset(infomask);
  52. size = hoff + ComputeDataSize(tupleDescriptor, value, null);
  53. size = MAXALIGN(size); /* be conservative */
  54. tp = (char *) palloc(size);
  55. tuple = (IndexTuple) tp;
  56. MemSet(tp, 0, (int) size);
  57. DataFill((char *) tp + hoff,
  58.  tupleDescriptor,
  59.  value,
  60.  null,
  61.  &tupmask,
  62.  (hasnull ? (bits8 *) tp + sizeof(*tuple) : NULL));
  63. /*
  64.  * We do this because DataFill wants to initialize a "tupmask" which
  65.  * is used for HeapTuples, but we want an indextuple infomask. The
  66.  * only "relevent" info is the "has variable attributes" field, which
  67.  * is in mask position 0x02.  We have already set the null mask above.
  68.  */
  69. if (tupmask & 0x02)
  70. infomask |= INDEX_VAR_MASK;
  71. /*
  72.  * Here we make sure that we can actually hold the size.  We also want
  73.  * to make sure that size is not aligned oddly.  This actually is a
  74.  * rather odd way to make sure the size is not too large overall.
  75.  */
  76. if (size & 0xE000)
  77. elog(ERROR, "index_formtuple: data takes %d bytes: too big", size);
  78. infomask |= size;
  79. /* ----------------
  80.  * initialize metadata
  81.  * ----------------
  82.  */
  83. tuple->t_info = infomask;
  84. return tuple;
  85. }
  86. /* ----------------
  87.  * nocache_index_getattr
  88.  *
  89.  * This gets called from index_getattr() macro, and only in cases
  90.  * where we can't use cacheoffset and the value is not null.
  91.  *
  92.  * This caches attribute offsets in the attribute descriptor.
  93.  *
  94.  * an alternate way to speed things up would be to cache offsets
  95.  * with the tuple, but that seems more difficult unless you take
  96.  * the storage hit of actually putting those offsets into the
  97.  * tuple you send to disk.  Yuck.
  98.  *
  99.  * This scheme will be slightly slower than that, but should
  100.  * preform well for queries which hit large #'s of tuples.  After
  101.  * you cache the offsets once, examining all the other tuples using
  102.  * the same attribute descriptor will go much quicker. -cim 5/4/91
  103.  * ----------------
  104.  */
  105. Datum
  106. nocache_index_getattr(IndexTuple tup,
  107.   int attnum,
  108.   TupleDesc tupleDesc,
  109.   bool *isnull)
  110. {
  111. char    *tp; /* ptr to att in tuple */
  112. char    *bp = NULL; /* ptr to att in tuple */
  113. int slow; /* do we have to walk nulls? */
  114. int data_off; /* tuple data offset */
  115. Form_pg_attribute *att = tupleDesc->attrs;
  116. /* ----------------
  117.  * sanity checks
  118.  * ----------------
  119.  */
  120. /* ----------------
  121.  *  Three cases:
  122.  *
  123.  *  1: No nulls and no variable length attributes.
  124.  *  2: Has a null or a varlena AFTER att.
  125.  *  3: Has nulls or varlenas BEFORE att.
  126.  * ----------------
  127.  */
  128. #ifdef IN_MACRO
  129. /* This is handled in the macro */
  130. Assert(PointerIsValid(isnull));
  131. Assert(attnum > 0);
  132. *isnull = false;
  133. #endif
  134. data_off = IndexTupleHasMinHeader(tup) ? sizeof *tup :
  135. IndexInfoFindDataOffset(tup->t_info);
  136. if (IndexTupleNoNulls(tup))
  137. {
  138. attnum--;
  139. #ifdef IN_MACRO
  140. /* This is handled in the macro */
  141. /* first attribute is always at position zero */
  142. if (attnum == 1)
  143. return (Datum) fetchatt(&(att[0]), (char *) tup + data_off);
  144. if (att[attnum]->attcacheoff != -1)
  145. {
  146. return (Datum) fetchatt(&(att[attnum]),
  147. (char *) tup + data_off +
  148. att[attnum]->attcacheoff);
  149. }
  150. #endif
  151. slow = 0;
  152. }
  153. else
  154. { /* there's a null somewhere in the tuple */
  155. slow = 0;
  156. /* ----------------
  157.  * check to see if desired att is null
  158.  * ----------------
  159.  */
  160. attnum--;
  161. bp = (char *) tup + sizeof(*tup); /* "knows" t_bits are
  162.  * here! */
  163. #ifdef IN_MACRO
  164. /* This is handled in the macro */
  165. if (att_isnull(attnum, bp))
  166. {
  167. *isnull = true;
  168. return (Datum) NULL;
  169. }
  170. #endif
  171. /* ----------------
  172.  * Now check to see if any preceeding bits are null...
  173.  * ----------------
  174.  */
  175. {
  176. int i = 0; /* current offset in bp */
  177. int mask; /* bit in byte we're looking at */
  178. char n; /* current byte in bp */
  179. int byte,
  180. finalbit;
  181. byte = attnum >> 3;
  182. finalbit = attnum & 0x07;
  183. for (; i <= byte && !slow; i++)
  184. {
  185. n = bp[i];
  186. if (i < byte)
  187. {
  188. /* check for nulls in any "earlier" bytes */
  189. if ((~n) != 0)
  190. slow = 1;
  191. }
  192. else
  193. {
  194. /* check for nulls "before" final bit of last byte */
  195. mask = (1 << finalbit) - 1;
  196. if ((~n) & mask)
  197. slow = 1;
  198. }
  199. }
  200. }
  201. }
  202. tp = (char *) tup + data_off;
  203. /* now check for any non-fixed length attrs before our attribute */
  204. if (!slow)
  205. {
  206. if (att[attnum]->attcacheoff != -1)
  207. {
  208. return (Datum) fetchatt(&(att[attnum]),
  209. tp + att[attnum]->attcacheoff);
  210. }
  211. else if (attnum == 0)
  212. return (Datum) fetchatt(&(att[0]), (char *) tp);
  213. else if (!IndexTupleAllFixed(tup))
  214. {
  215. int j = 0;
  216. for (j = 0; j < attnum && !slow; j++)
  217. if (att[j]->attlen < 1 && !VARLENA_FIXED_SIZE(att[j]))
  218. slow = 1;
  219. }
  220. }
  221. /*
  222.  * if slow is zero, and we got here, we know that we have a tuple with
  223.  * no nulls.  We also know that we have to initialize the remainder of
  224.  * the attribute cached offset values.
  225.  */
  226. if (!slow)
  227. {
  228. int j = 1;
  229. long off;
  230. /*
  231.  * need to set cache for some atts
  232.  */
  233. att[0]->attcacheoff = 0;
  234. while (att[j]->attcacheoff != -1)
  235. j++;
  236. if (!VARLENA_FIXED_SIZE(att[j - 1]))
  237. off = att[j - 1]->attcacheoff + att[j - 1]->attlen;
  238. else
  239. off = att[j - 1]->attcacheoff + att[j - 1]->atttypmod;
  240. for (; j < attnum + 1; j++)
  241. {
  242. /*
  243.  * Fix me when going to a machine with more than a four-byte
  244.  * word!
  245.  */
  246. off = att_align(off, att[j]->attlen, att[j]->attalign);
  247. att[j]->attcacheoff = off;
  248. /* The only varlena/-1 length value to get here is this */
  249. if (!VARLENA_FIXED_SIZE(att[j]))
  250. off += att[j]->attlen;
  251. else
  252. {
  253. Assert(att[j]->atttypmod == VARSIZE(tp + off));
  254. off += att[j]->atttypmod;
  255. }
  256. }
  257. return (Datum) fetchatt(&(att[attnum]), tp + att[attnum]->attcacheoff);
  258. }
  259. else
  260. {
  261. bool usecache = true;
  262. int off = 0;
  263. int i;
  264. /*
  265.  * Now we know that we have to walk the tuple CAREFULLY.
  266.  */
  267. for (i = 0; i < attnum; i++)
  268. {
  269. if (!IndexTupleNoNulls(tup))
  270. {
  271. if (att_isnull(i, bp))
  272. {
  273. usecache = false;
  274. continue;
  275. }
  276. }
  277. /* If we know the next offset, we can skip the rest */
  278. if (usecache && att[i]->attcacheoff != -1)
  279. off = att[i]->attcacheoff;
  280. else
  281. {
  282. off = att_align(off, att[i]->attlen, att[i]->attalign);
  283. if (usecache)
  284. att[i]->attcacheoff = off;
  285. }
  286. switch (att[i]->attlen)
  287. {
  288. case sizeof(char):
  289. off++;
  290. break;
  291. case sizeof(short):
  292. off += sizeof(short);
  293. break;
  294. case sizeof(int32):
  295. off += sizeof(int32);
  296. break;
  297. case -1:
  298. Assert(!VARLENA_FIXED_SIZE(att[i]) ||
  299.    att[i]->atttypmod == VARSIZE(tp + off));
  300. off += VARSIZE(tp + off);
  301. if (!VARLENA_FIXED_SIZE(att[i]))
  302. usecache = false;
  303. break;
  304. default:
  305. off += att[i]->attlen;
  306. break;
  307. }
  308. }
  309. off = att_align(off, att[attnum]->attlen, att[attnum]->attalign);
  310. return (Datum) fetchatt(&att[attnum], tp + off);
  311. }
  312. }
  313. RetrieveIndexResult
  314. FormRetrieveIndexResult(ItemPointer indexItemPointer,
  315. ItemPointer heapItemPointer)
  316. {
  317. RetrieveIndexResult result;
  318. Assert(ItemPointerIsValid(indexItemPointer));
  319. Assert(ItemPointerIsValid(heapItemPointer));
  320. result = (RetrieveIndexResult) palloc(sizeof *result);
  321. result->index_iptr = *indexItemPointer;
  322. result->heap_iptr = *heapItemPointer;
  323. return result;
  324. }
  325. /*
  326.  * Copies source into target.  If *target == NULL, we palloc space; otherwise
  327.  * we assume we have space that is already palloc'ed.
  328.  */
  329. void
  330. CopyIndexTuple(IndexTuple source, IndexTuple *target)
  331. {
  332. Size size;
  333. IndexTuple ret;
  334. size = IndexTupleSize(source);
  335. if (*target == NULL)
  336. *target = (IndexTuple) palloc(size);
  337. ret = *target;
  338. memmove((char *) ret, (char *) source, size);
  339. }