gistproc.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 709 行 · 第 1/2 页

C
709
字号
/*------------------------------------------------------------------------- * * 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-2005, 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.3 2005/10/15 02:49:08 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/gist.h"#include "access/itup.h"#include "access/rtree.h"#include "utils/geo_decls.h"typedef struct{	BOX		   *key;	int			pos;} KBsort;static int	compare_KB(const void *a, const void *b);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 **************************************************//* * 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));}/* * 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);		if (pageunion->high.x < cur->high.x)			pageunion->high.x = cur->high.x;		if (pageunion->low.x > cur->low.x)			pageunion->low.x = cur->low.x;		if (pageunion->high.y < cur->high.y)			pageunion->high.y = cur->high.y;		if (pageunion->low.y > cur->low.y)			pageunion->low.y = cur->low.y;	}	*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);}/* * qsort comparator for box areas */static intcompare_KB(const void *a, const void *b){	BOX		   *abox = ((const KBsort *) a)->key;	BOX		   *bbox = ((const KBsort *) b)->key;	double		sa = (abox->high.x - abox->low.x) * (abox->high.y - abox->low.y);	double		sb = (bbox->high.x - bbox->low.x) * (bbox->high.y - bbox->low.y);	if (sa == sb)		return 0;	return (sa > sb) ? 1 : -1;}/* * 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;		if (pageunion.high.x < cur->high.x)			pageunion.high.x = cur->high.x;		if (pageunion.low.x > cur->low.x)			pageunion.low.x = cur->low.x;		if (pageunion.high.y < cur->high.y)			pageunion.high.y = cur->high.y;		if (pageunion.low.y > cur->low.y)			pageunion.low.y = cur->low.y;	}	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++;				}			}			v->spl_ldatum = BoxPGetDatum(unionL);			v->spl_rdatum = BoxPGetDatum(unionR);			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);	}	/* bad disposition, sort by ascending and resplit */	if ((posR == 0 || posL == 0) && (posT == 0 || posB == 0))	{		KBsort	   *arr = (KBsort *) palloc(sizeof(KBsort) * maxoff);		posL = posR = posB = posT = 0;		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))		{			arr[i - 1].key = DatumGetBoxP(entryvec->vector[i].key);			arr[i - 1].pos = i;		}		qsort(arr, maxoff, sizeof(KBsort), compare_KB);		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))		{			cur = arr[i - 1].key;			if (cur->low.x - pageunion.low.x < pageunion.high.x - cur->high.x)				ADDLIST(listL, unionL, posL, arr[i - 1].pos);			else if (cur->low.x - pageunion.low.x == pageunion.high.x - cur->high.x)			{				if (posL > posR)					ADDLIST(listR, unionR, posR, arr[i - 1].pos);				else					ADDLIST(listL, unionL, posL, arr[i - 1].pos);			}			else				ADDLIST(listR, unionR, posR, arr[i - 1].pos);			if (cur->low.y - pageunion.low.y < pageunion.high.y - cur->high.y)				ADDLIST(listB, unionB, posB, arr[i - 1].pos);			else if (cur->low.y - pageunion.low.y == pageunion.high.y - cur->high.y)			{				if (posB > posT)					ADDLIST(listT, unionT, posT, arr[i - 1].pos);				else					ADDLIST(listB, unionB, posB, arr[i - 1].pos);			}			else				ADDLIST(listT, unionT, posT, arr[i - 1].pos);		}	}	/* which split more optimal? */	if (Max(posL, posR) < Max(posB, posT))		direction = 'x';	else if (Max(posL, posR) > Max(posB, posT))		direction = 'y';	else	{		Datum		interLR = DirectFunctionCall2(rt_box_inter,												  BoxPGetDatum(unionL),												  BoxPGetDatum(unionR));		Datum		interBT = DirectFunctionCall2(rt_box_inter,												  BoxPGetDatum(unionB),												  BoxPGetDatum(unionT));		double		sizeLR,					sizeBT;		sizeLR = size_box(interLR);		sizeBT = size_box(interBT);		if (sizeLR < sizeBT)			direction = 'x';

⌨️ 快捷键说明

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