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

📄 gistproc.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * gistproc.c *	  Support procedures for GiSTs over 2-D objects (boxes, polygons, circles). * * This gives R-tree behavior, with Guttman's poly-time split algorithm. * * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	$PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.13 2008/01/01 19:45:46 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/gist.h"#include "access/skey.h"#include "utils/geo_decls.h"static bool gist_box_leaf_consistent(BOX *key, BOX *query,						 StrategyNumber strategy);static double size_box(Datum dbox);static bool rtree_internal_consistent(BOX *key, BOX *query,						  StrategyNumber strategy);/************************************************** * Box ops **************************************************/static Datumrt_box_union(PG_FUNCTION_ARGS){	BOX		   *a = PG_GETARG_BOX_P(0);	BOX		   *b = PG_GETARG_BOX_P(1);	BOX		   *n;	n = (BOX *) palloc(sizeof(BOX));	n->high.x = Max(a->high.x, b->high.x);	n->high.y = Max(a->high.y, b->high.y);	n->low.x = Min(a->low.x, b->low.x);	n->low.y = Min(a->low.y, b->low.y);	PG_RETURN_BOX_P(n);}static Datumrt_box_inter(PG_FUNCTION_ARGS){	BOX		   *a = PG_GETARG_BOX_P(0);	BOX		   *b = PG_GETARG_BOX_P(1);	BOX		   *n;	n = (BOX *) palloc(sizeof(BOX));	n->high.x = Min(a->high.x, b->high.x);	n->high.y = Min(a->high.y, b->high.y);	n->low.x = Max(a->low.x, b->low.x);	n->low.y = Max(a->low.y, b->low.y);	if (n->high.x < n->low.x || n->high.y < n->low.y)	{		pfree(n);		/* Indicate "no intersection" by returning NULL pointer */		n = NULL;	}	PG_RETURN_BOX_P(n);}/* * The GiST Consistent method for boxes * * Should return false if for all data items x below entry, * the predicate x op query must be FALSE, where op is the oper * corresponding to strategy in the pg_amop table. */Datumgist_box_consistent(PG_FUNCTION_ARGS){	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);	BOX		   *query = PG_GETARG_BOX_P(1);	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);	if (DatumGetBoxP(entry->key) == NULL || query == NULL)		PG_RETURN_BOOL(FALSE);	/*	 * if entry is not leaf, use rtree_internal_consistent, else use	 * gist_box_leaf_consistent	 */	if (GIST_LEAF(entry))		PG_RETURN_BOOL(gist_box_leaf_consistent(DatumGetBoxP(entry->key),												query,												strategy));	else		PG_RETURN_BOOL(rtree_internal_consistent(DatumGetBoxP(entry->key),												 query,												 strategy));}static voidadjustBox(BOX *b, BOX *addon){	if (b->high.x < addon->high.x)		b->high.x = addon->high.x;	if (b->low.x > addon->low.x)		b->low.x = addon->low.x;	if (b->high.y < addon->high.y)		b->high.y = addon->high.y;	if (b->low.y > addon->low.y)		b->low.y = addon->low.y;}/* * The GiST Union method for boxes * * returns the minimal bounding box that encloses all the entries in entryvec */Datumgist_box_union(PG_FUNCTION_ARGS){	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);	int		   *sizep = (int *) PG_GETARG_POINTER(1);	int			numranges,				i;	BOX		   *cur,			   *pageunion;	numranges = entryvec->n;	pageunion = (BOX *) palloc(sizeof(BOX));	cur = DatumGetBoxP(entryvec->vector[0].key);	memcpy((void *) pageunion, (void *) cur, sizeof(BOX));	for (i = 1; i < numranges; i++)	{		cur = DatumGetBoxP(entryvec->vector[i].key);		adjustBox(pageunion, cur);	}	*sizep = sizeof(BOX);	PG_RETURN_POINTER(pageunion);}/* * GiST Compress methods for boxes * * do not do anything. */Datumgist_box_compress(PG_FUNCTION_ARGS){	PG_RETURN_POINTER(PG_GETARG_POINTER(0));}/* * GiST DeCompress method for boxes (also used for polygons and circles) * * do not do anything --- we just use the stored box as is. */Datumgist_box_decompress(PG_FUNCTION_ARGS){	PG_RETURN_POINTER(PG_GETARG_POINTER(0));}/* * The GiST Penalty method for boxes * * As in the R-tree paper, we use change in area as our penalty metric */Datumgist_box_penalty(PG_FUNCTION_ARGS){	GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);	GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);	float	   *result = (float *) PG_GETARG_POINTER(2);	Datum		ud;	ud = DirectFunctionCall2(rt_box_union, origentry->key, newentry->key);	*result = (float) (size_box(ud) - size_box(origentry->key));	PG_RETURN_POINTER(result);}static voidchooseLR(GIST_SPLITVEC *v,		 OffsetNumber *list1, int nlist1, BOX *union1,		 OffsetNumber *list2, int nlist2, BOX *union2){	bool		firstToLeft = true;	if (v->spl_ldatum_exists || v->spl_rdatum_exists)	{		if (v->spl_ldatum_exists && v->spl_rdatum_exists)		{			BOX			LRl = *union1,						LRr = *union2;			BOX			RLl = *union2,						RLr = *union1;			double		sizeLR,						sizeRL;			adjustBox(&LRl, DatumGetBoxP(v->spl_ldatum));			adjustBox(&LRr, DatumGetBoxP(v->spl_rdatum));			adjustBox(&RLl, DatumGetBoxP(v->spl_ldatum));			adjustBox(&RLr, DatumGetBoxP(v->spl_rdatum));			sizeLR = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&LRl), BoxPGetDatum(&LRr)));			sizeRL = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&RLl), BoxPGetDatum(&RLr)));			if (sizeLR > sizeRL)				firstToLeft = false;		}		else		{			float		p1,						p2;			GISTENTRY	oldUnion,						addon;			gistentryinit(oldUnion, (v->spl_ldatum_exists) ? v->spl_ldatum : v->spl_rdatum,						  NULL, NULL, InvalidOffsetNumber, FALSE);			gistentryinit(addon, BoxPGetDatum(union1), NULL, NULL, InvalidOffsetNumber, FALSE);			DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union1), PointerGetDatum(&p1));			gistentryinit(addon, BoxPGetDatum(union2), NULL, NULL, InvalidOffsetNumber, FALSE);			DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union2), PointerGetDatum(&p2));			if ((v->spl_ldatum_exists && p1 > p2) || (v->spl_rdatum_exists && p1 < p2))				firstToLeft = false;		}	}	if (firstToLeft)	{		v->spl_left = list1;		v->spl_right = list2;		v->spl_nleft = nlist1;		v->spl_nright = nlist2;		if (v->spl_ldatum_exists)			adjustBox(union1, DatumGetBoxP(v->spl_ldatum));		v->spl_ldatum = BoxPGetDatum(union1);		if (v->spl_rdatum_exists)			adjustBox(union2, DatumGetBoxP(v->spl_rdatum));		v->spl_rdatum = BoxPGetDatum(union2);	}	else	{		v->spl_left = list2;		v->spl_right = list1;		v->spl_nleft = nlist2;		v->spl_nright = nlist1;		if (v->spl_ldatum_exists)			adjustBox(union2, DatumGetBoxP(v->spl_ldatum));		v->spl_ldatum = BoxPGetDatum(union2);		if (v->spl_rdatum_exists)			adjustBox(union1, DatumGetBoxP(v->spl_rdatum));		v->spl_rdatum = BoxPGetDatum(union1);	}	v->spl_ldatum_exists = v->spl_rdatum_exists = false;}/* * The GiST PickSplit method * * New linear algorithm, see 'New Linear Node Splitting Algorithm for R-tree', * C.H.Ang and T.C.Tan */Datumgist_box_picksplit(PG_FUNCTION_ARGS){	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);	GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);	OffsetNumber i;	OffsetNumber *listL,			   *listR,			   *listB,			   *listT;	BOX		   *unionL,			   *unionR,			   *unionB,			   *unionT;	int			posL,				posR,				posB,				posT;	BOX			pageunion;	BOX		   *cur;	char		direction = ' ';	bool		allisequal = true;	OffsetNumber maxoff;	int			nbytes;	posL = posR = posB = posT = 0;	maxoff = entryvec->n - 1;	cur = DatumGetBoxP(entryvec->vector[FirstOffsetNumber].key);	memcpy((void *) &pageunion, (void *) cur, sizeof(BOX));	/* find MBR */	for (i = OffsetNumberNext(FirstOffsetNumber); i <= maxoff; i = OffsetNumberNext(i))	{		cur = DatumGetBoxP(entryvec->vector[i].key);		if (allisequal == true && (								   pageunion.high.x != cur->high.x ||								   pageunion.high.y != cur->high.y ||								   pageunion.low.x != cur->low.x ||								   pageunion.low.y != cur->low.y								   ))			allisequal = false;		adjustBox(&pageunion, cur);	}	nbytes = (maxoff + 2) * sizeof(OffsetNumber);	listL = (OffsetNumber *) palloc(nbytes);	listR = (OffsetNumber *) palloc(nbytes);	unionL = (BOX *) palloc(sizeof(BOX));	unionR = (BOX *) palloc(sizeof(BOX));	if (allisequal)	{		cur = DatumGetBoxP(entryvec->vector[OffsetNumberNext(FirstOffsetNumber)].key);		if (memcmp((void *) cur, (void *) &pageunion, sizeof(BOX)) == 0)		{			v->spl_left = listL;			v->spl_right = listR;			v->spl_nleft = v->spl_nright = 0;			memcpy((void *) unionL, (void *) &pageunion, sizeof(BOX));			memcpy((void *) unionR, (void *) &pageunion, sizeof(BOX));			for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))			{				if (i <= (maxoff - FirstOffsetNumber + 1) / 2)				{					v->spl_left[v->spl_nleft] = i;					v->spl_nleft++;				}				else				{					v->spl_right[v->spl_nright] = i;					v->spl_nright++;				}			}			if (v->spl_ldatum_exists)				adjustBox(unionL, DatumGetBoxP(v->spl_ldatum));			v->spl_ldatum = BoxPGetDatum(unionL);			if (v->spl_rdatum_exists)				adjustBox(unionR, DatumGetBoxP(v->spl_rdatum));			v->spl_rdatum = BoxPGetDatum(unionR);			v->spl_ldatum_exists = v->spl_rdatum_exists = false;			PG_RETURN_POINTER(v);		}	}	listB = (OffsetNumber *) palloc(nbytes);	listT = (OffsetNumber *) palloc(nbytes);	unionB = (BOX *) palloc(sizeof(BOX));	unionT = (BOX *) palloc(sizeof(BOX));#define ADDLIST( list, unionD, pos, num ) do { \	if ( pos ) { \		if ( (unionD)->high.x < cur->high.x ) (unionD)->high.x	= cur->high.x; \		if ( (unionD)->low.x  > cur->low.x	) (unionD)->low.x	= cur->low.x; \		if ( (unionD)->high.y < cur->high.y ) (unionD)->high.y	= cur->high.y; \		if ( (unionD)->low.y  > cur->low.y	) (unionD)->low.y	= cur->low.y; \	} else { \			memcpy( (void*)(unionD), (void*) cur, sizeof( BOX ) );	\	} \	(list)[pos] = num; \	(pos)++; \} while(0)	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))	{		cur = DatumGetBoxP(entryvec->vector[i].key);		if (cur->low.x - pageunion.low.x < pageunion.high.x - cur->high.x)			ADDLIST(listL, unionL, posL, i);		else			ADDLIST(listR, unionR, posR, i);		if (cur->low.y - pageunion.low.y < pageunion.high.y - cur->high.y)			ADDLIST(listB, unionB, posB, i);		else			ADDLIST(listT, unionT, posT, i);	}#define LIMIT_RATIO 0.1#define _IS_BADRATIO(x,y)	( (y) == 0 || (float)(x)/(float)(y) < LIMIT_RATIO )#define IS_BADRATIO(x,y) ( _IS_BADRATIO((x),(y)) || _IS_BADRATIO((y),(x)) )	/* bad disposition, try to split by centers of boxes  */	if (IS_BADRATIO(posR, posL) && IS_BADRATIO(posT, posB))	{		double		avgCenterX = 0.0,					avgCenterY = 0.0;		double		CenterX,					CenterY;		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))		{

⌨️ 快捷键说明

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