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

📄 heapam.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*------------------------------------------------------------------------- * * heapam.c *	  heap access method code * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.200.2.2 2005/11/22 18:23:03 momjian Exp $ * * * INTERFACE ROUTINES *		relation_open	- open any relation by relation OID *		relation_openrv - open any relation specified by a RangeVar *		relation_close	- close any relation *		heap_open		- open a heap relation by relation OID *		heap_openrv		- open a heap relation specified by a RangeVar *		heap_close		- (now just a macro for relation_close) *		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		- retrieve tuple with given tid *		heap_insert		- insert tuple into a relation *		heap_delete		- delete a tuple from a relation *		heap_update		- 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. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "access/hio.h"#include "access/multixact.h"#include "access/tuptoaster.h"#include "access/valid.h"#include "access/xlogutils.h"#include "catalog/catalog.h"#include "catalog/namespace.h"#include "miscadmin.h"#include "pgstat.h"#include "storage/procarray.h"#include "utils/inval.h"#include "utils/relcache.h"static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf,		   ItemPointerData from, Buffer newbuf, HeapTuple newtup, bool move);/* ---------------------------------------------------------------- *						 heap support routines * ---------------------------------------------------------------- *//* ---------------- *		initscan - scan code common to heap_beginscan and heap_rescan * ---------------- */static voidinitscan(HeapScanDesc scan, ScanKey key){	/*	 * Determine the number of blocks we have to scan.	 *	 * It is sufficient to do this once at scan start, since any tuples added	 * while the scan is in progress will be invisible to my transaction	 * anyway...	 */	scan->rs_nblocks = RelationGetNumberOfBlocks(scan->rs_rd);	scan->rs_ctup.t_datamcxt = NULL;	scan->rs_ctup.t_data = NULL;	scan->rs_cbuf = InvalidBuffer;	/* we don't have a marked position... */	ItemPointerSetInvalid(&(scan->rs_mctid));	/*	 * copy the scan key, if appropriate	 */	if (key != NULL)		memcpy(scan->rs_key, key, scan->rs_nkeys * sizeof(ScanKeyData));	pgstat_count_heap_scan(&scan->rs_pgstat_info);}/* ---------------- *		heapgettup - fetch next heap tuple * *		routine used by heap_getnext() which does most of the *		real work in scanning tuples. * *		The passed-in *buffer must be either InvalidBuffer or the pinned *		current page of the scan.  If we have to move to another page, *		we will unpin this buffer (if valid).  On return, *buffer is either *		InvalidBuffer or the ID of a pinned buffer. * ---------------- */static voidheapgettup(Relation relation,		   int dir,		   HeapTuple tuple,		   Buffer *buffer,		   Snapshot snapshot,		   int nkeys,		   ScanKey key,		   BlockNumber pages){	ItemId		lpp;	Page		dp;	BlockNumber page;	int			lines;	OffsetNumber lineoff;	int			linesleft;	ItemPointer tid;	tid = (tuple->t_data == NULL) ? NULL : &(tuple->t_self);	/*	 * 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(DEBUG2, "heapgettup(%s, tid=0x%x[%d,%d], dir=%d, ...)",			 RelationGetRelationName(relation), tid, tid->ip_blkid,			 tid->ip_posid, dir);	else		elog(DEBUG2, "heapgettup(%s, tid=0x%x, dir=%d, ...)",			 RelationGetRelationName(relation), tid, dir);	elog(DEBUG2, "heapgettup(..., b=0x%x, nkeys=%d, key=0x%x", buffer, nkeys, key);	elog(DEBUG2, "heapgettup: relation(%c)=`%s', %p",		 relation->rd_rel->relkind, RelationGetRelationName(relation),		 snapshot);#endif   /* HEAPDEBUGALL */	if (!ItemPointerIsValid(tid))	{		Assert(!PointerIsValid(tid));		tid = NULL;	}	tuple->t_tableOid = RelationGetRelid(relation);	/*	 * return null immediately if relation is empty	 */	if (pages == 0)	{		if (BufferIsValid(*buffer))			ReleaseBuffer(*buffer);		*buffer = InvalidBuffer;		tuple->t_datamcxt = NULL;		tuple->t_data = NULL;		return;	}	/*	 * calculate next starting lineoff, given scan direction	 */	if (dir == 0)	{		/*		 * ``no movement'' scan direction: refetch same tuple		 */		if (tid == NULL)		{			if (BufferIsValid(*buffer))				ReleaseBuffer(*buffer);			*buffer = InvalidBuffer;			tuple->t_datamcxt = NULL;			tuple->t_data = NULL;			return;		}		*buffer = ReleaseAndReadBuffer(*buffer,									   relation,									   ItemPointerGetBlockNumber(tid));		LockBuffer(*buffer, BUFFER_LOCK_SHARE);		dp = (Page) BufferGetPage(*buffer);		lineoff = ItemPointerGetOffsetNumber(tid);		lpp = PageGetItemId(dp, lineoff);		tuple->t_datamcxt = NULL;		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 (tid == NULL)		{			page = pages - 1;	/* final page */		}		else		{			page = ItemPointerGetBlockNumber(tid);		/* current page */		}		Assert(page < pages);		*buffer = ReleaseAndReadBuffer(*buffer,									   relation,									   page);		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 (tid == NULL)		{			page = 0;			/* first page */			lineoff = FirstOffsetNumber;		/* first offnum */		}		else		{			page = ItemPointerGetBlockNumber(tid);		/* current page */			lineoff =			/* next offnum */				OffsetNumberNext(ItemPointerGetOffsetNumber(tid));		}		Assert(page < pages);		*buffer = ReleaseAndReadBuffer(*buffer,									   relation,									   page);		LockBuffer(*buffer, BUFFER_LOCK_SHARE);		dp = (Page) BufferGetPage(*buffer);		lines = PageGetMaxOffsetNumber(dp);		/* page and lineoff now reference the physically next tid */	}	/* '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))			{				bool		valid;				tuple->t_datamcxt = NULL;				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, valid);				if (valid)				{					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);		/*		 * return NULL if we've exhausted all the pages		 */		if ((dir < 0) ? (page == 0) : (page + 1 >= pages))		{			if (BufferIsValid(*buffer))				ReleaseBuffer(*buffer);			*buffer = InvalidBuffer;			tuple->t_datamcxt = NULL;			tuple->t_data = NULL;			return;		}		page = (dir < 0) ? (page - 1) : (page + 1);		Assert(page < pages);		*buffer = ReleaseAndReadBuffer(*buffer,									   relation,									   page);		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);		}	}}#if defined(DISABLE_COMPLEX_MACRO)/* * This is formatted so oddly so that the correspondence to the macro * definition in access/heapam.h is maintained. */Datumfastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,			bool *isnull){	return (			(attnum) > 0 ?			(			 ((isnull) ? (*(isnull) = false) : (dummyret) NULL),			 HeapTupleNoNulls(tup) ?			 (			  (tupleDesc)->attrs[(attnum) - 1]->attcacheoff >= 0 ?			  (			   fetchatt((tupleDesc)->attrs[(attnum) - 1],						(char *) (tup)->t_data + (tup)->t_data->t_hoff +						(tupleDesc)->attrs[(attnum) - 1]->attcacheoff)			   )			  :			  nocachegetattr((tup), (attnum), (tupleDesc), (isnull))			  )			 :			 (			  att_isnull((attnum) - 1, (tup)->t_data->t_bits) ?			  (			   ((isnull) ? (*(isnull) = true) : (dummyret) NULL),			   (Datum) NULL			   )			  :			  (			   nocachegetattr((tup), (attnum), (tupleDesc), (isnull))			   )			  )			 )			:			(			 (Datum) NULL			 )		);}#endif   /* defined(DISABLE_COMPLEX_MACRO) *//* ---------------------------------------------------------------- *					 heap access method interface * ---------------------------------------------------------------- *//* ---------------- *		relation_open - open any relation by relation OID * *		If lockmode is not "NoLock", the specified kind of lock is *		obtained on the relation.  (Generally, NoLock should only be *		used if the caller knows it has some appropriate lock on the *		relation already.) * *		An error is raised if the relation does not exist. * *		NB: a "relation" is anything with a pg_class entry.  The caller is *		expected to check whether the relkind is something it can handle. * ---------------- */Relationrelation_open(Oid relationId, LOCKMODE lockmode){	Relation	r;	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);	/* The relcache does all the real work... */	r = RelationIdGetRelation(relationId);	if (!RelationIsValid(r))		elog(ERROR, "could not open relation with OID %u", relationId);

⌨️ 快捷键说明

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