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

📄 hash.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * hash.c *	  Implementation of Margo Seltzer's Hashing package for postgres. * * 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/hash/hash.c,v 1.81 2005/10/15 02:49:08 momjian Exp $ * * NOTES *	  This file contains only the public interface routines. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/hash.h"#include "access/heapam.h"#include "access/xlogutils.h"#include "catalog/index.h"#include "commands/vacuum.h"#include "executor/executor.h"#include "miscadmin.h"/* Working state for hashbuild and its callback */typedef struct{	double		indtuples;} HashBuildState;static void hashbuildCallback(Relation index,				  HeapTuple htup,				  Datum *values,				  bool *isnull,				  bool tupleIsAlive,				  void *state);/* *	hashbuild() -- build a new hash index. */Datumhashbuild(PG_FUNCTION_ARGS){	Relation	heap = (Relation) PG_GETARG_POINTER(0);	Relation	index = (Relation) PG_GETARG_POINTER(1);	IndexInfo  *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);	double		reltuples;	HashBuildState buildstate;	/*	 * We expect to be called exactly once for any index relation. If that's	 * not the case, big trouble's what we have.	 */	if (RelationGetNumberOfBlocks(index) != 0)		elog(ERROR, "index \"%s\" already contains data",			 RelationGetRelationName(index));	/* initialize the hash index metadata page */	_hash_metapinit(index);	/* build the index */	buildstate.indtuples = 0;	/* do the heap scan */	reltuples = IndexBuildHeapScan(heap, index, indexInfo,								   hashbuildCallback, (void *) &buildstate);	/* since we just counted the # of tuples, may as well update stats */	IndexCloseAndUpdateStats(heap, reltuples, index, buildstate.indtuples);	PG_RETURN_VOID();}/* * Per-tuple callback from IndexBuildHeapScan */static voidhashbuildCallback(Relation index,				  HeapTuple htup,				  Datum *values,				  bool *isnull,				  bool tupleIsAlive,				  void *state){	HashBuildState *buildstate = (HashBuildState *) state;	IndexTuple	itup;	HashItem	hitem;	/* form an index tuple and point it at the heap tuple */	itup = index_form_tuple(RelationGetDescr(index), values, isnull);	itup->t_tid = htup->t_self;	/* Hash indexes don't index nulls, see notes in hashinsert */	if (IndexTupleHasNulls(itup))	{		pfree(itup);		return;	}	hitem = _hash_formitem(itup);	_hash_doinsert(index, hitem);	buildstate->indtuples += 1;	pfree(hitem);	pfree(itup);}/* *	hashinsert() -- insert an index tuple into a hash table. * *	Hash on the index tuple's key, find the appropriate location *	for the new tuple, and put it there. */Datumhashinsert(PG_FUNCTION_ARGS){	Relation	rel = (Relation) PG_GETARG_POINTER(0);	Datum	   *values = (Datum *) PG_GETARG_POINTER(1);	bool	   *isnull = (bool *) PG_GETARG_POINTER(2);	ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);#ifdef NOT_USED	Relation	heapRel = (Relation) PG_GETARG_POINTER(4);	bool		checkUnique = PG_GETARG_BOOL(5);#endif	HashItem	hitem;	IndexTuple	itup;	/* generate an index tuple */	itup = index_form_tuple(RelationGetDescr(rel), values, isnull);	itup->t_tid = *ht_ctid;	/*	 * If the single index key is null, we don't insert it into the index.	 * Hash tables support scans on '='. Relational algebra says that A = B	 * returns null if either A or B is null.  This means that no	 * qualification used in an index scan could ever return true on a null	 * attribute.  It also means that indices can't be used by ISNULL or	 * NOTNULL scans, but that's an artifact of the strategy map architecture	 * chosen in 1986, not of the way nulls are handled here.	 */	if (IndexTupleHasNulls(itup))	{		pfree(itup);		PG_RETURN_BOOL(false);	}	hitem = _hash_formitem(itup);	_hash_doinsert(rel, hitem);	pfree(hitem);	pfree(itup);	PG_RETURN_BOOL(true);}/* *	hashgettuple() -- Get the next tuple in the scan. */Datumhashgettuple(PG_FUNCTION_ARGS){	IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);	ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);	HashScanOpaque so = (HashScanOpaque) scan->opaque;	Relation	rel = scan->indexRelation;	Page		page;	OffsetNumber offnum;	bool		res;	/*	 * We hold pin but not lock on current buffer while outside the hash AM.	 * Reacquire the read lock here.	 */	if (BufferIsValid(so->hashso_curbuf))		_hash_chgbufaccess(rel, so->hashso_curbuf, HASH_NOLOCK, HASH_READ);	/*	 * If we've already initialized this scan, we can just advance it in the	 * appropriate direction.  If we haven't done so yet, we call a routine to	 * get the first item in the scan.	 */	if (ItemPointerIsValid(&(scan->currentItemData)))	{		/*		 * Check to see if we should kill the previously-fetched tuple.		 */		if (scan->kill_prior_tuple)		{			/*			 * Yes, so mark it by setting the LP_DELETE bit in the item flags.			 */			offnum = ItemPointerGetOffsetNumber(&(scan->currentItemData));			page = BufferGetPage(so->hashso_curbuf);			PageGetItemId(page, offnum)->lp_flags |= LP_DELETE;			/*			 * Since this can be redone later if needed, it's treated the same			 * as a commit-hint-bit status update for heap tuples: we mark the			 * buffer dirty but don't make a WAL log entry.			 */			SetBufferCommitInfoNeedsSave(so->hashso_curbuf);		}		/*		 * Now continue the scan.		 */		res = _hash_next(scan, dir);	}	else		res = _hash_first(scan, dir);	/*	 * Skip killed tuples if asked to.	 */	if (scan->ignore_killed_tuples)	{		while (res)		{			offnum = ItemPointerGetOffsetNumber(&(scan->currentItemData));			page = BufferGetPage(so->hashso_curbuf);			if (!ItemIdDeleted(PageGetItemId(page, offnum)))				break;			res = _hash_next(scan, dir);		}	}	/* Release read lock on current buffer, but keep it pinned */	if (BufferIsValid(so->hashso_curbuf))		_hash_chgbufaccess(rel, so->hashso_curbuf, HASH_READ, HASH_NOLOCK);	PG_RETURN_BOOL(res);}/* *	hashgetmulti() -- get multiple tuples at once * * This is a somewhat generic implementation: it avoids lock reacquisition * overhead, but there's no smarts about picking especially good stopping * points such as index page boundaries. */Datumhashgetmulti(PG_FUNCTION_ARGS){	IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);	ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1);	int32		max_tids = PG_GETARG_INT32(2);	int32	   *returned_tids = (int32 *) PG_GETARG_POINTER(3);	HashScanOpaque so = (HashScanOpaque) scan->opaque;	Relation	rel = scan->indexRelation;	bool		res = true;	int32		ntids = 0;	/*	 * We hold pin but not lock on current buffer while outside the hash AM.	 * Reacquire the read lock here.	 */	if (BufferIsValid(so->hashso_curbuf))		_hash_chgbufaccess(rel, so->hashso_curbuf, HASH_NOLOCK, HASH_READ);	while (ntids < max_tids)	{		/*		 * Start scan, or advance to next tuple.		 */		if (ItemPointerIsValid(&(scan->currentItemData)))			res = _hash_next(scan, ForwardScanDirection);		else			res = _hash_first(scan, ForwardScanDirection);		/*		 * Skip killed tuples if asked to.		 */		if (scan->ignore_killed_tuples)		{			while (res)			{				Page		page;				OffsetNumber offnum;				offnum = ItemPointerGetOffsetNumber(&(scan->currentItemData));				page = BufferGetPage(so->hashso_curbuf);				if (!ItemIdDeleted(PageGetItemId(page, offnum)))					break;				res = _hash_next(scan, ForwardScanDirection);			}		}		if (!res)			break;		/* Save tuple ID, and continue scanning */		tids[ntids] = scan->xs_ctup.t_self;		ntids++;	}	/* Release read lock on current buffer, but keep it pinned */	if (BufferIsValid(so->hashso_curbuf))		_hash_chgbufaccess(rel, so->hashso_curbuf, HASH_READ, HASH_NOLOCK);	*returned_tids = ntids;	PG_RETURN_BOOL(res);}/* *	hashbeginscan() -- start a scan on a hash index */Datumhashbeginscan(PG_FUNCTION_ARGS){	Relation	rel = (Relation) PG_GETARG_POINTER(0);	int			keysz = PG_GETARG_INT32(1);	ScanKey		scankey = (ScanKey) PG_GETARG_POINTER(2);	IndexScanDesc scan;	HashScanOpaque so;	scan = RelationGetIndexScan(rel, keysz, scankey);	so = (HashScanOpaque) palloc(sizeof(HashScanOpaqueData));	so->hashso_bucket_valid = false;	so->hashso_bucket_blkno = 0;	so->hashso_curbuf = so->hashso_mrkbuf = InvalidBuffer;	scan->opaque = so;	/* register scan in case we change pages it's using */	_hash_regscan(scan);	PG_RETURN_POINTER(scan);

⌨️ 快捷键说明

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