📄 heapam.c
字号:
*/Relationrelation_open_nowait(Oid relationId, LOCKMODE lockmode){ Relation r; Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES); /* Get the lock before trying to open the relcache entry */ if (lockmode != NoLock) { if (!ConditionalLockRelationOid(relationId, lockmode)) { /* try to throw error by name; relation could be deleted... */ char *relname = get_rel_name(relationId); if (relname) ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("could not obtain lock on relation \"%s\"", relname))); else ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("could not obtain lock on relation with OID %u", relationId))); } } /* The relcache does all the real work... */ r = RelationIdGetRelation(relationId); if (!RelationIsValid(r)) elog(ERROR, "could not open relation with OID %u", relationId); /* Make note that we've accessed a temporary relation */ if (r->rd_istemp) MyXactAccessedTempRel = true; pgstat_initstats(r); return r;}/* ---------------- * relation_openrv - open any relation specified by a RangeVar * * Same as relation_open, but the relation is specified by a RangeVar. * ---------------- */Relationrelation_openrv(const RangeVar *relation, LOCKMODE lockmode){ Oid relOid; /* * Check for shared-cache-inval messages before trying to open the * relation. This is needed to cover the case where the name identifies a * rel that has been dropped and recreated since the start of our * transaction: if we don't flush the old syscache entry then we'll latch * onto that entry and suffer an error when we do RelationIdGetRelation. * Note that relation_open does not need to do this, since a relation's * OID never changes. * * We skip this if asked for NoLock, on the assumption that the caller has * already ensured some appropriate lock is held. */ if (lockmode != NoLock) AcceptInvalidationMessages(); /* Look up the appropriate relation using namespace search */ relOid = RangeVarGetRelid(relation, false); /* Let relation_open do the rest */ return relation_open(relOid, lockmode);}/* ---------------- * relation_close - close any relation * * If lockmode is not "NoLock", we then release the specified lock. * * Note that it is often sensible to hold a lock beyond relation_close; * in that case, the lock is released automatically at xact end. * ---------------- */voidrelation_close(Relation relation, LOCKMODE lockmode){ LockRelId relid = relation->rd_lockInfo.lockRelId; Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES); /* The relcache does the real work... */ RelationClose(relation); if (lockmode != NoLock) UnlockRelationId(&relid, lockmode);}/* ---------------- * heap_open - open a heap relation by relation OID * * This is essentially relation_open plus check that the relation * is not an index nor a composite type. (The caller should also * check that it's not a view before assuming it has storage.) * ---------------- */Relationheap_open(Oid relationId, LOCKMODE lockmode){ Relation r; r = relation_open(relationId, lockmode); if (r->rd_rel->relkind == RELKIND_INDEX) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an index", RelationGetRelationName(r)))); else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a composite type", RelationGetRelationName(r)))); return r;}/* ---------------- * heap_openrv - open a heap relation specified * by a RangeVar node * * As above, but relation is specified by a RangeVar. * ---------------- */Relationheap_openrv(const RangeVar *relation, LOCKMODE lockmode){ Relation r; r = relation_openrv(relation, lockmode); if (r->rd_rel->relkind == RELKIND_INDEX) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an index", RelationGetRelationName(r)))); else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a composite type", RelationGetRelationName(r)))); return r;}/* ---------------- * heap_beginscan - begin relation scan * * heap_beginscan_strat offers an extended API that lets the caller control * whether a nondefault buffer access strategy can be used, and whether * syncscan can be chosen (possibly resulting in the scan not starting from * block zero). Both of these default to TRUE with plain heap_beginscan. * * heap_beginscan_bm is an alternative entry point for setting up a * HeapScanDesc for a bitmap heap scan. Although that scan technology is * really quite unlike a standard seqscan, there is just enough commonality * to make it worth using the same data structure. * ---------------- */HeapScanDescheap_beginscan(Relation relation, Snapshot snapshot, int nkeys, ScanKey key){ return heap_beginscan_internal(relation, snapshot, nkeys, key, true, true, false);}HeapScanDescheap_beginscan_strat(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, bool allow_strat, bool allow_sync){ return heap_beginscan_internal(relation, snapshot, nkeys, key, allow_strat, allow_sync, false);}HeapScanDescheap_beginscan_bm(Relation relation, Snapshot snapshot, int nkeys, ScanKey key){ return heap_beginscan_internal(relation, snapshot, nkeys, key, false, false, true);}static HeapScanDescheap_beginscan_internal(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, bool allow_strat, bool allow_sync, bool is_bitmapscan){ HeapScanDesc scan; /* * increment relation ref count while scanning relation * * This is just to make really sure the relcache entry won't go away while * the scan has a pointer to it. Caller should be holding the rel open * anyway, so this is redundant in all normal scenarios... */ RelationIncrementReferenceCount(relation); /* * allocate and initialize scan descriptor */ scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData)); scan->rs_rd = relation; scan->rs_snapshot = snapshot; scan->rs_nkeys = nkeys; scan->rs_bitmapscan = is_bitmapscan; scan->rs_strategy = NULL; /* set in initscan */ scan->rs_allow_strat = allow_strat; scan->rs_allow_sync = allow_sync; /* * we can use page-at-a-time mode if it's an MVCC-safe snapshot */ scan->rs_pageatatime = IsMVCCSnapshot(snapshot); /* we only need to set this up once */ scan->rs_ctup.t_tableOid = RelationGetRelid(relation); /* * we do this here instead of in initscan() because heap_rescan also calls * initscan() and we don't want to allocate memory again */ if (nkeys > 0) scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys); else scan->rs_key = NULL; initscan(scan, key); return scan;}/* ---------------- * heap_rescan - restart a relation scan * ---------------- */voidheap_rescan(HeapScanDesc scan, ScanKey key){ /* * unpin scan buffers */ if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); /* * reinitialize scan descriptor */ initscan(scan, key);}/* ---------------- * heap_endscan - end relation scan * * See how to integrate with index scans. * Check handling if reldesc caching. * ---------------- */voidheap_endscan(HeapScanDesc scan){ /* Note: no locking manipulations needed */ /* * unpin scan buffers */ if (BufferIsValid(scan->rs_cbuf)) ReleaseBuffer(scan->rs_cbuf); /* * decrement relation reference count and free scan descriptor storage */ RelationDecrementReferenceCount(scan->rs_rd); if (scan->rs_key) pfree(scan->rs_key); if (scan->rs_strategy != NULL) FreeAccessStrategy(scan->rs_strategy); pfree(scan);}/* ---------------- * 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(DEBUG2, "heap_getnext([%s,nkeys=%d],dir=%d) called", \ RelationGetRelationName(scan->rs_rd), scan->rs_nkeys, (int) direction)#define HEAPDEBUG_2 \ elog(DEBUG2, "heap_getnext returning EOS")#define HEAPDEBUG_3 \ elog(DEBUG2, "heap_getnext returning tuple")#else#define HEAPDEBUG_1#define HEAPDEBUG_2#define HEAPDEBUG_3#endif /* !defined(HEAPDEBUGALL) */HeapTupleheap_getnext(HeapScanDesc scan, ScanDirection direction){ /* Note: no locking manipulations needed */ HEAPDEBUG_1; /* heap_getnext( info ) */ if (scan->rs_pageatatime) heapgettup_pagemode(scan, direction, scan->rs_nkeys, scan->rs_key); else heapgettup(scan, direction, scan->rs_nkeys, scan->rs_key); if (scan->rs_ctup.t_data == NULL) { HEAPDEBUG_2; /* heap_getnext returning EOS */ return NULL; } /* * 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_3; /* heap_getnext returning tuple */ pgstat_count_heap_getnext(scan->rs_rd); return &(scan->rs_ctup);}/* * heap_fetch - retrieve tuple with given tid * * On entry, tuple->t_self is the TID to fetch. We pin the buffer holding * the tuple, fill in the remaining fields of *tuple, and check the tuple * against the specified snapshot. * * If successful (tuple found and passes snapshot time qual), then *userbuf * is set to the buffer holding the tuple and TRUE is returned. The caller * must unpin the buffer when done with the tuple. * * If the tuple is not found (ie, item number references a deleted slot), * then tuple->t_data is set to NULL and FALSE is returned. * * If the tuple is found but fails the time qual check, then FALSE is returned * but tuple->t_data is left pointing to the tuple. * * keep_buf determines what is done with the buffer in the FALSE-result cases. * When the caller specifies keep_buf = true, we retain the pin on the buffer * and return it in *userbuf (so the caller must eventually unpin it); when * keep_buf = false, the pin is released and *userbuf is set to InvalidBuffer. * * stats_relation is the relation to charge the heap_fetch operation against * for statistical purposes. (This could be the heap rel itself, an * associated index, or NULL to not count the fetch at all.) * * heap_fetch does not follow HOT chains: only the exact TID requested will * be fetched. * * It is somewhat inconsistent that we ereport() on invalid block number but * return false on invalid item number. There are a couple of reasons though. * One is that the caller can relatively easily check the block number for * validity, but cannot check the item number without reading the page * himself. Another is that when we are following a t_ctid link, we can be * reasonably confident that the page number is valid (since VACUUM shouldn't * truncate off the destination page without having killed the referencing * tuple first), but the item number might well not be good. */boolheap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, Relation stats_relation){ /* Assume *userbuf is undefined on entry */ *userbuf = InvalidBuffer; return heap_release_fetch(relation, snapshot, tuple, userbuf, keep_buf, stats_relation);}/* * heap_release_fetch - retrieve tuple with given tid * * This has the same API as heap_fetch except that if *userbuf is not * InvalidBuffer on entry, that buffer will be released before reading * the new page. This saves a separate ReleaseBuffer step and hence * one entry into the bufmgr when looping through multiple fetches. * Also, if *userbuf is the same buffer that holds the target tuple, * we avoid bufmgr manipulation altogether. */boolheap_release_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, Relation stats_relation){ ItemPointer tid = &(tuple->t_self); ItemId lp; Buffer buffer; PageHeader dp; OffsetNumber offnum; bool valid; /* * get the buffer from the relation descriptor. Note that this does a * buffer pin, and releases the old *userbuf if not InvalidBuffer. */ buffer = ReleaseAndReadBuffer(*userbuf, relation, ItemPointerGetBlockNumber(tid)); /* * Need share lock on buffer to examine tuple commit status. */ LockBuffer(buffer, BUFFER_LOCK_SHARE); dp = (PageHeader) BufferGetPage(buffer); /* * We'd better check for out-of-range offnum in case of VACUUM since the * TID was obtained. */ offnum = ItemPointerGetOffsetNumber(tid); if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(dp)) { LockBuffer(buffer, BUFFER_LOCK_UNLOCK); if (keep_buf) *userbuf = buffer; else { ReleaseBuffer(buffer); *userbuf = InvalidBuffer; } tuple->t_data = NULL; return false; } /* * get the item line pointer corresponding to the requested tid
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -