⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 heapam.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * heapam.c *	  heap access method code * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.46.2.1 1999/08/02 05:56:36 scrappy Exp $ * * * INTERFACE ROUTINES *		heapgettup		- fetch next heap tuple from a scan *		heap_open		- open a heap relation by relationId *		heap_openr		- open a heap relation by name *		heap_close		- close a heap relation *		heap_beginscan	- begin relation scan *		heap_rescan		- restart a relation scan *		heap_endscan	- end relation scan *		heap_getnext	- retrieve next tuple in scan *		heap_fetch		- retrive tuple with tid *		heap_insert		- insert tuple into a relation *		heap_delete		- delete a tuple from a relation *		heap_replace	- replace a tuple in a relation with another tuple *		heap_markpos	- mark scan position *		heap_restrpos	- restore position to marked location * * NOTES *	  This file contains the heap_ routines which implement *	  the POSTGRES heap access method used for all POSTGRES *	  relations. * * OLD COMMENTS *		struct relscan hints:  (struct should be made AM independent?) * *		rs_ctid is the tid of the last tuple returned by getnext. *		rs_ptid and rs_ntid are the tids of the previous and next tuples *		returned by getnext, respectively.	NULL indicates an end of *		scan (either direction); NON indicates an unknow value. * *		possible combinations: *		rs_p	rs_c	rs_n			interpretation *		NULL	NULL	NULL			empty scan *		NULL	NULL	NON				at begining of scan *		NULL	NULL	t1				at begining of scan (with cached tid) *		NON		NULL	NULL			at end of scan *		t1		NULL	NULL			at end of scan (with cached tid) *		NULL	t1		NULL			just returned only tuple *		NULL	t1		NON				just returned first tuple *		NULL	t1		t2				returned first tuple (with cached tid) *		NON		t1		NULL			just returned last tuple *		t2		t1		NULL			returned last tuple (with cached tid) *		t1		t2		NON				in the middle of a forward scan *		NON		t2		t1				in the middle of a reverse scan *		ti		tj		tk				in the middle of a scan (w cached tid) * *		Here NULL is ...tup == NULL && ...buf == InvalidBuffer, *		and NON is ...tup == NULL && ...buf == UnknownBuffer. * *		Currently, the NONTID values are not cached with their actual *		values by getnext.	Values may be cached by markpos since it stores *		all three tids. * *		NOTE:  the calls to elog() must stop.  Should decide on an interface *		between the general and specific AM calls. * *		XXX probably do not need a free tuple routine for heaps. *		Huh?  Free tuple is not necessary for tuples returned by scans, but *		is necessary for tuples which are returned by *		RelationGetTupleByItemPointer. -hirohama * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "access/hio.h"#include "access/valid.h"#include "catalog/catalog.h"#include "miscadmin.h"#include "storage/smgr.h"#include "utils/builtins.h"#include "utils/inval.h"#include "utils/relcache.h"/* ---------------------------------------------------------------- *						 heap support routines * ---------------------------------------------------------------- *//* ---------------- *		initscan - scan code common to heap_beginscan and heap_rescan * ---------------- */static voidinitscan(HeapScanDesc scan,		 Relation relation,		 int atend,		 unsigned nkeys,		 ScanKey key){	if (!RelationGetNumberOfBlocks(relation))	{		/* ----------------		 *	relation is empty		 * ----------------		 */		scan->rs_ntup.t_data = scan->rs_ctup.t_data =		scan->rs_ptup.t_data = NULL;		scan->rs_nbuf = scan->rs_cbuf = scan->rs_pbuf = InvalidBuffer;	}	else if (atend)	{		/* ----------------		 *	reverse scan		 * ----------------		 */		scan->rs_ntup.t_data = scan->rs_ctup.t_data = NULL;		scan->rs_nbuf = scan->rs_cbuf = InvalidBuffer;		scan->rs_ptup.t_data = NULL;		scan->rs_pbuf = UnknownBuffer;	}	else	{		/* ----------------		 *	forward scan		 * ----------------		 */		scan->rs_ctup.t_data = scan->rs_ptup.t_data = NULL;		scan->rs_cbuf = scan->rs_pbuf = InvalidBuffer;		scan->rs_ntup.t_data = NULL;		scan->rs_nbuf = UnknownBuffer;	}							/* invalid too */	/* we don't have a marked position... */	ItemPointerSetInvalid(&(scan->rs_mptid));	ItemPointerSetInvalid(&(scan->rs_mctid));	ItemPointerSetInvalid(&(scan->rs_mntid));	ItemPointerSetInvalid(&(scan->rs_mcd));	/* ----------------	 *	copy the scan key, if appropriate	 * ----------------	 */	if (key != NULL)		memmove(scan->rs_key, key, nkeys * sizeof(ScanKeyData));}/* ---------------- *		unpinscan - code common to heap_rescan and heap_endscan * ---------------- */static voidunpinscan(HeapScanDesc scan){	if (BufferIsValid(scan->rs_pbuf))		ReleaseBuffer(scan->rs_pbuf);	/* ------------------------------------	 *	Scan will pin buffer one for each non-NULL tuple pointer	 *	(ptup, ctup, ntup), so they have to be unpinned multiple	 *	times.	 * ------------------------------------	 */	if (BufferIsValid(scan->rs_cbuf))		ReleaseBuffer(scan->rs_cbuf);	if (BufferIsValid(scan->rs_nbuf))		ReleaseBuffer(scan->rs_nbuf);}/* ------------------------------------------ *		nextpage * *		figure out the next page to scan after the current page *		taking into account of possible adjustment of degrees of *		parallelism * ------------------------------------------ */static intnextpage(int page, int dir){	return (dir < 0) ? page - 1 : page + 1;}/* ---------------- *		heapgettup - fetch next heap tuple * *		routine used by heap_getnext() which does most of the *		real work in scanning tuples. * *		The scan routines handle their own buffer lock/unlocking, so *		there is no reason to request the buffer number unless *		to want to perform some other operation with the result, *		like pass it to another function. * ---------------- */static voidheapgettup(Relation relation,		   HeapTuple tuple,		   int dir,		   Buffer *buffer,		   Snapshot snapshot,		   int nkeys,		   ScanKey key){	ItemId		lpp;	Page		dp;	int			page;	int			pages;	int			lines;	OffsetNumber lineoff;	int			linesleft;	ItemPointer tid = (tuple->t_data == NULL) ?	(ItemPointer) NULL : &(tuple->t_self);	/* ----------------	 *	increment access statistics	 * ----------------	 */	IncrHeapAccessStat(local_heapgettup);	IncrHeapAccessStat(global_heapgettup);	/* ----------------	 *	debugging stuff	 *	 * check validity of arguments, here and for other functions too	 * Note: no locking manipulations needed--this is a local function	 * ----------------	 */#ifdef	HEAPDEBUGALL	if (ItemPointerIsValid(tid))	{		elog(DEBUG, "heapgettup(%s, tid=0x%x[%d,%d], dir=%d, ...)",			 RelationGetRelationName(relation), tid, tid->ip_blkid,			 tid->ip_posid, dir);	}	else	{		elog(DEBUG, "heapgettup(%s, tid=0x%x, dir=%d, ...)",			 RelationGetRelationName(relation), tid, dir);	}	elog(DEBUG, "heapgettup(..., b=0x%x, nkeys=%d, key=0x%x", buffer, nkeys, key);	elog(DEBUG, "heapgettup: relation(%c)=`%s', %p",		 relation->rd_rel->relkind, &relation->rd_rel->relname,		 snapshot);#endif	 /* !defined(HEAPDEBUGALL) */	if (!ItemPointerIsValid(tid))		Assert(!PointerIsValid(tid));	/* ----------------	 *	return null immediately if relation is empty	 * ----------------	 */	if (!(pages = relation->rd_nblocks))	{		tuple->t_data = NULL;		return;	}	/* ----------------	 *	calculate next starting lineoff, given scan direction	 * ----------------	 */	if (!dir)	{		/* ----------------		 * ``no movement'' scan direction		 * ----------------		 */		/* assume it is a valid TID XXX */		if (ItemPointerIsValid(tid) == false)		{			*buffer = InvalidBuffer;			tuple->t_data = NULL;			return;		}		*buffer = RelationGetBufferWithBuffer(relation,										  ItemPointerGetBlockNumber(tid),											  *buffer);		if (!BufferIsValid(*buffer))			elog(ERROR, "heapgettup: failed ReadBuffer");		LockBuffer(*buffer, BUFFER_LOCK_SHARE);		dp = (Page) BufferGetPage(*buffer);		lineoff = ItemPointerGetOffsetNumber(tid);		lpp = PageGetItemId(dp, lineoff);		tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);		tuple->t_len = ItemIdGetLength(lpp);		LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);		return;	}	else if (dir < 0)	{		/* ----------------		 *	reverse scan direction		 * ----------------		 */		if (ItemPointerIsValid(tid) == false)			tid = NULL;		if (tid == NULL)		{			page = pages - 1;	/* final page */		}		else		{			page = ItemPointerGetBlockNumber(tid);		/* current page */		}		if (page < 0)		{			*buffer = InvalidBuffer;			tuple->t_data = NULL;			return;		}		*buffer = RelationGetBufferWithBuffer(relation, page, *buffer);		if (!BufferIsValid(*buffer))			elog(ERROR, "heapgettup: failed ReadBuffer");		LockBuffer(*buffer, BUFFER_LOCK_SHARE);		dp = (Page) BufferGetPage(*buffer);		lines = PageGetMaxOffsetNumber(dp);		if (tid == NULL)		{			lineoff = lines;	/* final offnum */		}		else		{			lineoff =			/* previous offnum */				OffsetNumberPrev(ItemPointerGetOffsetNumber(tid));		}		/* page and lineoff now reference the physically previous tid */	}	else	{		/* ----------------		 *	forward scan direction		 * ----------------		 */		if (ItemPointerIsValid(tid) == false)		{			page = 0;			/* first page */			lineoff = FirstOffsetNumber;		/* first offnum */		}		else		{			page = ItemPointerGetBlockNumber(tid);		/* current page */			lineoff =			/* next offnum */				OffsetNumberNext(ItemPointerGetOffsetNumber(tid));		}		if (page >= pages)		{			*buffer = InvalidBuffer;			tuple->t_data = NULL;			return;		}		/* page and lineoff now reference the physically next tid */		*buffer = RelationGetBufferWithBuffer(relation, page, *buffer);		if (!BufferIsValid(*buffer))			elog(ERROR, "heapgettup: failed ReadBuffer");		LockBuffer(*buffer, BUFFER_LOCK_SHARE);		dp = (Page) BufferGetPage(*buffer);		lines = PageGetMaxOffsetNumber(dp);	}	/* 'dir' is now non-zero */	/* ----------------	 *	calculate line pointer and number of remaining items	 *	to check on this page.	 * ----------------	 */	lpp = PageGetItemId(dp, lineoff);	if (dir < 0)		linesleft = lineoff - 1;	else		linesleft = lines - lineoff;	/* ----------------	 *	advance the scan until we find a qualifying tuple or	 *	run out of stuff to scan	 * ----------------	 */	for (;;)	{		while (linesleft >= 0)		{			if (ItemIdIsUsed(lpp))			{				tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);				tuple->t_len = ItemIdGetLength(lpp);				ItemPointerSet(&(tuple->t_self), page, lineoff);				/* ----------------				 *	if current tuple qualifies, return it.				 * ----------------				 */				HeapTupleSatisfies(tuple, relation, *buffer, (PageHeader) dp,								   snapshot, nkeys, key);				if (tuple->t_data != NULL)				{					LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);					return;				}			}			/* ----------------			 *	otherwise move to the next item on the page			 * ----------------			 */			--linesleft;			if (dir < 0)			{				--lpp;			/* move back in this page's ItemId array */				--lineoff;			}			else			{				++lpp;			/* move forward in this page's ItemId								 * array */				++lineoff;			}		}		/* ----------------		 *	if we get here, it means we've exhausted the items on		 *	this page and it's time to move to the next..		 * ----------------		 */		LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);		page = nextpage(page, dir);		/* ----------------		 *	return NULL if we've exhausted all the pages..		 * ----------------		 */		if (page < 0 || page >= pages)		{			if (BufferIsValid(*buffer))				ReleaseBuffer(*buffer);			*buffer = InvalidBuffer;			tuple->t_data = NULL;			return;		}		*buffer = ReleaseAndReadBuffer(*buffer, relation, page);		if (!BufferIsValid(*buffer))			elog(ERROR, "heapgettup: failed ReadBuffer");		LockBuffer(*buffer, BUFFER_LOCK_SHARE);		dp = (Page) BufferGetPage(*buffer);		lines = PageGetMaxOffsetNumber((Page) dp);		linesleft = lines - 1;		if (dir < 0)		{			lineoff = lines;			lpp = PageGetItemId(dp, lines);		}		else		{			lineoff = FirstOffsetNumber;			lpp = PageGetItemId(dp, FirstOffsetNumber);		}	}}/* ---------------------------------------------------------------- *					 heap access method interface * ---------------------------------------------------------------- *//* ---------------- *		heap_open - open a heap relation by relationId * *		presently the relcache routines do all the work we need *		to open/close heap relations. * ---------------- */Relationheap_open(Oid relationId){	Relation	r;	/* ----------------	 *	increment access statistics	 * ----------------	 */	IncrHeapAccessStat(local_open);	IncrHeapAccessStat(global_open);	r = (Relation) RelationIdGetRelation(relationId);	if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX)		elog(ERROR, "%s is an index relation", r->rd_rel->relname.data);	return r;}/* ---------------- *		heap_openr - open a heap relation by name * *		presently the relcache routines do all the work we need *		to open/close heap relations. * ---------------- */Relation

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -