From 4cbe473938779ec414d90c2063c4398e68a70838 Mon Sep 17 00:00:00 2001 From: Teodor Sigaev Date: Thu, 14 Jan 2010 16:31:09 +0000 Subject: Add point_ops opclass for GiST. --- src/backend/access/gist/gistproc.c | 174 ++++++++++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 3 deletions(-) (limited to 'src/backend/access/gist/gistproc.c') diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c index cf3442763e..18ee0259a5 100644 --- a/src/backend/access/gist/gistproc.c +++ b/src/backend/access/gist/gistproc.c @@ -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); +} -- cgit v1.2.1