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 + -
显示快捷键?