heapam.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,410 行 · 第 1/5 页
C
2,410 行
Assert(relation->schemaname == NULL); return relation_openr(relation->relname, lockmode); } /* * 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 * LockRelation. 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_openr - open a system relation specified by name. * * As above, but the relation is specified by an unqualified name; * it is assumed to live in the system catalog namespace. * ---------------- */Relationrelation_openr(const char *sysRelationName, LOCKMODE lockmode){ Relation r; Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES); /* * We assume we should not need to worry about the rel's OID changing, * hence no need for AcceptInvalidationMessages here. */ /* The relcache does all the real work... */ r = RelationSysNameGetRelation(sysRelationName); if (!RelationIsValid(r)) elog(ERROR, "could not open relation \"%s\"", sysRelationName); if (lockmode != NoLock) LockRelation(r, lockmode); return r;}/* ---------------- * relation_close - close any relation * * If lockmode is not "NoLock", we first 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){ Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES); if (lockmode != NoLock) UnlockRelation(relation, lockmode); /* The relcache does the real work... */ RelationClose(relation);}/* ---------------- * heap_open - open a heap relation by relation OID * * This is essentially relation_open plus check that the relation * is not an index or special relation. (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_SPECIAL) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a special relation", 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)))); pgstat_initstats(&r->pgstat_info, 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_SPECIAL) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a special relation", 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)))); pgstat_initstats(&r->pgstat_info, r); return r;}/* ---------------- * heap_openr - open a system heap relation specified by name. * * As above, but the relation is specified by an unqualified name; * it is assumed to live in the system catalog namespace. * ---------------- */Relationheap_openr(const char *sysRelationName, LOCKMODE lockmode){ Relation r; r = relation_openr(sysRelationName, 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_SPECIAL) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a special relation", 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)))); pgstat_initstats(&r->pgstat_info, r); return r;}/* ---------------- * heap_beginscan - begin relation scan * ---------------- */HeapScanDescheap_beginscan(Relation relation, Snapshot snapshot, int nkeys, ScanKey key){ 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); /* XXX someday assert SelfTimeQual if relkind == RELKIND_UNCATALOGED */ if (relation->rd_rel->relkind == RELKIND_UNCATALOGED) snapshot = SnapshotSelf; /* * allocate and initialize scan descriptor */ scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData)); scan->rs_rd = relation; scan->rs_snapshot = snapshot; scan->rs_nkeys = nkeys; /* * 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; pgstat_initstats(&scan->rs_pgstat_info, relation); 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); pgstat_reset_heap_scan(&scan->rs_pgstat_info);}/* ---------------- * 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); 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 ) */ /* * Note: we depend here on the -1/0/1 encoding of ScanDirection. */ heapgettup(scan->rs_rd, (int) direction, &(scan->rs_ctup), &(scan->rs_cbuf), scan->rs_snapshot, scan->rs_nkeys, scan->rs_key); if (scan->rs_ctup.t_data == NULL && !BufferIsValid(scan->rs_cbuf)) { HEAPDEBUG_2; /* heap_getnext returning EOS */ return NULL; } pgstat_count_heap_scan(&scan->rs_pgstat_info); /* * 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 */ if (scan->rs_ctup.t_data != NULL) pgstat_count_heap_getnext(&scan->rs_pgstat_info); return ((scan->rs_ctup.t_data == NULL) ? NULL : &(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, then tuple->t_data is set to NULL, *userbuf * is set to InvalidBuffer, and FALSE is returned. * * If the tuple is found but fails the time qual check, then FALSE will be * returned. When the caller specifies keep_buf = true, we retain the pin * on the buffer and return it in *userbuf (so the caller can still access * the tuple); when keep_buf = false, the pin is released and *userbuf is set * to InvalidBuffer. * * It is somewhat inconsistent that we ereport() on invalid block number but * return false on invalid item number. This is historical. The only * justification I can see is that the caller can relatively easily check the * block number for validity, but cannot check the item number without reading * the page himself. */boolheap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, PgStat_Info *pgstat_info){ 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. */ buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); if (!BufferIsValid(buffer)) elog(ERROR, "ReadBuffer(\"%s\", %lu) failed", RelationGetRelationName(relation), (unsigned long) ItemPointerGetBlockNumber(tid)); /* * Need share lock on buffer to examine tuple commit status. */ 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); /* * must check for deleted tuple (see for example analyze.c, which is * careful to pass an offnum in range, but doesn't know if the offnum * actually corresponds to an undeleted tuple). */ if (!ItemIdIsUsed(lp)) { LockBuffer(buffer, BUFFER_LOCK_UNLOCK); ReleaseBuffer(buffer); *userbuf = InvalidBuffer; tuple->t_datamcxt = NULL; tuple->t_data = NULL; return false; } /* * fill in *tuple fields */ tuple->t_datamcxt = NULL; tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp); tuple->t_len = ItemIdGetLength(lp); tuple->t_tableOid = relation->rd_id; /* * check time qualification of tuple, then release lock */ HeapTupleSatisfies(tuple, relation, buffer, dp, snapshot, 0, (ScanKey) NULL, valid); LockBuffer(buffer, BUFFER_LOCK_UNLOCK); if (valid) { /* * All checks passed, so return the tuple as valid. Caller is now * responsible for releasing the buffer. */ *userbuf = buffer; /* * Count the successful fetch in *pgstat_info if given, otherwise * in the relation's default statistics area. */ if (pgstat_info != NULL) pgstat_count_heap_fetch(pgstat_info); else pgstat_count_heap_fetch(&relation->pgstat_info); return true; } /* Tuple failed time qual, but maybe caller wants to see it anyway. */ if (keep_buf) { *userbuf = buffer; return false; } /* Okay to release pin on buffer. */ ReleaseBuffer(buffer); *userbuf = InvalidBuffer; return false;}/* * heap_get_latest_tid - get the latest tid of a specified tuple */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?