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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * gistget.c
  4.  *   fetch tuples from a GiST scan.
  5.  *
  6.  *
  7.  *
  8.  * IDENTIFICATION
  9.  *   /usr/local/devel/pglite/cvs/src/backend/access/gisr/gistget.c,v 1.9.1 1996/11/21 01:00:00 vadim Exp
  10.  *
  11.  *-------------------------------------------------------------------------
  12.  */
  13. #include "postgres.h"
  14. #include "access/gist.h"
  15. #include "executor/execdebug.h"
  16. static OffsetNumber gistfindnext(IndexScanDesc s, Page p, OffsetNumber n,
  17.  ScanDirection dir);
  18. static RetrieveIndexResult gistscancache(IndexScanDesc s, ScanDirection dir);
  19. static RetrieveIndexResult gistfirst(IndexScanDesc s, ScanDirection dir);
  20. static RetrieveIndexResult gistnext(IndexScanDesc s, ScanDirection dir);
  21. static ItemPointer gistheapptr(Relation r, ItemPointer itemp);
  22. static bool gistindex_keytest(IndexTuple tuple, TupleDesc tupdesc,
  23.   int scanKeySize, ScanKey key, GISTSTATE *giststate,
  24.   Relation r, Page p, OffsetNumber offset);
  25. RetrieveIndexResult
  26. gistgettuple(IndexScanDesc s, ScanDirection dir)
  27. {
  28. RetrieveIndexResult res;
  29. /* if we have it cached in the scan desc, just return the value */
  30. if ((res = gistscancache(s, dir)) != (RetrieveIndexResult) NULL)
  31. return res;
  32. /* not cached, so we'll have to do some work */
  33. if (ItemPointerIsValid(&(s->currentItemData)))
  34. res = gistnext(s, dir);
  35. else
  36. res = gistfirst(s, dir);
  37. return res;
  38. }
  39. static RetrieveIndexResult
  40. gistfirst(IndexScanDesc s, ScanDirection dir)
  41. {
  42. Buffer b;
  43. Page p;
  44. OffsetNumber n;
  45. OffsetNumber maxoff;
  46. RetrieveIndexResult res;
  47. GISTPageOpaque po;
  48. GISTScanOpaque so;
  49. GISTSTACK  *stk;
  50. BlockNumber blk;
  51. IndexTuple it;
  52. b = ReadBuffer(s->relation, GISTP_ROOT);
  53. p = BufferGetPage(b);
  54. po = (GISTPageOpaque) PageGetSpecialPointer(p);
  55. so = (GISTScanOpaque) s->opaque;
  56. for (;;)
  57. {
  58. maxoff = PageGetMaxOffsetNumber(p);
  59. if (ScanDirectionIsBackward(dir))
  60. n = gistfindnext(s, p, maxoff, dir);
  61. else
  62. n = gistfindnext(s, p, FirstOffsetNumber, dir);
  63. while (n < FirstOffsetNumber || n > maxoff)
  64. {
  65. ReleaseBuffer(b);
  66. if (so->s_stack == (GISTSTACK *) NULL)
  67. return (RetrieveIndexResult) NULL;
  68. stk = so->s_stack;
  69. b = ReadBuffer(s->relation, stk->gs_blk);
  70. p = BufferGetPage(b);
  71. po = (GISTPageOpaque) PageGetSpecialPointer(p);
  72. maxoff = PageGetMaxOffsetNumber(p);
  73. if (ScanDirectionIsBackward(dir))
  74. n = OffsetNumberPrev(stk->gs_child);
  75. else
  76. n = OffsetNumberNext(stk->gs_child);
  77. so->s_stack = stk->gs_parent;
  78. pfree(stk);
  79. n = gistfindnext(s, p, n, dir);
  80. }
  81. if (po->flags & F_LEAF)
  82. {
  83. ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
  84. it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
  85. res = FormRetrieveIndexResult(&(s->currentItemData), &(it->t_tid));
  86. ReleaseBuffer(b);
  87. return res;
  88. }
  89. else
  90. {
  91. stk = (GISTSTACK *) palloc(sizeof(GISTSTACK));
  92. stk->gs_child = n;
  93. stk->gs_blk = BufferGetBlockNumber(b);
  94. stk->gs_parent = so->s_stack;
  95. so->s_stack = stk;
  96. it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
  97. blk = ItemPointerGetBlockNumber(&(it->t_tid));
  98. ReleaseBuffer(b);
  99. b = ReadBuffer(s->relation, blk);
  100. p = BufferGetPage(b);
  101. po = (GISTPageOpaque) PageGetSpecialPointer(p);
  102. }
  103. }
  104. }
  105. static RetrieveIndexResult
  106. gistnext(IndexScanDesc s, ScanDirection dir)
  107. {
  108. Buffer b;
  109. Page p;
  110. OffsetNumber n;
  111. OffsetNumber maxoff;
  112. RetrieveIndexResult res;
  113. GISTPageOpaque po;
  114. GISTScanOpaque so;
  115. GISTSTACK  *stk;
  116. BlockNumber blk;
  117. IndexTuple it;
  118. blk = ItemPointerGetBlockNumber(&(s->currentItemData));
  119. n = ItemPointerGetOffsetNumber(&(s->currentItemData));
  120. if (ScanDirectionIsForward(dir))
  121. n = OffsetNumberNext(n);
  122. else
  123. n = OffsetNumberPrev(n);
  124. b = ReadBuffer(s->relation, blk);
  125. p = BufferGetPage(b);
  126. po = (GISTPageOpaque) PageGetSpecialPointer(p);
  127. so = (GISTScanOpaque) s->opaque;
  128. for (;;)
  129. {
  130. maxoff = PageGetMaxOffsetNumber(p);
  131. n = gistfindnext(s, p, n, dir);
  132. while (n < FirstOffsetNumber || n > maxoff)
  133. {
  134. ReleaseBuffer(b);
  135. if (so->s_stack == (GISTSTACK *) NULL)
  136. return (RetrieveIndexResult) NULL;
  137. stk = so->s_stack;
  138. b = ReadBuffer(s->relation, stk->gs_blk);
  139. p = BufferGetPage(b);
  140. maxoff = PageGetMaxOffsetNumber(p);
  141. po = (GISTPageOpaque) PageGetSpecialPointer(p);
  142. if (ScanDirectionIsBackward(dir))
  143. n = OffsetNumberPrev(stk->gs_child);
  144. else
  145. n = OffsetNumberNext(stk->gs_child);
  146. so->s_stack = stk->gs_parent;
  147. pfree(stk);
  148. n = gistfindnext(s, p, n, dir);
  149. }
  150. if (po->flags & F_LEAF)
  151. {
  152. ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
  153. it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
  154. res = FormRetrieveIndexResult(&(s->currentItemData), &(it->t_tid));
  155. ReleaseBuffer(b);
  156. return res;
  157. }
  158. else
  159. {
  160. stk = (GISTSTACK *) palloc(sizeof(GISTSTACK));
  161. stk->gs_child = n;
  162. stk->gs_blk = BufferGetBlockNumber(b);
  163. stk->gs_parent = so->s_stack;
  164. so->s_stack = stk;
  165. it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
  166. blk = ItemPointerGetBlockNumber(&(it->t_tid));
  167. ReleaseBuffer(b);
  168. b = ReadBuffer(s->relation, blk);
  169. p = BufferGetPage(b);
  170. po = (GISTPageOpaque) PageGetSpecialPointer(p);
  171. if (ScanDirectionIsBackward(dir))
  172. n = PageGetMaxOffsetNumber(p);
  173. else
  174. n = FirstOffsetNumber;
  175. }
  176. }
  177. }
  178. /* Similar to index_keytest, but decompresses the key in the IndexTuple */
  179. static bool
  180. gistindex_keytest(IndexTuple tuple,
  181.   TupleDesc tupdesc,
  182.   int scanKeySize,
  183.   ScanKey key,
  184.   GISTSTATE *giststate,
  185.   Relation r,
  186.   Page p,
  187.   OffsetNumber offset)
  188. {
  189. bool isNull;
  190. Datum datum;
  191. int test;
  192. GISTENTRY de;
  193. IncrIndexProcessed();
  194. while (scanKeySize > 0)
  195. {
  196. datum = index_getattr(tuple,
  197.   1,
  198.   tupdesc,
  199.   &isNull);
  200. gistdentryinit(giststate, &de, (char *) datum, r, p, offset,
  201.    IndexTupleSize(tuple) - sizeof(IndexTupleData),
  202.    FALSE);
  203. if (isNull)
  204. {
  205. /* XXX eventually should check if SK_ISNULL */
  206. return false;
  207. }
  208. if (key[0].sk_flags & SK_COMMUTE)
  209. {
  210. test = (*fmgr_faddr(&key[0].sk_func))
  211. (DatumGetPointer(key[0].sk_argument),
  212.  &de, key[0].sk_procedure) ? 1 : 0;
  213. }
  214. else
  215. {
  216. test = (*fmgr_faddr(&key[0].sk_func))
  217. (&de,
  218.  DatumGetPointer(key[0].sk_argument),
  219.  key[0].sk_procedure) ? 1 : 0;
  220. }
  221. if (!test == !(key[0].sk_flags & SK_NEGATE))
  222. return false;
  223. scanKeySize -= 1;
  224. key++;
  225. }
  226. return true;
  227. }
  228. static OffsetNumber
  229. gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir)
  230. {
  231. OffsetNumber maxoff;
  232. char    *it;
  233. GISTPageOpaque po;
  234. GISTScanOpaque so;
  235. GISTSTATE  *giststate;
  236. maxoff = PageGetMaxOffsetNumber(p);
  237. po = (GISTPageOpaque) PageGetSpecialPointer(p);
  238. so = (GISTScanOpaque) s->opaque;
  239. giststate = so->giststate;
  240. /*
  241.  * If we modified the index during the scan, we may have a pointer to
  242.  * a ghost tuple, before the scan. If this is the case, back up one.
  243.  */
  244. if (so->s_flags & GS_CURBEFORE)
  245. {
  246. so->s_flags &= ~GS_CURBEFORE;
  247. n = OffsetNumberPrev(n);
  248. }
  249. while (n >= FirstOffsetNumber && n <= maxoff)
  250. {
  251. it = (char *) PageGetItem(p, PageGetItemId(p, n));
  252. if (gistindex_keytest((IndexTuple) it,
  253.   RelationGetDescr(s->relation),
  254.   s->numberOfKeys, s->keyData, giststate,
  255.   s->relation, p, n))
  256. break;
  257. if (ScanDirectionIsBackward(dir))
  258. n = OffsetNumberPrev(n);
  259. else
  260. n = OffsetNumberNext(n);
  261. }
  262. return n;
  263. }
  264. static RetrieveIndexResult
  265. gistscancache(IndexScanDesc s, ScanDirection dir)
  266. {
  267. RetrieveIndexResult res;
  268. ItemPointer ip;
  269. if (!(ScanDirectionIsNoMovement(dir)
  270.   && ItemPointerIsValid(&(s->currentItemData))))
  271. {
  272. return (RetrieveIndexResult) NULL;
  273. }
  274. ip = gistheapptr(s->relation, &(s->currentItemData));
  275. if (ItemPointerIsValid(ip))
  276. res = FormRetrieveIndexResult(&(s->currentItemData), ip);
  277. else
  278. res = (RetrieveIndexResult) NULL;
  279. pfree(ip);
  280. return res;
  281. }
  282. /*
  283.  * gistheapptr returns the item pointer to the tuple in the heap relation
  284.  * for which itemp is the index relation item pointer.
  285.  */
  286. static ItemPointer
  287. gistheapptr(Relation r, ItemPointer itemp)
  288. {
  289. Buffer b;
  290. Page p;
  291. IndexTuple it;
  292. ItemPointer ip;
  293. OffsetNumber n;
  294. ip = (ItemPointer) palloc(sizeof(ItemPointerData));
  295. if (ItemPointerIsValid(itemp))
  296. {
  297. b = ReadBuffer(r, ItemPointerGetBlockNumber(itemp));
  298. p = BufferGetPage(b);
  299. n = ItemPointerGetOffsetNumber(itemp);
  300. it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
  301. memmove((char *) ip, (char *) &(it->t_tid),
  302. sizeof(ItemPointerData));
  303. ReleaseBuffer(b);
  304. }
  305. else
  306. ItemPointerSetInvalid(ip);
  307. return ip;
  308. }