mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			590 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			590 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*-------------------------------------------------------------------------
 | 
						|
 *
 | 
						|
 * rtree_gist.c
 | 
						|
 *	  pg_amproc entries for GiSTs over 2-D boxes.
 | 
						|
 * This gives R-tree behavior, with Guttman's poly-time split algorithm.
 | 
						|
 *
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * IDENTIFICATION
 | 
						|
 *	$Header: /cvsroot/pgsql/contrib/rtree_gist/Attic/rtree_gist.c,v 1.6 2002/09/04 20:31:08 momjian Exp $
 | 
						|
 *
 | 
						|
 *-------------------------------------------------------------------------
 | 
						|
 */
 | 
						|
#include "postgres.h"
 | 
						|
 | 
						|
#include "access/gist.h"
 | 
						|
#include "access/itup.h"
 | 
						|
#include "access/rtree.h"
 | 
						|
#include "utils/palloc.h"
 | 
						|
#include "utils/geo_decls.h"
 | 
						|
#include "utils/elog.h"
 | 
						|
 | 
						|
typedef Datum (*RDF) (PG_FUNCTION_ARGS);
 | 
						|
typedef Datum (*BINARY_UNION) (Datum, Datum, int *);
 | 
						|
typedef float (*SIZE_BOX) (Datum);
 | 
						|
 | 
						|
/*
 | 
						|
** box ops
 | 
						|
*/
 | 
						|
PG_FUNCTION_INFO_V1(gbox_compress);
 | 
						|
PG_FUNCTION_INFO_V1(gbox_union);
 | 
						|
PG_FUNCTION_INFO_V1(gbox_picksplit);
 | 
						|
PG_FUNCTION_INFO_V1(gbox_consistent);
 | 
						|
PG_FUNCTION_INFO_V1(gbox_penalty);
 | 
						|
PG_FUNCTION_INFO_V1(gbox_same);
 | 
						|
 | 
						|
Datum		gbox_compress(PG_FUNCTION_ARGS);
 | 
						|
Datum		gbox_union(PG_FUNCTION_ARGS);
 | 
						|
Datum		gbox_picksplit(PG_FUNCTION_ARGS);
 | 
						|
Datum		gbox_consistent(PG_FUNCTION_ARGS);
 | 
						|
Datum		gbox_penalty(PG_FUNCTION_ARGS);
 | 
						|
Datum		gbox_same(PG_FUNCTION_ARGS);
 | 
						|
 | 
						|
static bool gbox_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy);
 | 
						|
static float size_box(Datum box);
 | 
						|
 | 
						|
/*
 | 
						|
** Polygon ops
 | 
						|
*/
 | 
						|
PG_FUNCTION_INFO_V1(gpoly_compress);
 | 
						|
PG_FUNCTION_INFO_V1(gpoly_consistent);
 | 
						|
 | 
						|
Datum		gpoly_compress(PG_FUNCTION_ARGS);
 | 
						|
Datum		gpoly_consistent(PG_FUNCTION_ARGS);
 | 
						|
 | 
						|
/*
 | 
						|
** Common rtree-function (for all ops)
 | 
						|
*/
 | 
						|
static bool rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy);
 | 
						|
 | 
						|
PG_FUNCTION_INFO_V1(rtree_decompress);
 | 
						|
 | 
						|
Datum		rtree_decompress(PG_FUNCTION_ARGS);
 | 
						|
 | 
						|
/**************************************************
 | 
						|
 * Box ops
 | 
						|
 **************************************************/
 | 
						|
 | 
						|
/*
 | 
						|
** The GiST Consistent method for boxes
 | 
						|
** Should return false if for all data items x below entry,
 | 
						|
** the predicate x op query == FALSE, where op is the oper
 | 
						|
** corresponding to strategy in the pg_amop table.
 | 
						|
*/
 | 
						|
Datum
 | 
						|
