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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * heapam.c
  4.  *   heap access method code
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.46.2.1 1999/08/02 05:56:36 scrappy Exp $
  11.  *
  12.  *
  13.  * INTERFACE ROUTINES
  14.  * heapgettup - fetch next heap tuple from a scan
  15.  * heap_open - open a heap relation by relationId
  16.  * heap_openr - open a heap relation by name
  17.  * heap_close - close a heap relation
  18.  * heap_beginscan - begin relation scan
  19.  * heap_rescan - restart a relation scan
  20.  * heap_endscan - end relation scan
  21.  * heap_getnext - retrieve next tuple in scan
  22.  * heap_fetch - retrive tuple with tid
  23.  * heap_insert - insert tuple into a relation
  24.  * heap_delete - delete a tuple from a relation
  25.  * heap_replace - replace a tuple in a relation with another tuple
  26.  * heap_markpos - mark scan position
  27.  * heap_restrpos - restore position to marked location
  28.  *
  29.  * NOTES
  30.  *   This file contains the heap_ routines which implement
  31.  *   the POSTGRES heap access method used for all POSTGRES
  32.  *   relations.
  33.  *
  34.  * OLD COMMENTS
  35.  * struct relscan hints:  (struct should be made AM independent?)
  36.  *
  37.  * rs_ctid is the tid of the last tuple returned by getnext.
  38.  * rs_ptid and rs_ntid are the tids of the previous and next tuples
  39.  * returned by getnext, respectively. NULL indicates an end of
  40.  * scan (either direction); NON indicates an unknow value.
  41.  *
  42.  * possible combinations:
  43.  * rs_p rs_c rs_n interpretation
  44.  * NULL NULL NULL empty scan
  45.  * NULL NULL NON at begining of scan
  46.  * NULL NULL t1 at begining of scan (with cached tid)
  47.  * NON NULL NULL at end of scan
  48.  * t1 NULL NULL at end of scan (with cached tid)
  49.  * NULL t1 NULL just returned only tuple
  50.  * NULL t1 NON just returned first tuple
  51.  * NULL t1 t2 returned first tuple (with cached tid)
  52.  * NON t1 NULL just returned last tuple
  53.  * t2 t1 NULL returned last tuple (with cached tid)
  54.  * t1 t2 NON in the middle of a forward scan
  55.  * NON t2 t1 in the middle of a reverse scan
  56.  * ti tj tk in the middle of a scan (w cached tid)
  57.  *
  58.  * Here NULL is ...tup == NULL && ...buf == InvalidBuffer,
  59.  * and NON is ...tup == NULL && ...buf == UnknownBuffer.
  60.  *
  61.  * Currently, the NONTID values are not cached with their actual
  62.  * values by getnext. Values may be cached by markpos since it stores
  63.  * all three tids.
  64.  *
  65.  * NOTE:  the calls to elog() must stop.  Should decide on an interface
  66.  * between the general and specific AM calls.
  67.  *
  68.  * XXX probably do not need a free tuple routine for heaps.
  69.  * Huh?  Free tuple is not necessary for tuples returned by scans, but
  70.  * is necessary for tuples which are returned by
  71.  * RelationGetTupleByItemPointer. -hirohama
  72.  *
  73.  *-------------------------------------------------------------------------
  74.  */
  75. #include "postgres.h"
  76. #include "access/heapam.h"
  77. #include "access/hio.h"
  78. #include "access/valid.h"
  79. #include "catalog/catalog.h"
  80. #include "miscadmin.h"
  81. #include "storage/smgr.h"
  82. #include "utils/builtins.h"
  83. #include "utils/inval.h"
  84. #include "utils/relcache.h"
  85. /* ----------------------------------------------------------------
  86.  *  heap support routines
  87.  * ----------------------------------------------------------------
  88.  */
  89. /* ----------------
  90.  * initscan - scan code common to heap_beginscan and heap_rescan
  91.  * ----------------
  92.  */
  93. static void
  94. initscan(HeapScanDesc scan,
  95.  Relation relation,
  96.  int atend,
  97.  unsigned nkeys,
  98.  ScanKey key)
  99. {
  100. if (!RelationGetNumberOfBlocks(relation))
  101. {
  102. /* ----------------
  103.  * relation is empty
  104.  * ----------------
  105.  */
  106. scan->rs_ntup.t_data = scan->rs_ctup.t_data =
  107. scan->rs_ptup.t_data = NULL;
  108. scan->rs_nbuf = scan->rs_cbuf = scan->rs_pbuf = InvalidBuffer;
  109. }
  110. else if (atend)
  111. {
  112. /* ----------------
  113.  * reverse scan
  114.  * ----------------
  115.  */
  116. scan->rs_ntup.t_data = scan->rs_ctup.t_data = NULL;
  117. scan->rs_nbuf = scan->rs_cbuf = InvalidBuffer;
  118. scan->rs_ptup.t_data = NULL;
  119. scan->rs_pbuf = UnknownBuffer;
  120. }
  121. else
  122. {
  123. /* ----------------
  124.  * forward scan
  125.  * ----------------
  126.  */
  127. scan->rs_ctup.t_data = scan->rs_ptup.t_data = NULL;
  128. scan->rs_cbuf = scan->rs_pbuf = InvalidBuffer;
  129. scan->rs_ntup.t_data = NULL;
  130. scan->rs_nbuf = UnknownBuffer;
  131. } /* invalid too */
  132. /* we don't have a marked position... */
  133. ItemPointerSetInvalid(&(scan->rs_mptid));
  134. ItemPointerSetInvalid(&(scan->rs_mctid));
  135. ItemPointerSetInvalid(&(scan->rs_mntid));
  136. ItemPointerSetInvalid(&(scan->rs_mcd));
  137. /* ----------------
  138.  * copy the scan key, if appropriate
  139.  * ----------------
  140.  */
  141. if (key != NULL)
  142. memmove(scan->rs_key, key, nkeys * sizeof(ScanKeyData));
  143. }
  144. /* ----------------
  145.  * unpinscan - code common to heap_rescan and heap_endscan
  146.  * ----------------
  147.  */
  148. static void
  149. unpinscan(HeapScanDesc scan)
  150. {
  151. if (BufferIsValid(scan->rs_pbuf))
  152. ReleaseBuffer(scan->rs_pbuf);
  153. /* ------------------------------------
  154.  * Scan will pin buffer one for each non-NULL tuple pointer
  155.  * (ptup, ctup, ntup), so they have to be unpinned multiple
  156.  * times.
  157.  * ------------------------------------
  158.  */
  159. if (BufferIsValid(scan->rs_cbuf))
  160. ReleaseBuffer(scan->rs_cbuf);
  161. if (BufferIsValid(scan->rs_nbuf))
  162. ReleaseBuffer(scan->rs_nbuf);
  163. }
  164. /* ------------------------------------------
  165.  * nextpage
  166.  *
  167.  * figure out the next page to scan after the current page
  168.  * taking into account of possible adjustment of degrees of
  169.  * parallelism
  170.  * ------------------------------------------
  171.  */
  172. static int
  173. nextpage(int page, int dir)
  174. {
  175. return (dir < 0) ? page - 1 : page + 1;
  176. }
  177. /* ----------------
  178.  * heapgettup - fetch next heap tuple
  179.  *
  180.  * routine used by heap_getnext() which does most of the
  181.  * real work in scanning tuples.
  182.  *
  183.  * The scan routines handle their own buffer lock/unlocking, so
  184.  * there is no reason to request the buffer number unless
  185.  * to want to perform some other operation with the result,
  186.  * like pass it to another function.
  187.  * ----------------
  188.  */
  189. static void
  190. heapgettup(Relation relation,
  191.    HeapTuple tuple,
  192.    int dir,
  193.    Buffer *buffer,
  194.    Snapshot snapshot,
  195.    int nkeys,
  196.    ScanKey key)
  197. {
  198. ItemId lpp;
  199. Page dp;
  200. int page;
  201. int pages;
  202. int lines;
  203. OffsetNumber lineoff;
  204. int linesleft;
  205. ItemPointer tid = (tuple->t_data == NULL) ?
  206. (ItemPointer) NULL : &(tuple->t_self);
  207. /* ----------------
  208.  * increment access statistics
  209.  * ----------------
  210.  */
  211. IncrHeapAccessStat(local_heapgettup);
  212. IncrHeapAccessStat(global_heapgettup);
  213. /* ----------------
  214.  * debugging stuff
  215.  *
  216.  * check validity of arguments, here and for other functions too
  217.  * Note: no locking manipulations needed--this is a local function
  218.  * ----------------
  219.  */
  220. #ifdef HEAPDEBUGALL
  221. if (ItemPointerIsValid(tid))
  222. {
  223. elog(DEBUG, "heapgettup(%s, tid=0x%x[%d,%d], dir=%d, ...)",
  224.  RelationGetRelationName(relation), tid, tid->ip_blkid,
  225.  tid->ip_posid, dir);
  226. }
  227. else
  228. {
  229. elog(DEBUG, "heapgettup(%s, tid=0x%x, dir=%d, ...)",
  230.  RelationGetRelationName(relation), tid, dir);
  231. }
  232. elog(DEBUG, "heapgettup(..., b=0x%x, nkeys=%d, key=0x%x", buffer, nkeys, key);
  233. elog(DEBUG, "heapgettup: relation(%c)=`%s', %p",
  234.  relation->rd_rel->relkind, &relation->rd_rel->relname,
  235.  snapshot);
  236. #endif  /* !defined(HEAPDEBUGALL) */
  237. if (!ItemPointerIsValid(tid))
  238. Assert(!PointerIsValid(tid));
  239. /* ----------------
  240.  * return null immediately if relation is empty
  241.  * ----------------
  242.  */
  243. if (!(pages = relation->rd_nblocks))
  244. {
  245. tuple->t_data = NULL;
  246. return;
  247. }
  248. /* ----------------
  249.  * calculate next starting lineoff, given scan direction
  250.  * ----------------
  251.  */
  252. if (!dir)
  253. {
  254. /* ----------------
  255.  * ``no movement'' scan direction
  256.  * ----------------
  257.  */
  258. /* assume it is a valid TID XXX */
  259. if (ItemPointerIsValid(tid) == false)
  260. {
  261. *buffer = InvalidBuffer;
  262. tuple->t_data = NULL;
  263. return;
  264. }
  265. *buffer = RelationGetBufferWithBuffer(relation,
  266.   ItemPointerGetBlockNumber(tid),
  267.   *buffer);
  268. if (!BufferIsValid(*buffer))
  269. elog(ERROR, "heapgettup: failed ReadBuffer");
  270. LockBuffer(*buffer, BUFFER_LOCK_SHARE);
  271. dp = (Page) BufferGetPage(*buffer);
  272. lineoff = ItemPointerGetOffsetNumber(tid);
  273. lpp = PageGetItemId(dp, lineoff);
  274. tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
  275. tuple->t_len = ItemIdGetLength(lpp);
  276. LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
  277. return;
  278. }
  279. else if (dir < 0)
  280. {
  281. /* ----------------
  282.  * reverse scan direction
  283.  * ----------------
  284.  */
  285. if (ItemPointerIsValid(tid) == false)
  286. tid = NULL;
  287. if (tid == NULL)
  288. {
  289. page = pages - 1; /* final page */
  290. }
  291. else
  292. {
  293. page = ItemPointerGetBlockNumber(tid); /* current page */
  294. }
  295. if (page < 0)
  296. {
  297. *buffer = InvalidBuffer;
  298. tuple->t_data = NULL;
  299. return;
  300. }
  301. *buffer = RelationGetBufferWithBuffer(relation, page, *buffer);
  302. if (!BufferIsValid(*buffer))
  303. elog(ERROR, "heapgettup: failed ReadBuffer");
  304. LockBuffer(*buffer, BUFFER_LOCK_SHARE);
  305. dp = (Page) BufferGetPage(*buffer);
  306. lines = PageGetMaxOffsetNumber(dp);
  307. if (tid == NULL)
  308. {
  309. lineoff = lines; /* final offnum */
  310. }
  311. else
  312. {
  313. lineoff = /* previous offnum */
  314. OffsetNumberPrev(ItemPointerGetOffsetNumber(tid));
  315. }
  316. /* page and lineoff now reference the physically previous tid */
  317. }
  318. else
  319. {
  320. /* ----------------
  321.  * forward scan direction
  322.  * ----------------
  323.  */
  324. if (ItemPointerIsValid(tid) == false)
  325. {
  326. page = 0; /* first page */
  327. lineoff = FirstOffsetNumber; /* first offnum */
  328. }
  329. else
  330. {
  331. page = ItemPointerGetBlockNumber(tid); /* current page */
  332. lineoff = /* next offnum */
  333. OffsetNumberNext(ItemPointerGetOffsetNumber(tid));
  334. }
  335. if (page >= pages)
  336. {
  337. *buffer = InvalidBuffer;
  338. tuple->t_data = NULL;
  339. return;
  340. }
  341. /* page and lineoff now reference the physically next tid */
  342. *buffer = RelationGetBufferWithBuffer(relation, page, *buffer);
  343. if (!BufferIsValid(*buffer))
  344. elog(ERROR, "heapgettup: failed ReadBuffer");
  345. LockBuffer(*buffer, BUFFER_LOCK_SHARE);
  346. dp = (Page) BufferGetPage(*buffer);
  347. lines = PageGetMaxOffsetNumber(dp);
  348. }
  349. /* 'dir' is now non-zero */
  350. /* ----------------
  351.  * calculate line pointer and number of remaining items
  352.  * to check on this page.
  353.  * ----------------
  354.  */
  355. lpp = PageGetItemId(dp, lineoff);
  356. if (dir < 0)
  357. linesleft = lineoff - 1;
  358. else
  359. linesleft = lines - lineoff;
  360. /* ----------------
  361.  * advance the scan until we find a qualifying tuple or
  362.  * run out of stuff to scan
  363.  * ----------------
  364.  */
  365. for (;;)
  366. {
  367. while (linesleft >= 0)
  368. {
  369. if (ItemIdIsUsed(lpp))
  370. {
  371. tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
  372. tuple->t_len = ItemIdGetLength(lpp);
  373. ItemPointerSet(&(tuple->t_self), page, lineoff);
  374. /* ----------------
  375.  * if current tuple qualifies, return it.
  376.  * ----------------
  377.  */
  378. HeapTupleSatisfies(tuple, relation, *buffer, (PageHeader) dp,
  379.    snapshot, nkeys, key);
  380. if (tuple->t_data != NULL)
  381. {
  382. LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
  383. return;
  384. }
  385. }
  386. /* ----------------
  387.  * otherwise move to the next item on the page
  388.  * ----------------
  389.  */
  390. --linesleft;
  391. if (dir < 0)
  392. {
  393. --lpp; /* move back in this page's ItemId array */
  394. --lineoff;
  395. }
  396. else
  397. {
  398. ++lpp; /* move forward in this page's ItemId
  399.  * array */
  400. ++lineoff;
  401. }
  402. }
  403. /* ----------------
  404.  * if we get here, it means we've exhausted the items on
  405.  * this page and it's time to move to the next..
  406.  * ----------------
  407.  */
  408. LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
  409. page = nextpage(page, dir);
  410. /* ----------------
  411.  * return NULL if we've exhausted all the pages..
  412.  * ----------------
  413.  */
  414. if (page < 0 || page >= pages)
  415. {
  416. if (BufferIsValid(*buffer))
  417. ReleaseBuffer(*buffer);
  418. *buffer = InvalidBuffer;
  419. tuple->t_data = NULL;
  420. return;
  421. }
  422. *buffer = ReleaseAndReadBuffer(*buffer, relation, page);
  423. if (!BufferIsValid(*buffer))
  424. elog(ERROR, "heapgettup: failed ReadBuffer");
  425. LockBuffer(*buffer, BUFFER_LOCK_SHARE);
  426. dp = (Page) BufferGetPage(*buffer);
  427. lines = PageGetMaxOffsetNumber((Page) dp);
  428. linesleft = lines - 1;
  429. if (dir < 0)
  430. {
  431. lineoff = lines;
  432. lpp = PageGetItemId(dp, lines);
  433. }
  434. else
  435. {
  436. lineoff = FirstOffsetNumber;
  437. lpp = PageGetItemId(dp, FirstOffsetNumber);
  438. }
  439. }
  440. }
  441. /* ----------------------------------------------------------------
  442.  *  heap access method interface
  443.  * ----------------------------------------------------------------
  444.  */
  445. /* ----------------
  446.  * heap_open - open a heap relation by relationId
  447.  *
  448.  * presently the relcache routines do all the work we need
  449.  * to open/close heap relations.
  450.  * ----------------
  451.  */
  452. Relation
  453. heap_open(Oid relationId)
  454. {
  455. Relation r;
  456. /* ----------------
  457.  * increment access statistics
  458.  * ----------------
  459.  */
  460. IncrHeapAccessStat(local_open);
  461. IncrHeapAccessStat(global_open);
  462. r = (Relation) RelationIdGetRelation(relationId);
  463. if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX)
  464. elog(ERROR, "%s is an index relation", r->rd_rel->relname.data);
  465. return r;
  466. }
  467. /* ----------------
  468.  * heap_openr - open a heap relation by name
  469.  *
  470.  * presently the relcache routines do all the work we need
  471.  * to open/close heap relations.
  472.  * ----------------
  473.  */
  474. Relation
  475. heap_openr(char *relationName)
  476. {
  477. Relation r;
  478. /* ----------------
  479.  * increment access statistics
  480.  * ----------------
  481.  */
  482. IncrHeapAccessStat(local_openr);
  483. IncrHeapAccessStat(global_openr);
  484. r = RelationNameGetRelation(relationName);
  485. if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX)
  486. elog(ERROR, "%s is an index relation", r->rd_rel->relname.data);
  487. return r;
  488. }
  489. /* ----------------
  490.  * heap_close - close a heap relation
  491.  *
  492.  * presently the relcache routines do all the work we need
  493.  * to open/close heap relations.
  494.  * ----------------
  495.  */
  496. void
  497. heap_close(Relation relation)
  498. {
  499. /* ----------------
  500.  * increment access statistics
  501.  * ----------------
  502.  */
  503. IncrHeapAccessStat(local_close);
  504. IncrHeapAccessStat(global_close);
  505. RelationClose(relation);
  506. }
  507. /* ----------------
  508.  * heap_beginscan - begin relation scan
  509.  * ----------------
  510.  */
  511. HeapScanDesc
  512. heap_beginscan(Relation relation,
  513.    int atend,
  514.    Snapshot snapshot,
  515.    unsigned nkeys,
  516.    ScanKey key)
  517. {
  518. HeapScanDesc scan;
  519. /* ----------------
  520.  * increment access statistics
  521.  * ----------------
  522.  */
  523. IncrHeapAccessStat(local_beginscan);
  524. IncrHeapAccessStat(global_beginscan);
  525. /* ----------------
  526.  * sanity checks
  527.  * ----------------
  528.  */
  529. if (RelationIsValid(relation) == false)
  530. elog(ERROR, "heap_beginscan: !RelationIsValid(relation)");
  531. LockRelation(relation, AccessShareLock);
  532. /* XXX someday assert SelfTimeQual if relkind == RELKIND_UNCATALOGED */
  533. if (relation->rd_rel->relkind == RELKIND_UNCATALOGED)
  534. snapshot = SnapshotSelf;
  535. /* ----------------
  536.  * increment relation ref count while scanning relation
  537.  * ----------------
  538.  */
  539. RelationIncrementReferenceCount(relation);
  540. /* ----------------
  541.  * allocate and initialize scan descriptor
  542.  * ----------------
  543.  */
  544. scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
  545. relation->rd_nblocks = smgrnblocks(DEFAULT_SMGR, relation);
  546. scan->rs_rd = relation;
  547. if (nkeys)
  548. /*
  549.  * we do this here instead of in initscan() because heap_rescan
  550.  * also calls initscan() and we don't want to allocate memory
  551.  * again
  552.  */
  553. scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
  554. else
  555. scan->rs_key = NULL;
  556. initscan(scan, relation, atend, nkeys, key);
  557. scan->rs_atend = atend;
  558. scan->rs_snapshot = snapshot;
  559. scan->rs_nkeys = (short) nkeys;
  560. return scan;
  561. }
  562. /* ----------------
  563.  * heap_rescan - restart a relation scan
  564.  * ----------------
  565.  */
  566. void
  567. heap_rescan(HeapScanDesc scan,
  568. bool scanFromEnd,
  569. ScanKey key)
  570. {
  571. /* ----------------
  572.  * increment access statistics
  573.  * ----------------
  574.  */
  575. IncrHeapAccessStat(local_rescan);
  576. IncrHeapAccessStat(global_rescan);
  577. /* Note: set relation level read lock is still set */
  578. /* ----------------
  579.  * unpin scan buffers
  580.  * ----------------
  581.  */
  582. unpinscan(scan);
  583. /* ----------------
  584.  * reinitialize scan descriptor
  585.  * ----------------
  586.  */
  587. initscan(scan, scan->rs_rd, scanFromEnd, scan->rs_nkeys, key);
  588. scan->rs_atend = (bool) scanFromEnd;
  589. }
  590. /* ----------------
  591.  * heap_endscan - end relation scan
  592.  *
  593.  * See how to integrate with index scans.
  594.  * Check handling if reldesc caching.
  595.  * ----------------
  596.  */
  597. void
  598. heap_endscan(HeapScanDesc scan)
  599. {
  600. /* ----------------
  601.  * increment access statistics
  602.  * ----------------
  603.  */
  604. IncrHeapAccessStat(local_endscan);
  605. IncrHeapAccessStat(global_endscan);
  606. /* Note: no locking manipulations needed */
  607. /* ----------------
  608.  * unpin scan buffers
  609.  * ----------------
  610.  */
  611. unpinscan(scan);
  612. /* ----------------
  613.  * decrement relation reference count and free scan descriptor storage
  614.  * ----------------
  615.  */
  616. RelationDecrementReferenceCount(scan->rs_rd);
  617. UnlockRelation(scan->rs_rd, AccessShareLock);
  618. pfree(scan); /* XXX */
  619. }
  620. /* ----------------
  621.  * heap_getnext - retrieve next tuple in scan
  622.  *
  623.  * Fix to work with index relations.
  624.  * We don't return the buffer anymore, but you can get it from the
  625.  * returned HeapTuple.
  626.  * ----------------
  627.  */
  628. #ifdef HEAPDEBUGALL
  629. #define HEAPDEBUG_1 
  630. elog(DEBUG, "heap_getnext([%s,nkeys=%d],backw=%d) called", 
  631.  scan->rs_rd->rd_rel->relname.data, scan->rs_nkeys, backw)
  632. #define HEAPDEBUG_2 
  633.  elog(DEBUG, "heap_getnext called with backw (no tracing yet)")
  634. #define HEAPDEBUG_3 
  635.  elog(DEBUG, "heap_getnext returns NULL at end")
  636. #define HEAPDEBUG_4 
  637.  elog(DEBUG, "heap_getnext valid buffer UNPIN'd")
  638. #define HEAPDEBUG_5 
  639.  elog(DEBUG, "heap_getnext next tuple was cached")
  640. #define HEAPDEBUG_6 
  641.  elog(DEBUG, "heap_getnext returning EOS")
  642. #define HEAPDEBUG_7 
  643.  elog(DEBUG, "heap_getnext returning tuple");
  644. #else
  645. #define HEAPDEBUG_1
  646. #define HEAPDEBUG_2
  647. #define HEAPDEBUG_3
  648. #define HEAPDEBUG_4
  649. #define HEAPDEBUG_5
  650. #define HEAPDEBUG_6
  651. #define HEAPDEBUG_7
  652. #endif  /* !defined(HEAPDEBUGALL) */
  653. HeapTuple
  654. heap_getnext(HeapScanDesc scandesc, int backw)
  655. {
  656. HeapScanDesc scan = scandesc;
  657. /* ----------------
  658.  * increment access statistics
  659.  * ----------------
  660.  */
  661. IncrHeapAccessStat(local_getnext);
  662. IncrHeapAccessStat(global_getnext);
  663. /* Note: no locking manipulations needed */
  664. /* ----------------
  665.  * argument checks
  666.  * ----------------
  667.  */
  668. if (scan == NULL)
  669. elog(ERROR, "heap_getnext: NULL relscan");
  670. /* ----------------
  671.  * initialize return buffer to InvalidBuffer
  672.  * ----------------
  673.  */
  674. HEAPDEBUG_1; /* heap_getnext( info ) */
  675. if (backw)
  676. {
  677. /* ----------------
  678.  * handle reverse scan
  679.  * ----------------
  680.  */
  681. HEAPDEBUG_2; /* heap_getnext called with backw */
  682. if (scan->rs_ptup.t_data == scan->rs_ctup.t_data &&
  683. BufferIsInvalid(scan->rs_pbuf))
  684. {
  685. if (BufferIsValid(scan->rs_nbuf))
  686. ReleaseBuffer(scan->rs_nbuf);
  687. return NULL;
  688. }
  689. /*
  690.  * Copy the "current" tuple/buffer to "next". Pin/unpin the
  691.  * buffers accordingly
  692.  */
  693. if (scan->rs_nbuf != scan->rs_cbuf)
  694. {
  695. if (BufferIsValid(scan->rs_nbuf))
  696. ReleaseBuffer(scan->rs_nbuf);
  697. if (BufferIsValid(scan->rs_cbuf))
  698. IncrBufferRefCount(scan->rs_cbuf);
  699. }
  700. scan->rs_ntup = scan->rs_ctup;
  701. scan->rs_nbuf = scan->rs_cbuf;
  702. if (scan->rs_ptup.t_data != NULL)
  703. {
  704. if (scan->rs_cbuf != scan->rs_pbuf)
  705. {
  706. if (BufferIsValid(scan->rs_cbuf))
  707. ReleaseBuffer(scan->rs_cbuf);
  708. if (BufferIsValid(scan->rs_pbuf))
  709. IncrBufferRefCount(scan->rs_pbuf);
  710. }
  711. scan->rs_ctup = scan->rs_ptup;
  712. scan->rs_cbuf = scan->rs_pbuf;
  713. }
  714. else
  715. { /* NONTUP */
  716. /*
  717.  * Don't release scan->rs_cbuf at this point, because
  718.  * heapgettup doesn't increase PrivateRefCount if it is
  719.  * already set. On a backward scan, both rs_ctup and rs_ntup
  720.  * usually point to the same buffer page, so
  721.  * PrivateRefCount[rs_cbuf] should be 2 (or more, if for
  722.  * instance ctup is stored in a TupleTableSlot).  - 01/09/94
  723.  */
  724. heapgettup(scan->rs_rd,
  725.    &(scan->rs_ctup),
  726.    -1,
  727.    &(scan->rs_cbuf),
  728.    scan->rs_snapshot,
  729.    scan->rs_nkeys,
  730.    scan->rs_key);
  731. }
  732. if (scan->rs_ctup.t_data == NULL && !BufferIsValid(scan->rs_cbuf))
  733. {
  734. if (BufferIsValid(scan->rs_pbuf))
  735. ReleaseBuffer(scan->rs_pbuf);
  736. scan->rs_ptup.t_data = NULL;
  737. scan->rs_pbuf = InvalidBuffer;
  738. if (BufferIsValid(scan->rs_nbuf))
  739. ReleaseBuffer(scan->rs_nbuf);
  740. scan->rs_ntup.t_data = NULL;
  741. scan->rs_nbuf = InvalidBuffer;
  742. return NULL;
  743. }
  744. if (BufferIsValid(scan->rs_pbuf))
  745. ReleaseBuffer(scan->rs_pbuf);
  746. scan->rs_ptup.t_data = NULL;
  747. scan->rs_pbuf = UnknownBuffer;
  748. }
  749. else
  750. {
  751. /* ----------------
  752.  * handle forward scan
  753.  * ----------------
  754.  */
  755. if (scan->rs_ctup.t_data == scan->rs_ntup.t_data &&
  756. BufferIsInvalid(scan->rs_nbuf))
  757. {
  758. if (BufferIsValid(scan->rs_pbuf))
  759. ReleaseBuffer(scan->rs_pbuf);
  760. HEAPDEBUG_3; /* heap_getnext returns NULL at end */
  761. return NULL;
  762. }
  763. /*
  764.  * Copy the "current" tuple/buffer to "previous". Pin/unpin the
  765.  * buffers accordingly
  766.  */
  767. if (scan->rs_pbuf != scan->rs_cbuf)
  768. {
  769. if (BufferIsValid(scan->rs_pbuf))
  770. ReleaseBuffer(scan->rs_pbuf);
  771. if (BufferIsValid(scan->rs_cbuf))
  772. IncrBufferRefCount(scan->rs_cbuf);
  773. }
  774. scan->rs_ptup = scan->rs_ctup;
  775. scan->rs_pbuf = scan->rs_cbuf;
  776. if (scan->rs_ntup.t_data != NULL)
  777. {
  778. if (scan->rs_cbuf != scan->rs_nbuf)
  779. {
  780. if (BufferIsValid(scan->rs_cbuf))
  781. ReleaseBuffer(scan->rs_cbuf);
  782. if (BufferIsValid(scan->rs_nbuf))
  783. IncrBufferRefCount(scan->rs_nbuf);
  784. }
  785. scan->rs_ctup = scan->rs_ntup;
  786. scan->rs_cbuf = scan->rs_nbuf;
  787. HEAPDEBUG_5; /* heap_getnext next tuple was cached */
  788. }
  789. else
  790. { /* NONTUP */
  791. /*
  792.  * Don't release scan->rs_cbuf at this point, because
  793.  * heapgettup doesn't increase PrivateRefCount if it is
  794.  * already set. On a forward scan, both rs_ctup and rs_ptup
  795.  * usually point to the same buffer page, so
  796.  * PrivateRefCount[rs_cbuf] should be 2 (or more, if for
  797.  * instance ctup is stored in a TupleTableSlot).  - 01/09/93
  798.  */
  799. heapgettup(scan->rs_rd,
  800.    &(scan->rs_ctup),
  801.    1,
  802.    &scan->rs_cbuf,
  803.    scan->rs_snapshot,
  804.    scan->rs_nkeys,
  805.    scan->rs_key);
  806. }
  807. if (scan->rs_ctup.t_data == NULL && !BufferIsValid(scan->rs_cbuf))
  808. {
  809. if (BufferIsValid(scan->rs_nbuf))
  810. ReleaseBuffer(scan->rs_nbuf);
  811. scan->rs_ntup.t_data = NULL;
  812. scan->rs_nbuf = InvalidBuffer;
  813. if (BufferIsValid(scan->rs_pbuf))
  814. ReleaseBuffer(scan->rs_pbuf);
  815. scan->rs_ptup.t_data = NULL;
  816. scan->rs_pbuf = InvalidBuffer;
  817. HEAPDEBUG_6; /* heap_getnext returning EOS */
  818. return NULL;
  819. }
  820. if (BufferIsValid(scan->rs_nbuf))
  821. ReleaseBuffer(scan->rs_nbuf);
  822. scan->rs_ntup.t_data = NULL;
  823. scan->rs_nbuf = UnknownBuffer;
  824. }
  825. /* ----------------
  826.  * if we get here it means we have a new current scan tuple, so
  827.  * point to the proper return buffer and return the tuple.
  828.  * ----------------
  829.  */
  830. HEAPDEBUG_7; /* heap_getnext returning tuple */
  831. return ((scan->rs_ctup.t_data == NULL) ? NULL : &(scan->rs_ctup));
  832. }
  833. /* ----------------
  834.  * heap_fetch - retrive tuple with tid
  835.  *
  836.  * Currently ignores LP_IVALID during processing!
  837.  *
  838.  * Because this is not part of a scan, there is no way to
  839.  * automatically lock/unlock the shared buffers.
  840.  * For this reason, we require that the user retrieve the buffer
  841.  * value, and they are required to BufferRelease() it when they
  842.  * are done.  If they want to make a copy of it before releasing it,
  843.  * they can call heap_copytyple().
  844.  * ----------------
  845.  */
  846. void
  847. heap_fetch(Relation relation,
  848.    Snapshot snapshot,
  849.    HeapTuple tuple,
  850.    Buffer *userbuf)
  851. {
  852. ItemId lp;
  853. Buffer buffer;
  854. PageHeader dp;
  855. ItemPointer tid = &(tuple->t_self);
  856. OffsetNumber offnum;
  857. AssertMacro(PointerIsValid(userbuf)); /* see comments above */
  858. /* ----------------
  859.  * increment access statistics
  860.  * ----------------
  861.  */
  862. IncrHeapAccessStat(local_fetch);
  863. IncrHeapAccessStat(global_fetch);
  864. /* ----------------
  865.  * get the buffer from the relation descriptor
  866.  * Note that this does a buffer pin.
  867.  * ----------------
  868.  */
  869. buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
  870. if (!BufferIsValid(buffer))
  871. elog(ERROR, "heap_fetch: %s relation: ReadBuffer(%lx) failed",
  872.  &relation->rd_rel->relname, (long) tid);
  873. LockBuffer(buffer, BUFFER_LOCK_SHARE);
  874. /* ----------------
  875.  * get the item line pointer corresponding to the requested tid
  876.  * ----------------
  877.  */
  878. dp = (PageHeader) BufferGetPage(buffer);
  879. offnum = ItemPointerGetOffsetNumber(tid);
  880. lp = PageGetItemId(dp, offnum);
  881. /* ----------------
  882.  * more sanity checks
  883.  * ----------------
  884.  */
  885. Assert(ItemIdIsUsed(lp));
  886. tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
  887. tuple->t_len = ItemIdGetLength(lp);
  888. /* ----------------
  889.  * check time qualification of tid
  890.  * ----------------
  891.  */
  892. HeapTupleSatisfies(tuple, relation, buffer, dp,
  893.    snapshot, 0, (ScanKey) NULL);
  894. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  895. if (tuple->t_data == NULL)
  896. {
  897. ReleaseBuffer(buffer);
  898. return;
  899. }
  900. /* ----------------
  901.  * all checks passed, now either return a copy of the tuple
  902.  * or pin the buffer page and return a pointer, depending on
  903.  * whether caller gave us a valid buf.
  904.  * ----------------
  905.  */
  906. *userbuf = buffer; /* user is required to ReleaseBuffer()
  907.  * this */
  908. return;
  909. }
  910. /* ----------------
  911.  * heap_insert - insert tuple
  912.  *
  913.  * The assignment of t_min (and thus the others) should be
  914.  * removed eventually.
  915.  *
  916.  * Currently places the tuple onto the last page. If there is no room,
  917.  * it is placed on new pages. (Heap relations)
  918.  * Note that concurrent inserts during a scan will probably have
  919.  * unexpected results, though this will be fixed eventually.
  920.  *
  921.  * Fix to work with indexes.
  922.  * ----------------
  923.  */
  924. Oid
  925. heap_insert(Relation relation, HeapTuple tup)
  926. {
  927. /* ----------------
  928.  * increment access statistics
  929.  * ----------------
  930.  */
  931. IncrHeapAccessStat(local_insert);
  932. IncrHeapAccessStat(global_insert);
  933. /* ----------------
  934.  * If the object id of this tuple has already been assigned, trust
  935.  * the caller.  There are a couple of ways this can happen.  At initial
  936.  * db creation, the backend program sets oids for tuples. When we
  937.  * define an index, we set the oid.  Finally, in the future, we may
  938.  * allow users to set their own object ids in order to support a
  939.  * persistent object store (objects need to contain pointers to one
  940.  * another).
  941.  * ----------------
  942.  */
  943. if (!OidIsValid(tup->t_data->t_oid))
  944. {
  945. tup->t_data->t_oid = newoid();
  946. LastOidProcessed = tup->t_data->t_oid;
  947. }
  948. else
  949. CheckMaxObjectId(tup->t_data->t_oid);
  950. TransactionIdStore(GetCurrentTransactionId(), &(tup->t_data->t_xmin));
  951. tup->t_data->t_cmin = GetCurrentCommandId();
  952. StoreInvalidTransactionId(&(tup->t_data->t_xmax));
  953. tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
  954. tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
  955. RelationPutHeapTupleAtEnd(relation, tup);
  956. if (IsSystemRelationName(RelationGetRelationName(relation)->data))
  957. RelationInvalidateHeapTuple(relation, tup);
  958. return tup->t_data->t_oid;
  959. }
  960. /*
  961.  * heap_delete - delete a tuple
  962.  */
  963. int
  964. heap_delete(Relation relation, ItemPointer tid, ItemPointer ctid)
  965. {
  966. ItemId lp;
  967. HeapTupleData tp;
  968. PageHeader dp;
  969. Buffer buffer;
  970. int result;
  971. /* increment access statistics */
  972. IncrHeapAccessStat(local_delete);
  973. IncrHeapAccessStat(global_delete);
  974. Assert(ItemPointerIsValid(tid));
  975. buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
  976. if (!BufferIsValid(buffer))
  977. elog(ERROR, "heap_delete: failed ReadBuffer");
  978. LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  979. dp = (PageHeader) BufferGetPage(buffer);
  980. lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
  981. tp.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
  982. tp.t_len = ItemIdGetLength(lp);
  983. tp.t_self = *tid;
  984. l1:
  985. result = HeapTupleSatisfiesUpdate(&tp);
  986. if (result == HeapTupleInvisible)
  987. {
  988. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  989. ReleaseBuffer(buffer);
  990. elog(ERROR, "heap_delete: (am)invalid tid");
  991. }
  992. else if (result == HeapTupleBeingUpdated)
  993. {
  994. TransactionId xwait = tp.t_data->t_xmax;
  995. /* sleep until concurrent transaction ends */
  996. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  997. XactLockTableWait(xwait);
  998. LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  999. if (TransactionIdDidAbort(xwait))
  1000. goto l1;
  1001. /* 
  1002.  * xwait is committed but if xwait had just marked
  1003.  * the tuple for update then some other xaction could 
  1004.  * update this tuple before we got to this point.
  1005.  */
  1006. if (tp.t_data->t_xmax != xwait)
  1007. goto l1;
  1008. if (!(tp.t_data->t_infomask & HEAP_XMAX_COMMITTED))
  1009. {
  1010. tp.t_data->t_infomask |= HEAP_XMAX_COMMITTED;
  1011. SetBufferCommitInfoNeedsSave(buffer);
  1012. }
  1013. /* if tuple was marked for update but not updated... */
  1014. if (tp.t_data->t_infomask & HEAP_MARKED_FOR_UPDATE)
  1015. result = HeapTupleMayBeUpdated;
  1016. else
  1017. result = HeapTupleUpdated;
  1018. }
  1019. if (result != HeapTupleMayBeUpdated)
  1020. {
  1021. Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated);
  1022. if (ctid != NULL)
  1023. *ctid = tp.t_data->t_ctid;
  1024. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  1025. ReleaseBuffer(buffer);
  1026. return result;
  1027. }
  1028. /* store transaction information of xact deleting the tuple */
  1029. TransactionIdStore(GetCurrentTransactionId(), &(tp.t_data->t_xmax));
  1030. tp.t_data->t_cmax = GetCurrentCommandId();
  1031. tp.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
  1032.  HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
  1033. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  1034. /* invalidate caches */
  1035. RelationInvalidateHeapTuple(relation, &tp);
  1036. WriteBuffer(buffer);
  1037. return HeapTupleMayBeUpdated;
  1038. }
  1039. /*
  1040.  * heap_replace - replace a tuple
  1041.  */
  1042. int
  1043. heap_replace(Relation relation, ItemPointer otid, HeapTuple newtup,
  1044.  ItemPointer ctid)
  1045. {
  1046. ItemId lp;
  1047. HeapTupleData oldtup;
  1048. PageHeader dp;
  1049. Buffer buffer;
  1050. int result;
  1051. /* increment access statistics */
  1052. IncrHeapAccessStat(local_replace);
  1053. IncrHeapAccessStat(global_replace);
  1054. Assert(ItemPointerIsValid(otid));
  1055. buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(otid));
  1056. if (!BufferIsValid(buffer))
  1057. elog(ERROR, "amreplace: failed ReadBuffer");
  1058. LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  1059. dp = (PageHeader) BufferGetPage(buffer);
  1060. lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(otid));
  1061. oldtup.t_data = (HeapTupleHeader) PageGetItem(dp, lp);
  1062. oldtup.t_len = ItemIdGetLength(lp);
  1063. oldtup.t_self = *otid;
  1064. l2:
  1065. result = HeapTupleSatisfiesUpdate(&oldtup);
  1066. if (result == HeapTupleInvisible)
  1067. {
  1068. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  1069. ReleaseBuffer(buffer);
  1070. elog(ERROR, "heap_replace: (am)invalid tid");
  1071. }
  1072. else if (result == HeapTupleBeingUpdated)
  1073. {
  1074. TransactionId xwait = oldtup.t_data->t_xmax;
  1075. /* sleep untill concurrent transaction ends */
  1076. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  1077. XactLockTableWait(xwait);
  1078. LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  1079. if (TransactionIdDidAbort(xwait))
  1080. goto l2;
  1081. /* 
  1082.  * xwait is committed but if xwait had just marked
  1083.  * the tuple for update then some other xaction could 
  1084.  * update this tuple before we got to this point.
  1085.  */
  1086. if (oldtup.t_data->t_xmax != xwait)
  1087. goto l2;
  1088. if (!(oldtup.t_data->t_infomask & HEAP_XMAX_COMMITTED))
  1089. {
  1090. oldtup.t_data->t_infomask |= HEAP_XMAX_COMMITTED;
  1091. SetBufferCommitInfoNeedsSave(buffer);
  1092. }
  1093. /* if tuple was marked for update but not updated... */
  1094. if (oldtup.t_data->t_infomask & HEAP_MARKED_FOR_UPDATE)
  1095. result = HeapTupleMayBeUpdated;
  1096. else
  1097. result = HeapTupleUpdated;
  1098. }
  1099. if (result != HeapTupleMayBeUpdated)
  1100. {
  1101. Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated);
  1102. if (ctid != NULL)
  1103. *ctid = oldtup.t_data->t_ctid;
  1104. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  1105. ReleaseBuffer(buffer);
  1106. return result;
  1107. }
  1108. /* XXX order problems if not atomic assignment ??? */
  1109. newtup->t_data->t_oid = oldtup.t_data->t_oid;
  1110. TransactionIdStore(GetCurrentTransactionId(), &(newtup->t_data->t_xmin));
  1111. newtup->t_data->t_cmin = GetCurrentCommandId();
  1112. StoreInvalidTransactionId(&(newtup->t_data->t_xmax));
  1113. newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
  1114. newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED);
  1115. /* logically delete old item */
  1116. TransactionIdStore(GetCurrentTransactionId(), &(oldtup.t_data->t_xmax));
  1117. oldtup.t_data->t_cmax = GetCurrentCommandId();
  1118. oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
  1119.  HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
  1120. /* insert new item */
  1121. if ((unsigned) MAXALIGN(newtup->t_len) <= PageGetFreeSpace((Page) dp))
  1122. RelationPutHeapTuple(relation, buffer, newtup);
  1123. else
  1124. {
  1125. /*
  1126.  * New item won't fit on same page as old item, have to look for a
  1127.  * new place to put it. Note that we have to unlock current buffer
  1128.  * context - not good but RelationPutHeapTupleAtEnd uses extend
  1129.  * lock.
  1130.  */
  1131. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  1132. RelationPutHeapTupleAtEnd(relation, newtup);
  1133. LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  1134. }
  1135. /*
  1136.  * New item in place, now record address of new tuple in t_ctid of old
  1137.  * one.
  1138.  */
  1139. oldtup.t_data->t_ctid = newtup->t_self;
  1140. LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  1141. /* invalidate caches */
  1142. RelationInvalidateHeapTuple(relation, &oldtup);
  1143. WriteBuffer(buffer);
  1144. return HeapTupleMayBeUpdated;
  1145. }
  1146. /*
  1147.  * heap_mark4update - mark a tuple for update
  1148.  */
  1149. int
  1150. heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer)
  1151. {
  1152. ItemPointer tid = &(tuple->t_self);
  1153. ItemId lp;
  1154. PageHeader dp;
  1155. int result;
  1156. /* increment access statistics */
  1157. IncrHeapAccessStat(local_mark4update);
  1158. IncrHeapAccessStat(global_mark4update);
  1159. *buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
  1160. if (!BufferIsValid(*buffer))
  1161. elog(ERROR, "heap_mark4update: failed ReadBuffer");
  1162. LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
  1163. dp = (PageHeader) BufferGetPage(*buffer);
  1164. lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
  1165. tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
  1166. tuple->t_len = ItemIdGetLength(lp);
  1167. l3:
  1168. result = HeapTupleSatisfiesUpdate(tuple);
  1169. if (result == HeapTupleInvisible)
  1170. {
  1171. LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
  1172. ReleaseBuffer(*buffer);
  1173. elog(ERROR, "heap_mark4update: (am)invalid tid");
  1174. }
  1175. else if (result == HeapTupleBeingUpdated)
  1176. {
  1177. TransactionId xwait = tuple->t_data->t_xmax;
  1178. /* sleep untill concurrent transaction ends */
  1179. LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
  1180. XactLockTableWait(xwait);
  1181. LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
  1182. if (TransactionIdDidAbort(xwait))
  1183. goto l3;
  1184. /* 
  1185.  * xwait is committed but if xwait had just marked
  1186.  * the tuple for update then some other xaction could 
  1187.  * update this tuple before we got to this point.
  1188.  */
  1189. if (tuple->t_data->t_xmax != xwait)
  1190. goto l3;
  1191. if (!(tuple->t_data->t_infomask & HEAP_XMAX_COMMITTED))
  1192. {
  1193. tuple->t_data->t_infomask |= HEAP_XMAX_COMMITTED;
  1194. SetBufferCommitInfoNeedsSave(*buffer);
  1195. }
  1196. /* if tuple was marked for update but not updated... */
  1197. if (tuple->t_data->t_infomask & HEAP_MARKED_FOR_UPDATE)
  1198. result = HeapTupleMayBeUpdated;
  1199. else
  1200. result = HeapTupleUpdated;
  1201. }
  1202. if (result != HeapTupleMayBeUpdated)
  1203. {
  1204. Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated);
  1205. tuple->t_self = tuple->t_data->t_ctid;
  1206. LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
  1207. return result;
  1208. }
  1209. /* store transaction information of xact marking the tuple */
  1210. TransactionIdStore(GetCurrentTransactionId(), &(tuple->t_data->t_xmax));
  1211. tuple->t_data->t_cmax = GetCurrentCommandId();
  1212. tuple->t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID);
  1213. tuple->t_data->t_infomask |= HEAP_MARKED_FOR_UPDATE;
  1214. LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
  1215. WriteNoReleaseBuffer(*buffer);
  1216. return HeapTupleMayBeUpdated;
  1217. }
  1218. /* ----------------
  1219.  * heap_markpos - mark scan position
  1220.  *
  1221.  * Note:
  1222.  * Should only one mark be maintained per scan at one time.
  1223.  * Check if this can be done generally--say calls to get the
  1224.  * next/previous tuple and NEVER pass struct scandesc to the
  1225.  * user AM's.  Now, the mark is sent to the executor for safekeeping.
  1226.  * Probably can store this info into a GENERAL scan structure.
  1227.  *
  1228.  * May be best to change this call to store the marked position
  1229.  * (up to 2?) in the scan structure itself.
  1230.  * Fix to use the proper caching structure.
  1231.  * ----------------
  1232.  */
  1233. void
  1234. heap_markpos(HeapScanDesc scan)
  1235. {
  1236. /* ----------------
  1237.  * increment access statistics
  1238.  * ----------------
  1239.  */
  1240. IncrHeapAccessStat(local_markpos);
  1241. IncrHeapAccessStat(global_markpos);
  1242. /* Note: no locking manipulations needed */
  1243. if (scan->rs_ptup.t_data == NULL &&
  1244. BufferIsUnknown(scan->rs_pbuf))
  1245. { /* == NONTUP */
  1246. scan->rs_ptup = scan->rs_ctup;
  1247. heapgettup(scan->rs_rd,
  1248.    &(scan->rs_ptup),
  1249.    -1,
  1250.    &scan->rs_pbuf,
  1251.    scan->rs_snapshot,
  1252.    scan->rs_nkeys,
  1253.    scan->rs_key);
  1254. }
  1255. else if (scan->rs_ntup.t_data == NULL &&
  1256.  BufferIsUnknown(scan->rs_nbuf))
  1257. { /* == NONTUP */
  1258. scan->rs_ntup = scan->rs_ctup;
  1259. heapgettup(scan->rs_rd,
  1260.    &(scan->rs_ntup),
  1261.    1,
  1262.    &scan->rs_nbuf,
  1263.    scan->rs_snapshot,
  1264.    scan->rs_nkeys,
  1265.    scan->rs_key);
  1266. }
  1267. /* ----------------
  1268.  * Should not unpin the buffer pages.  They may still be in use.
  1269.  * ----------------
  1270.  */
  1271. if (scan->rs_ptup.t_data != NULL)
  1272. scan->rs_mptid = scan->rs_ptup.t_self;
  1273. else
  1274. ItemPointerSetInvalid(&scan->rs_mptid);
  1275. if (scan->rs_ctup.t_data != NULL)
  1276. scan->rs_mctid = scan->rs_ctup.t_self;
  1277. else
  1278. ItemPointerSetInvalid(&scan->rs_mctid);
  1279. if (scan->rs_ntup.t_data != NULL)
  1280. scan->rs_mntid = scan->rs_ntup.t_self;
  1281. else
  1282. ItemPointerSetInvalid(&scan->rs_mntid);
  1283. }
  1284. /* ----------------
  1285.  * heap_restrpos - restore position to marked location
  1286.  *
  1287.  * Note:  there are bad side effects here.  If we were past the end
  1288.  * of a relation when heapmarkpos is called, then if the relation is
  1289.  * extended via insert, then the next call to heaprestrpos will set
  1290.  * cause the added tuples to be visible when the scan continues.
  1291.  * Problems also arise if the TID's are rearranged!!!
  1292.  *
  1293.  * Now pins buffer once for each valid tuple pointer (rs_ptup,
  1294.  * rs_ctup, rs_ntup) referencing it.
  1295.  *  - 01/13/94
  1296.  *
  1297.  * XXX might be better to do direct access instead of
  1298.  * using the generality of heapgettup().
  1299.  *
  1300.  * XXX It is very possible that when a scan is restored, that a tuple
  1301.  * XXX which previously qualified may fail for time range purposes, unless
  1302.  * XXX some form of locking exists (ie., portals currently can act funny.
  1303.  * ----------------
  1304.  */
  1305. void
  1306. heap_restrpos(HeapScanDesc scan)
  1307. {
  1308. /* ----------------
  1309.  * increment access statistics
  1310.  * ----------------
  1311.  */
  1312. IncrHeapAccessStat(local_restrpos);
  1313. IncrHeapAccessStat(global_restrpos);
  1314. /* XXX no amrestrpos checking that ammarkpos called */
  1315. /* Note: no locking manipulations needed */
  1316. unpinscan(scan);
  1317. /* force heapgettup to pin buffer for each loaded tuple */
  1318. scan->rs_pbuf = InvalidBuffer;
  1319. scan->rs_cbuf = InvalidBuffer;
  1320. scan->rs_nbuf = InvalidBuffer;
  1321. if (!ItemPointerIsValid(&scan->rs_mptid))
  1322. scan->rs_ptup.t_data = NULL;
  1323. else
  1324. {
  1325. scan->rs_ptup.t_self = scan->rs_mptid;
  1326. scan->rs_ptup.t_data = (HeapTupleHeader) 0x1; /* for heapgettup */
  1327. heapgettup(scan->rs_rd,
  1328.    &(scan->rs_ptup),
  1329.    0,
  1330.    &(scan->rs_pbuf),
  1331.    false,
  1332.    0,
  1333.    (ScanKey) NULL);
  1334. }
  1335. if (!ItemPointerIsValid(&scan->rs_mctid))
  1336. scan->rs_ctup.t_data = NULL;
  1337. else
  1338. {
  1339. scan->rs_ctup.t_self = scan->rs_mctid;
  1340. scan->rs_ctup.t_data = (HeapTupleHeader) 0x1; /* for heapgettup */
  1341. heapgettup(scan->rs_rd,
  1342.    &(scan->rs_ctup),
  1343.    0,
  1344.    &(scan->rs_cbuf),
  1345.    false,
  1346.    0,
  1347.    (ScanKey) NULL);
  1348. }
  1349. if (!ItemPointerIsValid(&scan->rs_mntid))
  1350. scan->rs_ntup.t_data = NULL;
  1351. else
  1352. {
  1353. scan->rs_ntup.t_self = scan->rs_mntid;
  1354. scan->rs_ntup.t_data = (HeapTupleHeader) 0x1; /* for heapgettup */
  1355. heapgettup(scan->rs_rd,
  1356.    &(scan->rs_ntup),
  1357.    0,
  1358.    &scan->rs_nbuf,
  1359.    false,
  1360.    0,
  1361.    (ScanKey) NULL);
  1362. }
  1363. }