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

📄 gist.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * gist.c *	  interface routines for the postgres GiST index access method. * * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.38.2.1 1999/08/02 05:24:28 scrappy Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/gist.h"#include "access/gistscan.h"#include "access/heapam.h"#include "catalog/index.h"#include "catalog/pg_index.h"#include "executor/executor.h"#include "utils/syscache.h"/* non-export function prototypes */static InsertIndexResult gistdoinsert(Relation r, IndexTuple itup,			 GISTSTATE *GISTstate);static InsertIndexResult gistentryinsert(Relation r, GISTSTACK *stk,				IndexTuple tup,				GISTSTATE *giststate);static void gistentryinserttwo(Relation r, GISTSTACK *stk, IndexTuple ltup,				   IndexTuple rtup, GISTSTATE *giststate);static void gistAdjustKeys(Relation r, GISTSTACK *stk, BlockNumber blk,			   char *datum, int att_size, GISTSTATE *giststate);static void gistintinsert(Relation r, GISTSTACK *stk, IndexTuple ltup,			  IndexTuple rtup, GISTSTATE *giststate);static InsertIndexResult gistSplit(Relation r, Buffer buffer,		  GISTSTACK *stack, IndexTuple itup,		  GISTSTATE *giststate);static void gistnewroot(GISTSTATE *giststate, Relation r, IndexTuple lt,			IndexTuple rt);static void GISTInitBuffer(Buffer b, uint32 f);static BlockNumber gistChooseSubtree(Relation r, IndexTuple itup, int level,				  GISTSTATE *giststate,				  GISTSTACK **retstack, Buffer *leafbuf);static OffsetNumber gistchoose(Relation r, Page p, IndexTuple it,		   GISTSTATE *giststate);static int	gistnospace(Page p, IndexTuple it);void		gistdelete(Relation r, ItemPointer tid);static IndexTuple gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t);static void gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr,			   Relation r, Page pg, OffsetNumber o, int b, bool l);#ifdef GISTDEBUGstatic char *int_range_out(INTRANGE *r);#endif/*** routine to build an index.  Basically calls insert over and over*/voidgistbuild(Relation heap,		  Relation index,		  int natts,		  AttrNumber *attnum,		  IndexStrategy istrat,		  uint16 pint,		  Datum *params,		  FuncIndexInfo *finfo,		  PredInfo *predInfo){	HeapScanDesc scan;	AttrNumber	i;	HeapTuple	htup;	IndexTuple	itup;	TupleDesc	hd,				id;	InsertIndexResult res;	Datum	   *d;	bool	   *nulls;	int			nb,				nh,				ni;#ifndef OMIT_PARTIAL_INDEX	ExprContext *econtext;	TupleTable	tupleTable;	TupleTableSlot *slot;#endif	Oid			hrelid,				irelid;	Node	   *pred,			   *oldPred;	GISTSTATE	giststate;	GISTENTRY	tmpcentry;	Buffer		buffer = InvalidBuffer;	bool	   *compvec;	/* no locking is needed */	setheapoverride(true);		/* so we can see the new pg_index tuple */	initGISTstate(&giststate, index);	setheapoverride(false);	pred = predInfo->pred;	oldPred = predInfo->oldPred;	/*	 * We expect to be called exactly once for any index relation. If	 * that's not the case, big trouble's what we have.	 */	if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0)		elog(ERROR, "%s already contains data", index->rd_rel->relname.data);	/* initialize the root page (if this is a new index) */	if (oldPred == NULL)	{		buffer = ReadBuffer(index, P_NEW);		GISTInitBuffer(buffer, F_LEAF);		WriteBuffer(buffer);	}	/* init the tuple descriptors and get set for a heap scan */	hd = RelationGetDescr(heap);	id = RelationGetDescr(index);	d = (Datum *) palloc(natts * sizeof(*d));	nulls = (bool *) palloc(natts * sizeof(*nulls));	/*	 * If this is a predicate (partial) index, we will need to evaluate	 * the predicate using ExecQual, which requires the current tuple to	 * be in a slot of a TupleTable.  In addition, ExecQual must have an	 * ExprContext referring to that slot.	Here, we initialize dummy	 * TupleTable and ExprContext objects for this purpose. --Nels, Feb	 * '92	 */#ifndef OMIT_PARTIAL_INDEX	if (pred != NULL || oldPred != NULL)	{		tupleTable = ExecCreateTupleTable(1);		slot = ExecAllocTableSlot(tupleTable);		econtext = makeNode(ExprContext);		FillDummyExprContext(econtext, slot, hd, buffer);	}	else/* shut the compiler up */	{		tupleTable = NULL;		slot = NULL;		econtext = NULL;	}#endif	 /* OMIT_PARTIAL_INDEX */	/* int the tuples as we insert them */	nh = ni = 0;	scan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);	while (HeapTupleIsValid(htup = heap_getnext(scan, 0)))	{		nh++;		/*		 * If oldPred != NULL, this is an EXTEND INDEX command, so skip		 * this tuple if it was already in the existing partial index		 */		if (oldPred != NULL)		{#ifndef OMIT_PARTIAL_INDEX			/* SetSlotContents(slot, htup); */			slot->val = htup;			if (ExecQual((List *) oldPred, econtext) == true)			{				ni++;				continue;			}#endif	 /* OMIT_PARTIAL_INDEX */		}		/*		 * Skip this tuple if it doesn't satisfy the partial-index		 * predicate		 */		if (pred != NULL)		{#ifndef OMIT_PARTIAL_INDEX			/* SetSlotContents(slot, htup); */			slot->val = htup;			if (ExecQual((List *) pred, econtext) == false)				continue;#endif	 /* OMIT_PARTIAL_INDEX */		}		ni++;		/*		 * For the current heap tuple, extract all the attributes we use		 * in this index, and note which are null.		 */		for (i = 1; i <= natts; i++)		{			int			attoff;			bool		attnull;			/*			 * Offsets are from the start of the tuple, and are			 * zero-based; indices are one-based.  The next call returns i			 * - 1.  That's data hiding for you.			 */			attoff = AttrNumberGetAttrOffset(i);			/*			 * d[attoff] = HeapTupleGetAttributeValue(htup, buffer,			 */			d[attoff] = GetIndexValue(htup,									  hd,									  attoff,									  attnum,									  finfo,									  &attnull);			nulls[attoff] = (attnull ? 'n' : ' ');		}		/* immediately compress keys to normalize */		compvec = (bool *) palloc(sizeof(bool) * natts);		for (i = 0; i < natts; i++)		{			gistcentryinit(&giststate, &tmpcentry, (char *) d[i],						   (Relation) NULL, (Page) NULL, (OffsetNumber) 0,						   -1 /* size is currently bogus */ , TRUE);			if (d[i] != (Datum) tmpcentry.pred && !(giststate.keytypbyval))				compvec[i] = TRUE;			else				compvec[i] = FALSE;			d[i] = (Datum) tmpcentry.pred;		}		/* form an index tuple and point it at the heap tuple */		itup = index_formtuple(id, &d[0], nulls);		itup->t_tid = htup->t_self;		/*		 * Since we already have the index relation locked, we call		 * gistdoinsert directly.  Normal access method calls dispatch		 * through gistinsert, 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.		 */		res = gistdoinsert(index, itup, &giststate);		for (i = 0; i < natts; i++)			if (compvec[i] == TRUE)				pfree((char *) d[i]);		pfree(itup);		pfree(res);		pfree(compvec);	}	/* okay, all heap tuples are indexed */	heap_endscan(scan);	if (pred != NULL || oldPred != NULL)	{#ifndef OMIT_PARTIAL_INDEX		ExecDestroyTupleTable(tupleTable, true);		pfree(econtext);#endif	 /* OMIT_PARTIAL_INDEX */	}	/*	 * Since we just inted the tuples in the heap, we update its stats in	 * pg_relation to guarantee that the planner takes advantage of the	 * index we just created.  UpdateStats() does a	 * CommandinterIncrement(), which flushes changed entries from the	 * system relcache.  The act of constructing an index changes these	 * heap and index tuples in the system catalogs, so they need to be	 * flushed.  We close them to guarantee that they will be.	 */	hrelid = RelationGetRelid(heap);	irelid = RelationGetRelid(index);	heap_close(heap);	index_close(index);	UpdateStats(hrelid, nh, true);	UpdateStats(irelid, ni, false);	if (oldPred != NULL)	{		if (ni == nh)			pred = NULL;		UpdateIndexPredicate(irelid, oldPred, pred);	}	/* be tidy */	pfree(nulls);	pfree(d);}/* *	gistinsert -- wrapper for GiST tuple insertion. * *	  This is the public interface routine for tuple insertion in GiSTs. *	  It doesn't do any work; just locks the relation and passes the buck. */InsertIndexResultgistinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation heapRel){	InsertIndexResult res;	IndexTuple	itup;	GISTSTATE	giststate;	GISTENTRY	tmpentry;	int			i;	bool	   *compvec;	initGISTstate(&giststate, r);	/* immediately compress keys to normalize */	compvec = (bool *) palloc(sizeof(bool) * r->rd_att->natts);	for (i = 0; i < r->rd_att->natts; i++)	{		gistcentryinit(&giststate, &tmpentry, (char *) datum[i],					   (Relation) NULL, (Page) NULL, (OffsetNumber) 0,					   -1 /* size is currently bogus */ , TRUE);		if (datum[i] != (Datum) tmpentry.pred && !(giststate.keytypbyval))			compvec[i] = TRUE;		else			compvec[i] = FALSE;		datum[i] = (Datum) tmpentry.pred;	}	itup = index_formtuple(RelationGetDescr(r), datum, nulls);	itup->t_tid = *ht_ctid;	/*	 * Notes in ExecUtils:ExecOpenIndices()	 *	 * RelationSetLockForWrite(r);	 */	res = gistdoinsert(r, itup, &giststate);	for (i = 0; i < r->rd_att->natts; i++)		if (compvec[i] == TRUE)			pfree((char *) datum[i]);	pfree(itup);	pfree(compvec);	return res;}/*** Take a compressed entry, and install it on a page.  Since we now know** where the entry will live, we decompress it and recompress it using** that knowledge (some compression routines may want to fish around** on the page, for example, or do something special for leaf nodes.)*/static OffsetNumbergistPageAddItem(GISTSTATE *giststate,				Relation r,				Page page,				Item item,				Size size,				OffsetNumber offsetNumber,				ItemIdFlags flags,				GISTENTRY *dentry,				IndexTuple *newtup){	GISTENTRY	tmpcentry;	IndexTuple	itup = (IndexTuple) item;	/*	 * recompress the item given that we now know the exact page and	 * offset for insertion	 */	gistdentryinit(giststate, dentry,				   (((char *) itup) + sizeof(IndexTupleData)),			  (Relation) 0, (Page) 0, (OffsetNumber) InvalidOffsetNumber,				   IndexTupleSize(itup) - sizeof(IndexTupleData), FALSE);	gistcentryinit(giststate, &tmpcentry, dentry->pred, r, page,				   offsetNumber, dentry->bytes, FALSE);	*newtup = gist_tuple_replacekey(r, *dentry, itup);	/* be tidy */	if (tmpcentry.pred != dentry->pred		&& tmpcentry.pred != (((char *) itup) + sizeof(IndexTupleData)))		pfree(tmpcentry.pred);	return (PageAddItem(page, (Item) *newtup, IndexTupleSize(*newtup),						offsetNumber, flags));}static InsertIndexResultgistdoinsert(Relation r,			 IndexTuple itup,	/* itup contains compressed entry */			 GISTSTATE *giststate){	GISTENTRY	tmpdentry;	InsertIndexResult res;	OffsetNumber l;	GISTSTACK  *stack;	Buffer		buffer;	BlockNumber blk;	Page		page;	OffsetNumber off;	IndexTuple	newtup;	/* 3rd arg is ignored for now */	blk = gistChooseSubtree(r, itup, 0, giststate, &stack, &buffer);	page = (Page) BufferGetPage(buffer);	if (gistnospace(page, itup))	{		/* need to do a split */		res = gistSplit(r, buffer, stack, itup, giststate);		gistfreestack(stack);		WriteBuffer(buffer);	/* don't forget to release buffer! */		return res;	}	if (PageIsEmpty(page))		off = FirstOffsetNumber;	else		off = OffsetNumberNext(PageGetMaxOffsetNumber(page));	/* add the item and write the buffer */	l = gistPageAddItem(giststate, r, page, (Item) itup, IndexTupleSize(itup),						off, LP_USED, &tmpdentry, &newtup);	WriteBuffer(buffer);	/* now expand the page boundary in the parent to include the new child */	gistAdjustKeys(r, stack, blk, tmpdentry.pred, tmpdentry.bytes, giststate);	gistfreestack(stack);	/* be tidy */	if (itup != newtup)		pfree(newtup);	if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData)))		pfree(tmpdentry.pred);	/* build and return an InsertIndexResult for this insertion */	res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));	ItemPointerSet(&(res->pointerData), blk, l);	return res;}

⌨️ 快捷键说明

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