gbox_consistent(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 | 
						|
	BOX		   *query = (BOX *) PG_GETARG_POINTER(1);
 | 
						|
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 | 
						|
 | 
						|
	/*
 | 
						|
	 * * if entry is not leaf, use gbox_internal_consistent, * else use
 | 
						|
	 * gbox_leaf_consistent
 | 
						|
	 */
 | 
						|
	if (!(DatumGetPointer(entry->key) != NULL && query))
 | 
						|
		PG_RETURN_BOOL(FALSE);
 | 
						|
 | 
						|
	if (GIST_LEAF(entry))
 | 
						|
		PG_RETURN_BOOL(gbox_leaf_consistent((BOX *) DatumGetPointer(entry->key), query, strategy));
 | 
						|
	else
 | 
						|
		PG_RETURN_BOOL(rtree_internal_consistent((BOX *) DatumGetPointer(entry->key), query, strategy));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
** The GiST Union method for boxes
 | 
						|
** returns the minimal bounding box that encloses all the entries in entryvec
 | 
						|
*/
 | 
						|
Datum
 | 
						|
gbox_union(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	bytea	   *entryvec = (bytea *) PG_GETARG_POINTER(0);
 | 
						|
	int		   *sizep = (int *) PG_GETARG_POINTER(1);
 | 
						|
	int			numranges,
 | 
						|
				i;
 | 
						|
	BOX		   *cur,
 | 
						|
			   *pageunion;
 | 
						|
 | 
						|
	numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
 | 
						|
	pageunion = (BOX *) palloc(sizeof(BOX));
 | 
						|
	cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[0].key);
 | 
						|
	memcpy((void *) pageunion, (void *) cur, sizeof(BOX));
 | 
						|
 | 
						|
	for (i = 1; i < numranges; i++)
 | 
						|
	{
 | 
						|
		cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[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.
 | 
						|
*/
 | 
						|
Datum
 | 
						|
gbox_compress(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
 | 
						|
*/
 | 
						|
Datum
 | 
						|
gbox_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;
 | 
						|
	float		tmp1;
 | 
						|
 | 
						|
	ud = DirectFunctionCall2(rt_box_union, origentry->key, newentry->key);
 | 
						|
	tmp1 = size_box(ud);
 | 
						|
	if (DatumGetPointer(ud) != NULL)
 | 
						|
		pfree(DatumGetPointer(ud));
 | 
						|
 | 
						|
	*result = tmp1 - size_box(origentry->key);
 | 
						|
	PG_RETURN_POINTER(result);
 | 
						|
}
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
	BOX		   *key;
 | 
						|
	int			pos;
 | 
						|
}	KBsort;
 | 
						|
 | 
						|
static int
 | 
						|
compare_KB(const void *a, const void *b)
 | 
						|
{
 | 
						|
	BOX		   *abox = ((KBsort *) a)->key;
 | 
						|
	BOX		   *bbox = ((KBsort *) b)->key;
 | 
						|
	float		sa = (abox->high.x - abox->low.x) * (abox->high.y - abox->low.y);
 | 
						|
	float		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
 | 
						|
*/
 | 
						|
Datum
 | 
						|
gbox_picksplit(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	bytea	   *entryvec = (bytea *) 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 = ((VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY)) - 1;
 | 
						|
 | 
						|
	cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[FirstOffsetNumber].key);
 | 
						|
	memcpy((void *) &pageunion, (void *) cur, sizeof(BOX));
 | 
						|
 | 
						|
	/* find MBR */
 | 
						|
	for (i = OffsetNumberNext(FirstOffsetNumber); i <= maxoff; i = OffsetNumberNext(i))
 | 
						|
	{
 | 
						|
		cur = DatumGetBoxP(((GISTENTRY *) VARDATA(entryvec))[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(((GISTENTRY *) VARDATA(entryvec))[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(((GISTENTRY *) VARDATA(entryvec))[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(((GISTENTRY *) VARDATA(entryvec))[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);
 | 
						|
		}
 | 
						|
		pfree(arr);
 | 
						|
	}
 | 
						|
 | 
						|
	/* 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));
 | 
						|
		float		sizeLR,
 | 
						|
					sizeBT;
 | 
						|
 | 
						|
		sizeLR = size_box(interLR);
 | 
						|
		sizeBT = size_box(interBT);
 | 
						|
 | 
						|
		if (sizeLR < sizeBT)
 | 
						|
			direction = 'x';
 | 
						|
		else
 | 
						|
			direction = 'y';
 | 
						|
	}
 | 
						|
 | 
						|
	if (direction == 'x')
 | 
						|
	{
 | 
						|
		pfree(unionB);
 | 
						|
		pfree(listB);
 | 
						|
		pfree(unionT);
 | 
						|
		pfree(listT);
 | 
						|
 | 
						|
		v->spl_left = listL;
 | 
						|
		v->spl_right = listR;
 | 
						|
		v->spl_nleft = posL;
 | 
						|
		v->spl_nright = posR;
 | 
						|
		v->spl_ldatum = BoxPGetDatum(unionL);
 | 
						|
		v->spl_rdatum = BoxPGetDatum(unionR);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		pfree(unionR);
 | 
						|
		pfree(listR);
 | 
						|
		pfree(unionL);
 | 
						|
		pfree(listL);
 | 
						|
 | 
						|
		v->spl_left = listB;
 | 
						|
		v->spl_right = listT;
 | 
						|
		v->spl_nleft = posB;
 | 
						|
		v->spl_nright = posT;
 | 
						|
		v->spl_ldatum = BoxPGetDatum(unionB);
 | 
						|
		v->spl_rdatum = BoxPGetDatum(unionT);
 | 
						|
	}
 | 
						|
 | 
						|
	PG_RETURN_POINTER(v);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** Equality method
 | 
						|
*/
 | 
						|
Datum
 | 
						|
gbox_same(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	BOX		   *b1 = (BOX *) PG_GETARG_POINTER(0);
 | 
						|
	BOX		   *b2 = (BOX *) PG_GETARG_POINTER(1);
 | 
						|
	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 | 
						|
 | 
						|
	if (b1 && b2)
 | 
						|
		*result = DatumGetBool(DirectFunctionCall2(box_same, PointerGetDatum(b1), PointerGetDatum(b2)));
 | 
						|
	else
 | 
						|
		*result = (b1 == NULL && b2 == NULL) ? TRUE : FALSE;
 | 
						|
	PG_RETURN_POINTER(result);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** SUPPORT ROUTINES for boxes
 | 
						|
*/
 | 
						|
static bool
 | 
						|
gbox_leaf_consistent(BOX *key,
 | 
						|
					 BOX *query,
 | 
						|
					 StrategyNumber strategy)
 | 
						|
{
 | 
						|
	bool		retval;
 | 
						|
 | 
						|
	switch (strategy)
 | 
						|
	{
 | 
						|
		case RTLeftStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_left, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		case RTOverLeftStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_overleft, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		case RTOverlapStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_overlap, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		case RTOverRightStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_overright, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		case RTRightStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_right, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		case RTSameStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_same, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		case RTContainsStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_contain, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		case RTContainedByStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_contained, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			retval = FALSE;
 | 
						|
	}
 | 
						|
	return (retval);
 | 
						|
}
 | 
						|
 | 
						|
static float
 | 
						|
size_box(Datum box)
 | 
						|
{
 | 
						|
	if (DatumGetPointer(box) != NULL)
 | 
						|
	{
 | 
						|
		float		size;
 | 
						|
 | 
						|
		DirectFunctionCall2(rt_box_size,
 | 
						|
							box, PointerGetDatum(&size));
 | 
						|
		return size;
 | 
						|
	}
 | 
						|
	else
 | 
						|
		return 0.0;
 | 
						|
}
 | 
						|
 | 
						|
/**************************************************
 | 
						|
 * Polygon ops
 | 
						|
 **************************************************/
 | 
						|
 | 
						|
Datum
 | 
						|
gpoly_compress(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 | 
						|
	GISTENTRY  *retval;
 | 
						|
 | 
						|
	if (entry->leafkey)
 | 
						|
	{
 | 
						|
		retval = palloc(sizeof(GISTENTRY));
 | 
						|
		if (DatumGetPointer(entry->key) != NULL)
 | 
						|
		{
 | 
						|
			POLYGON    *in;
 | 
						|
			BOX		   *r;
 | 
						|
 | 
						|
			in = (POLYGON *) PG_DETOAST_DATUM(entry->key);
 | 
						|
			r = (BOX *) palloc(sizeof(BOX));
 | 
						|
			memcpy((void *) r, (void *) &(in->boundbox), sizeof(BOX));
 | 
						|
			if (in != (POLYGON *) DatumGetPointer(entry->key))
 | 
						|
				pfree(in);
 | 
						|
 | 
						|
			gistentryinit(*retval, PointerGetDatum(r),
 | 
						|
						  entry->rel, entry->page,
 | 
						|
						  entry->offset, sizeof(BOX), FALSE);
 | 
						|
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			gistentryinit(*retval, (Datum) 0,
 | 
						|
						  entry->rel, entry->page,
 | 
						|
						  entry->offset, 0, FALSE);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
		retval = entry;
 | 
						|
	PG_RETURN_POINTER(retval);
 | 
						|
}
 | 
						|
 | 
						|
Datum
 | 
						|
gpoly_consistent(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 | 
						|
	POLYGON    *query = (POLYGON *) PG_DETOAST_DATUM(PG_GETARG_POINTER(1));
 | 
						|
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
 | 
						|
	bool		result;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * * if entry is not leaf, use gbox_internal_consistent, * else use
 | 
						|
	 * gbox_leaf_consistent
 | 
						|
	 */
 | 
						|
	if (!(DatumGetPointer(entry->key) != NULL && query))
 | 
						|
		PG_RETURN_BOOL(FALSE);
 | 
						|
 | 
						|
	result = rtree_internal_consistent((BOX *) DatumGetPointer(entry->key),
 | 
						|
									   &(query->boundbox), strategy);
 | 
						|
 | 
						|
	PG_FREE_IF_COPY(query, 1);
 | 
						|
	PG_RETURN_BOOL(result);
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************
 | 
						|
 * Common rtree-function (for all ops)
 | 
						|
 *****************************************/
 | 
						|
 | 
						|
static bool
 | 
						|
rtree_internal_consistent(BOX *key,
 | 
						|
						  BOX *query,
 | 
						|
						  StrategyNumber strategy)
 | 
						|
{
 | 
						|
	bool		retval;
 | 
						|
 | 
						|
	switch (strategy)
 | 
						|
	{
 | 
						|
		case RTLeftStrategyNumber:
 | 
						|
		case RTOverLeftStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_overleft, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		case RTOverlapStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_overlap, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		case RTOverRightStrategyNumber:
 | 
						|
		case RTRightStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_right, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		case RTSameStrategyNumber:
 | 
						|
		case RTContainsStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_contain, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		case RTContainedByStrategyNumber:
 | 
						|
			retval = DatumGetBool(DirectFunctionCall2(box_overlap, PointerGetDatum(key), PointerGetDatum(query)));
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			retval = FALSE;
 | 
						|
	}
 | 
						|
	return (retval);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
** GiST DeCompress methods
 | 
						|
** do not do anything.
 | 
						|
*/
 | 
						|
Datum
 | 
						|
rtree_decompress(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	PG_RETURN_POINTER(PG_GETARG_POINTER(0));
 | 
						|
}
 |