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

📄 rtree.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * rtree.c *	  interface routines for the postgres rtree indexed access method. * * 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/rtree/rtree.c,v 1.92.2.1 2005/11/22 18:23:04 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "access/rtree.h"#include "access/xlogutils.h"#include "catalog/index.h"#include "commands/vacuum.h"#include "executor/executor.h"#include "miscadmin.h"/* * XXX We assume that all datatypes indexable in rtrees are pass-by-reference. * To fix this, you'd need to improve the IndexTupleGetDatum() macro, and * do something with the various datum-pfreeing code.  However, it's not that * unreasonable an assumption in practice. */#define IndexTupleGetDatum(itup)  \	PointerGetDatum(((char *) (itup)) + sizeof(IndexTupleData))/* * Space-allocation macros.  Note we count the item's line pointer in its size. */#define RTPageAvailSpace  \	(BLCKSZ - (sizeof(PageHeaderData) - sizeof(ItemIdData)) \	 - MAXALIGN(sizeof(RTreePageOpaqueData)))#define IndexTupleTotalSize(itup)  \	(MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData))#define IndexTupleAttSize(itup)  \	(IndexTupleSize(itup) - sizeof(IndexTupleData))/* results of rtpicksplit() */typedef struct SPLITVEC{	OffsetNumber *spl_left;	int			spl_nleft;	Datum		spl_ldatum;	OffsetNumber *spl_right;	int			spl_nright;	Datum		spl_rdatum;} SPLITVEC;/* for sorting tuples by cost, for picking split */typedef struct SPLITCOST{	OffsetNumber offset_number;	float		cost_differential;	bool		choose_left;} SPLITCOST;typedef struct RTSTATE{	FmgrInfo	unionFn;		/* union function */	FmgrInfo	sizeFn;			/* size function */	FmgrInfo	interFn;		/* intersection function */} RTSTATE;/* Working state for rtbuild and its callback */typedef struct{	RTSTATE		rtState;	double		indtuples;} RTBuildState;/* non-export function prototypes */static void rtbuildCallback(Relation index,				HeapTuple htup,				Datum *values,				bool *isnull,				bool tupleIsAlive,				void *state);static void rtdoinsert(Relation r, IndexTuple itup, RTSTATE *rtstate);static void rttighten(Relation r, RTSTACK *stk, Datum datum, int att_size,		  RTSTATE *rtstate);static void rtdosplit(Relation r, Buffer buffer, RTSTACK *stack,		  IndexTuple itup, RTSTATE *rtstate);static void rtintinsert(Relation r, RTSTACK *stk, IndexTuple ltup,			IndexTuple rtup, RTSTATE *rtstate);static void rtnewroot(Relation r, IndexTuple lt, IndexTuple rt);static void rtpicksplit(Relation r, Page page, SPLITVEC *v, IndexTuple itup,			RTSTATE *rtstate);static void RTInitBuffer(Buffer b, uint32 f);static OffsetNumber choose(Relation r, Page p, IndexTuple it,	   RTSTATE *rtstate);static int	nospace(Page p, IndexTuple it);static void initRtstate(RTSTATE *rtstate, Relation index);static int	qsort_comp_splitcost(const void *a, const void *b);/* * routine to build an index.  Basically calls insert over and over */Datumrtbuild(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;	RTBuildState buildstate;	Buffer		buffer;	/* no locking is needed */	initRtstate(&buildstate.rtState, index);	/*	 * 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 root page */	buffer = ReadBuffer(index, P_NEW);	RTInitBuffer(buffer, F_LEAF);	WriteBuffer(buffer);	/* build the index */	buildstate.indtuples = 0;	/* do the heap scan */	reltuples = IndexBuildHeapScan(heap, index, indexInfo,								   rtbuildCallback, (void *) &buildstate);	/* okay, all heap tuples are indexed */	/* 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 voidrtbuildCallback(Relation index,				HeapTuple htup,				Datum *values,				bool *isnull,				bool tupleIsAlive,				void *state){	RTBuildState *buildstate = (RTBuildState *) state;	IndexTuple	itup;	/* 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;	/* rtree indexes don't index nulls, see notes in rtinsert */	if (IndexTupleHasNulls(itup))	{		pfree(itup);		return;	}	/*	 * Since we already have the index relation locked, we call rtdoinsert	 * directly.  Normal access method calls dispatch through rtinsert, which	 * locks the relation for write.  This is the right thing to do if you're	 * inserting single tups, but not when you're initializing the whole index	 * at once.	 */	rtdoinsert(index, itup, &buildstate->rtState);	buildstate->indtuples += 1;	pfree(itup);}/* *	rtinsert -- wrapper for rtree tuple insertion. * *	  This is the public interface routine for tuple insertion in rtrees. *	  It doesn't do any work; just locks the relation and passes the buck. */Datumrtinsert(PG_FUNCTION_ARGS){	Relation	r = (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	IndexTuple	itup;	RTSTATE		rtState;	/* generate an index tuple */	itup = index_form_tuple(RelationGetDescr(r), values, isnull);	itup->t_tid = *ht_ctid;	/*	 * Currently, rtrees do not support indexing NULLs; considerable	 * infrastructure work would have to be done to do anything reasonable	 * with a NULL.	 */	if (IndexTupleHasNulls(itup))	{		pfree(itup);		PG_RETURN_BOOL(false);	}	initRtstate(&rtState, r);	/*	 * Since rtree is not marked "amconcurrent" in pg_am, caller should have	 * acquired exclusive lock on index relation.  We need no locking here.	 */	rtdoinsert(r, itup, &rtState);	PG_RETURN_BOOL(true);}static voidrtdoinsert(Relation r, IndexTuple itup, RTSTATE *rtstate){	Page		page;	Buffer		buffer;	BlockNumber blk;	IndexTuple	which;	OffsetNumber l;	RTSTACK    *stack;	RTreePageOpaque opaque;	Datum		datum;	blk = P_ROOT;	buffer = InvalidBuffer;	stack = NULL;	do	{		/* release the current buffer, read in the next one */		buffer = ReleaseAndReadBuffer(buffer, r, blk);		page = (Page) BufferGetPage(buffer);		opaque = (RTreePageOpaque) PageGetSpecialPointer(page);		if (!(opaque->flags & F_LEAF))		{			RTSTACK    *n;			ItemId		iid;			n = (RTSTACK *) palloc(sizeof(RTSTACK));			n->rts_parent = stack;			n->rts_blk = blk;			n->rts_child = choose(r, page, itup, rtstate);			stack = n;			iid = PageGetItemId(page, n->rts_child);			which = (IndexTuple) PageGetItem(page, iid);			blk = ItemPointerGetBlockNumber(&(which->t_tid));		}	} while (!(opaque->flags & F_LEAF));	if (nospace(page, itup))	{		/* need to do a split */		rtdosplit(r, buffer, stack, itup, rtstate);		freestack(stack);		WriteBuffer(buffer);	/* don't forget to release buffer! */		return;	}	/* add the item and write the buffer */	if (PageIsEmpty(page))	{		l = PageAddItem(page, (Item) itup, IndexTupleSize(itup),						FirstOffsetNumber,						LP_USED);	}	else	{		l = PageAddItem(page, (Item) itup, IndexTupleSize(itup),						OffsetNumberNext(PageGetMaxOffsetNumber(page)),						LP_USED);	}	if (l == InvalidOffsetNumber)		elog(ERROR, "failed to add index item to \"%s\"",			 RelationGetRelationName(r));	WriteBuffer(buffer);	datum = IndexTupleGetDatum(itup);	/* now expand the page boundary in the parent to include the new child */	rttighten(r, stack, datum, IndexTupleAttSize(itup), rtstate);	freestack(stack);}static voidrttighten(Relation r,		  RTSTACK *stk,		  Datum datum,		  int att_size,		  RTSTATE *rtstate){	Datum		oldud;	Datum		tdatum;	Page		p;	float		old_size,				newd_size;	Buffer		b;	if (stk == NULL)		return;	b = ReadBuffer(r, stk->rts_blk);	p = BufferGetPage(b);	oldud = IndexTupleGetDatum(PageGetItem(p,										   PageGetItemId(p, stk->rts_child)));	FunctionCall2(&rtstate->sizeFn, oldud,				  PointerGetDatum(&old_size));	datum = FunctionCall2(&rtstate->unionFn, oldud, datum);	FunctionCall2(&rtstate->sizeFn, datum,				  PointerGetDatum(&newd_size));	/*	 * If newd_size == 0 we have degenerate rectangles, so we don't know if	 * there was any change, so we have to assume there was.	 */	if ((newd_size == 0) || (newd_size != old_size))	{		TupleDesc	td = RelationGetDescr(r);		if (td->attrs[0]->attlen < 0)		{			/*			 * This is an internal page, so 'oldud' had better be a union			 * (constant-length) key, too.	(See comment below.)			 */			Assert(VARSIZE(DatumGetPointer(datum)) ==				   VARSIZE(DatumGetPointer(oldud)));			memmove(DatumGetPointer(oldud), DatumGetPointer(datum),					VARSIZE(DatumGetPointer(datum)));		}		else		{			memmove(DatumGetPointer(oldud), DatumGetPointer(datum),					att_size);		}		WriteBuffer(b);		/*		 * The user may be defining an index on variable-sized data (like		 * polygons).  If so, we need to get a constant-sized datum for		 * insertion on the internal page.	We do this by calling the union		 * proc, which is required to return a rectangle.		 */		tdatum = FunctionCall2(&rtstate->unionFn, datum, datum);		rttighten(r, stk->rts_parent, tdatum, att_size, rtstate);		pfree(DatumGetPointer(tdatum));	}	else		ReleaseBuffer(b);	pfree(DatumGetPointer(datum));}/* *	rtdosplit -- split a page in the tree. * *	  rtpicksplit does the interesting work of choosing the split. *	  This routine just does the bit-pushing. */static voidrtdosplit(Relation r,		  Buffer buffer,		  RTSTACK *stack,		  IndexTuple itup,		  RTSTATE *rtstate){	Page		p;	Buffer		leftbuf,				rightbuf;	Page		left,				right;	ItemId		itemid;	IndexTuple	item;	IndexTuple	ltup,				rtup;	OffsetNumber maxoff;	OffsetNumber i;	OffsetNumber leftoff,				rightoff;	BlockNumber lbknum,				rbknum;	BlockNumber bufblock;	RTreePageOpaque opaque;	bool	   *isnull;	SPLITVEC	v;	OffsetNumber *spl_left,			   *spl_right;	TupleDesc	tupDesc;	int			n;	OffsetNumber newitemoff;	p = (Page) BufferGetPage(buffer);	opaque = (RTreePageOpaque) PageGetSpecialPointer(p);	rtpicksplit(r, p, &v, itup, rtstate);	/*	 * The root of the tree is the first block in the relation.  If we're	 * about to split the root, we need to do some hocus-pocus to enforce this	 * guarantee.	 */

⌨️ 快捷键说明

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