heapam.c
来自「关系型数据库 Postgresql 6.5.2」· C语言 代码 · 共 1,560 行 · 第 1/3 页
C
1,560 行
heap_openr(char *relationName){ Relation r; /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_openr); IncrHeapAccessStat(global_openr); r = RelationNameGetRelation(relationName); if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX) elog(ERROR, "%s is an index relation", r->rd_rel->relname.data); return r;}/* ---------------- * heap_close - close a heap relation * * presently the relcache routines do all the work we need * to open/close heap relations. * ---------------- */voidheap_close(Relation relation){ /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_close); IncrHeapAccessStat(global_close); RelationClose(relation);}/* ---------------- * heap_beginscan - begin relation scan * ---------------- */HeapScanDescheap_beginscan(Relation relation, int atend, Snapshot snapshot, unsigned nkeys, ScanKey key){ HeapScanDesc scan; /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_beginscan); IncrHeapAccessStat(global_beginscan); /* ---------------- * sanity checks * ---------------- */ if (RelationIsValid(relation) == false) elog(ERROR, "heap_beginscan: !RelationIsValid(relation)"); LockRelation(relation, AccessShareLock); /* XXX someday assert SelfTimeQual if relkind == RELKIND_UNCATALOGED */ if (relation->rd_rel->relkind == RELKIND_UNCATALOGED) snapshot = SnapshotSelf; /* ---------------- * increment relation ref count while scanning relation * ---------------- */ RelationIncrementReferenceCount(relation); /* ---------------- * allocate and initialize scan descriptor * ---------------- */ scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData)); relation->rd_nblocks = smgrnblocks(DEFAULT_SMGR, relation); scan->rs_rd = relation; if (nkeys) /* * we do this here instead of in initscan() because heap_rescan * also calls initscan() and we don't want to allocate memory * again */ scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys); else scan->rs_key = NULL; initscan(scan, relation, atend, nkeys, key); scan->rs_atend = atend; scan->rs_snapshot = snapshot; scan->rs_nkeys = (short) nkeys; return scan;}/* ---------------- * heap_rescan - restart a relation scan * ---------------- */voidheap_rescan(HeapScanDesc scan, bool scanFromEnd, ScanKey key){ /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_rescan); IncrHeapAccessStat(global_rescan); /* Note: set relation level read lock is still set */ /* ---------------- * unpin scan buffers * ---------------- */ unpinscan(scan); /* ---------------- * reinitialize scan descriptor * ---------------- */ initscan(scan, scan->rs_rd, scanFromEnd, scan->rs_nkeys, key); scan->rs_atend = (bool) scanFromEnd;}/* ---------------- * heap_endscan - end relation scan * * See how to integrate with index scans. * Check handling if reldesc caching. * ---------------- */voidheap_endscan(HeapScanDesc scan){ /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_endscan); IncrHeapAccessStat(global_endscan); /* Note: no locking manipulations needed */ /* ---------------- * unpin scan buffers * ---------------- */ unpinscan(scan); /* ---------------- * decrement relation reference count and free scan descriptor storage * ---------------- */ RelationDecrementReferenceCount(scan->rs_rd); UnlockRelation(scan->rs_rd, AccessShareLock); pfree(scan); /* XXX */}/* ---------------- * heap_getnext - retrieve next tuple in scan * * Fix to work with index relations. * We don't return the buffer anymore, but you can get it from the * returned HeapTuple. * ---------------- */#ifdef HEAPDEBUGALL#define HEAPDEBUG_1 \elog(DEBUG, "heap_getnext([%s,nkeys=%d],backw=%d) called", \ scan->rs_rd->rd_rel->relname.data, scan->rs_nkeys, backw)#define HEAPDEBUG_2 \ elog(DEBUG, "heap_getnext called with backw (no tracing yet)")#define HEAPDEBUG_3 \ elog(DEBUG, "heap_getnext returns NULL at end")#define HEAPDEBUG_4 \ elog(DEBUG, "heap_getnext valid buffer UNPIN'd")#define HEAPDEBUG_5 \ elog(DEBUG, "heap_getnext next tuple was cached")#define HEAPDEBUG_6 \ elog(DEBUG, "heap_getnext returning EOS")#define HEAPDEBUG_7 \ elog(DEBUG, "heap_getnext returning tuple");#else#define HEAPDEBUG_1#define HEAPDEBUG_2#define HEAPDEBUG_3#define HEAPDEBUG_4#define HEAPDEBUG_5#define HEAPDEBUG_6#define HEAPDEBUG_7#endif /* !defined(HEAPDEBUGALL) */HeapTupleheap_getnext(HeapScanDesc scandesc, int backw){ HeapScanDesc scan = scandesc; /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_getnext); IncrHeapAccessStat(global_getnext); /* Note: no locking manipulations needed */ /* ---------------- * argument checks * ---------------- */ if (scan == NULL) elog(ERROR, "heap_getnext: NULL relscan"); /* ---------------- * initialize return buffer to InvalidBuffer * ---------------- */ HEAPDEBUG_1; /* heap_getnext( info ) */ if (backw) { /* ---------------- * handle reverse scan * ---------------- */ HEAPDEBUG_2; /* heap_getnext called with backw */ if (scan->rs_ptup.t_data == scan->rs_ctup.t_data && BufferIsInvalid(scan->rs_pbuf)) { if (BufferIsValid(scan->rs_nbuf)) ReleaseBuffer(scan->rs_nbuf); return NULL; } /* * Copy the "current" tuple/buffer to "next". Pin/unpin the * buffers accordingly */ if (scan->rs_nbuf != scan->rs_cbuf) { if (BufferIsValid(scan->rs_nbuf)) ReleaseBuffer(scan->rs_nbuf); if (BufferIsValid(scan->rs_cbuf)) IncrBufferRefCount(scan->rs_cbuf); } scan->rs_ntup = scan->rs_ctup; scan->rs_nbuf = scan->rs_cbuf; if (scan->rs_ptup.t_data != NULL) { if (scan->rs_cbuf != scan->rs_pbuf) { if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); if (BufferIsValid(scan->rs_pbuf)) IncrBufferRefCount(scan->rs_pbuf); } scan->rs_ctup = scan->rs_ptup; scan->rs_cbuf = scan->rs_pbuf; } else { /* NONTUP */ /* * Don't release scan->rs_cbuf at this point, because * heapgettup doesn't increase PrivateRefCount if it is * already set. On a backward scan, both rs_ctup and rs_ntup * usually point to the same buffer page, so * PrivateRefCount[rs_cbuf] should be 2 (or more, if for * instance ctup is stored in a TupleTableSlot). - 01/09/94 */ heapgettup(scan->rs_rd, &(scan->rs_ctup), -1, &(scan->rs_cbuf), scan->rs_snapshot, scan->rs_nkeys, scan->rs_key); } if (scan->rs_ctup.t_data == NULL && !BufferIsValid(scan->rs_cbuf)) { if (BufferIsValid(scan->rs_pbuf)) ReleaseBuffer(scan->rs_pbuf); scan->rs_ptup.t_data = NULL; scan->rs_pbuf = InvalidBuffer; if (BufferIsValid(scan->rs_nbuf)) ReleaseBuffer(scan->rs_nbuf); scan->rs_ntup.t_data = NULL; scan->rs_nbuf = InvalidBuffer; return NULL; } if (BufferIsValid(scan->rs_pbuf)) ReleaseBuffer(scan->rs_pbuf); scan->rs_ptup.t_data = NULL; scan->rs_pbuf = UnknownBuffer; } else { /* ---------------- * handle forward scan * ---------------- */ if (scan->rs_ctup.t_data == scan->rs_ntup.t_data && BufferIsInvalid(scan->rs_nbuf)) { if (BufferIsValid(scan->rs_pbuf)) ReleaseBuffer(scan->rs_pbuf); HEAPDEBUG_3; /* heap_getnext returns NULL at end */ return NULL; } /* * Copy the "current" tuple/buffer to "previous". Pin/unpin the * buffers accordingly */ if (scan->rs_pbuf != scan->rs_cbuf) { if (BufferIsValid(scan->rs_pbuf)) ReleaseBuffer(scan->rs_pbuf); if (BufferIsValid(scan->rs_cbuf)) IncrBufferRefCount(scan->rs_cbuf); } scan->rs_ptup = scan->rs_ctup; scan->rs_pbuf = scan->rs_cbuf; if (scan->rs_ntup.t_data != NULL) { if (scan->rs_cbuf != scan->rs_nbuf) { if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); if (BufferIsValid(scan->rs_nbuf)) IncrBufferRefCount(scan->rs_nbuf); } scan->rs_ctup = scan->rs_ntup; scan->rs_cbuf = scan->rs_nbuf; HEAPDEBUG_5; /* heap_getnext next tuple was cached */ } else { /* NONTUP */ /* * Don't release scan->rs_cbuf at this point, because * heapgettup doesn't increase PrivateRefCount if it is * already set. On a forward scan, both rs_ctup and rs_ptup * usually point to the same buffer page, so * PrivateRefCount[rs_cbuf] should be 2 (or more, if for * instance ctup is stored in a TupleTableSlot). - 01/09/93 */ heapgettup(scan->rs_rd, &(scan->rs_ctup), 1, &scan->rs_cbuf, scan->rs_snapshot, scan->rs_nkeys, scan->rs_key); } if (scan->rs_ctup.t_data == NULL && !BufferIsValid(scan->rs_cbuf)) { if (BufferIsValid(scan->rs_nbuf)) ReleaseBuffer(scan->rs_nbuf); scan->rs_ntup.t_data = NULL; scan->rs_nbuf = InvalidBuffer; if (BufferIsValid(scan->rs_pbuf)) ReleaseBuffer(scan->rs_pbuf); scan->rs_ptup.t_data = NULL; scan->rs_pbuf = InvalidBuffer; HEAPDEBUG_6; /* heap_getnext returning EOS */ return NULL; } if (BufferIsValid(scan->rs_nbuf)) ReleaseBuffer(scan->rs_nbuf); scan->rs_ntup.t_data = NULL; scan->rs_nbuf = UnknownBuffer; } /* ---------------- * if we get here it means we have a new current scan tuple, so * point to the proper return buffer and return the tuple. * ---------------- */ HEAPDEBUG_7; /* heap_getnext returning tuple */ return ((scan->rs_ctup.t_data == NULL) ? NULL : &(scan->rs_ctup));}/* ---------------- * heap_fetch - retrive tuple with tid * * Currently ignores LP_IVALID during processing! * * Because this is not part of a scan, there is no way to * automatically lock/unlock the shared buffers. * For this reason, we require that the user retrieve the buffer * value, and they are required to BufferRelease() it when they * are done. If they want to make a copy of it before releasing it, * they can call heap_copytyple(). * ---------------- */voidheap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf){ ItemId lp; Buffer buffer; PageHeader dp; ItemPointer tid = &(tuple->t_self); OffsetNumber offnum; AssertMacro(PointerIsValid(userbuf)); /* see comments above */ /* ---------------- * increment access statistics * ---------------- */ IncrHeapAccessStat(local_fetch); IncrHeapAccessStat(global_fetch); /* ---------------- * get the buffer from the relation descriptor * Note that this does a buffer pin. * ---------------- */ buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); if (!BufferIsValid(buffer)) elog(ERROR, "heap_fetch: %s relation: ReadBuffer(%lx) failed", &relation->rd_rel->relname, (long) tid); LockBuffer(buffer, BUFFER_LOCK_SHARE); /* ---------------- * get the item line pointer corresponding to the requested tid * ---------------- */ dp = (PageHeader) BufferGetPage(buffer); offnum = ItemPointerGetOffsetNumber(tid); lp = PageGetItemId(dp, offnum); /* ---------------- * more sanity checks * ---------------- */ Assert(ItemIdIsUsed(lp)); tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp); tuple->t_len = ItemIdGetLength(lp); /* ---------------- * check time qualification of tid * ---------------- */ HeapTupleSatisfies(tuple, relation, buffer, dp, snapshot, 0, (ScanKey) NULL); LockBuffer(buffer, BUFFER_LOCK_UNLOCK); if (tuple->t_data == NULL) { ReleaseBuffer(buffer); return; } /* ---------------- * all checks passed, now either return a copy of the tuple * or pin the buffer page and return a pointer, depending on * whether caller gave us a valid buf. * ---------------- */ *userbuf = buffer; /* user is required to ReleaseBuffer() * this */ return;}/* ---------------- * heap_insert - insert tuple *
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?