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