mirror of
https://github.com/postgres/postgres.git
synced 2025-06-11 20:28:21 +03:00
Add point_ops opclass for GiST.
This commit is contained in:
@ -10,7 +10,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.19 2010/01/02 16:57:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.20 2010/01/14 16:31:09 teodor Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -165,7 +165,8 @@ gist_box_compress(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
/*
|
||||
* GiST DeCompress method for boxes (also used for polygons and circles)
|
||||
* GiST DeCompress method for boxes (also used for points, polygons
|
||||
* and circles)
|
||||
*
|
||||
* do not do anything --- we just use the stored box as is.
|
||||
*/
|
||||
@ -176,7 +177,7 @@ gist_box_decompress(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
/*
|
||||
* The GiST Penalty method for boxes
|
||||
* The GiST Penalty method for boxes (also used for points)
|
||||
*
|
||||
* As in the R-tree paper, we use change in area as our penalty metric
|
||||
*/
|
||||
@ -341,6 +342,8 @@ fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
|
||||
*
|
||||
* New linear algorithm, see 'New Linear Node Splitting Algorithm for R-tree',
|
||||
* C.H.Ang and T.C.Tan
|
||||
*
|
||||
* This is used for both boxes and points.
|
||||
*/
|
||||
Datum
|
||||
gist_box_picksplit(PG_FUNCTION_ARGS)
|
||||
@ -533,6 +536,8 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
|
||||
|
||||
/*
|
||||
* Equality method
|
||||
*
|
||||
* This is used for both boxes and points.
|
||||
*/
|
||||
Datum
|
||||
gist_box_same(PG_FUNCTION_ARGS)
|
||||
@ -872,3 +877,166 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
|
||||
|
||||
PG_RETURN_BOOL(result);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Point ops
|
||||
**************************************************/
|
||||
|
||||
Datum
|
||||
gist_point_compress(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
|
||||
if (entry->leafkey) /* Point, actually */
|
||||
{
|
||||
BOX *box = palloc(sizeof(BOX));
|
||||
Point *point = DatumGetPointP(entry->key);
|
||||
GISTENTRY *retval = palloc(sizeof(GISTENTRY));
|
||||
|
||||
box->high = box->low = *point;
|
||||
|
||||
gistentryinit(*retval, BoxPGetDatum(box),
|
||||
entry->rel, entry->page, entry->offset, FALSE);
|
||||
|
||||
PG_RETURN_POINTER(retval);
|
||||
}
|
||||
|
||||
PG_RETURN_POINTER(entry);
|
||||
}
|
||||
|
||||
static bool
|
||||
gist_point_consistent_internal(StrategyNumber strategy,
|
||||
bool isLeaf, BOX *key, Point *query)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
switch (strategy)
|
||||
{
|
||||
case RTLeftStrategyNumber:
|
||||
result = FPlt(key->low.x, query->x);
|
||||
break;
|
||||
case RTRightStrategyNumber:
|
||||
result = FPgt(key->high.x, query->x);
|
||||
break;
|
||||
case RTAboveStrategyNumber:
|
||||
result = FPgt(key->high.y, query->y);
|
||||
break;
|
||||
case RTBelowStrategyNumber:
|
||||
result = FPlt(key->low.y, query->y);
|
||||
break;
|
||||
case RTSameStrategyNumber:
|
||||
if (isLeaf)
|
||||
{
|
||||
result = FPeq(key->low.x, query->x)
|
||||
&& FPeq(key->low.y, query->y);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = (query->x <= key->high.x && query->x >= key->low.x &&
|
||||
query->y <= key->high.y && query->y >= key->low.y);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unknown strategy number: %d", strategy);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define GeoStrategyNumberOffset 20
|
||||
#define PointStrategyNumberGroup 0
|
||||
#define BoxStrategyNumberGroup 1
|
||||
#define PolygonStrategyNumberGroup 2
|
||||
#define CircleStrategyNumberGroup 3
|
||||
|
||||
Datum
|
||||
gist_point_consistent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
||||
bool result;
|
||||
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
||||
StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
|
||||
|
||||
switch (strategyGroup)
|
||||
{
|
||||
case PointStrategyNumberGroup:
|
||||
result = gist_point_consistent_internal(strategy % GeoStrategyNumberOffset,
|
||||
GIST_LEAF(entry),
|
||||
DatumGetBoxP(entry->key),
|
||||
PG_GETARG_POINT_P(1));
|
||||
*recheck = false;
|
||||
break;
|
||||
case BoxStrategyNumberGroup:
|
||||
result = DatumGetBool(DirectFunctionCall5(
|
||||
gist_box_consistent,
|
||||
PointerGetDatum(entry),
|
||||
PG_GETARG_DATUM(1),
|
||||
Int16GetDatum(RTOverlapStrategyNumber),
|
||||
0, PointerGetDatum(recheck)));
|
||||
break;
|
||||
case PolygonStrategyNumberGroup:
|
||||
{
|
||||
POLYGON *query = PG_GETARG_POLYGON_P(1);
|
||||
|
||||
result = DatumGetBool(DirectFunctionCall5(
|
||||
gist_poly_consistent,
|
||||
PointerGetDatum(entry),
|
||||
PolygonPGetDatum(query),
|
||||
Int16GetDatum(RTOverlapStrategyNumber),
|
||||
0, PointerGetDatum(recheck)));
|
||||
|
||||
if (GIST_LEAF(entry) && result)
|
||||
{
|
||||
/*
|
||||
* We are on leaf page and quick check shows overlapping
|
||||
* of polygon's bounding box and point
|
||||
*/
|
||||
BOX *box = DatumGetBoxP(entry->key);
|
||||
|
||||
Assert(box->high.x == box->low.x
|
||||
&& box->high.y == box->low.y);
|
||||
result = DatumGetBool(DirectFunctionCall2(
|
||||
poly_contain_pt,
|
||||
PolygonPGetDatum(query),
|
||||
PointPGetDatum(&box->high)));
|
||||
*recheck = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CircleStrategyNumberGroup:
|
||||
{
|
||||
CIRCLE *query = PG_GETARG_CIRCLE_P(1);
|
||||
|
||||
result = DatumGetBool(DirectFunctionCall5(
|
||||
gist_circle_consistent,
|
||||
PointerGetDatum(entry),
|
||||
CirclePGetDatum(query),
|
||||
Int16GetDatum(RTOverlapStrategyNumber),
|
||||
0, PointerGetDatum(recheck)));
|
||||
|
||||
if (GIST_LEAF(entry) && result)
|
||||
{
|
||||
/*
|
||||
* We are on leaf page and quick check shows overlapping
|
||||
* of polygon's bounding box and point
|
||||
*/
|
||||
BOX *box = DatumGetBoxP(entry->key);
|
||||
|
||||
Assert(box->high.x == box->low.x
|
||||
&& box->high.y == box->low.y);
|
||||
result = DatumGetBool(DirectFunctionCall2(
|
||||
circle_contain_pt,
|
||||
CirclePGetDatum(query),
|
||||
PointPGetDatum(&box->high)));
|
||||
*recheck = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result = false; /* silence compiler warning */
|
||||
elog(ERROR, "unknown strategy number: %d", strategy);
|
||||
}
|
||||
|
||||
PG_RETURN_BOOL(result);
|
||||
}
|
||||
|
Reference in New Issue
Block a user