#include "postgres.h"
#include "access/gist.h"
#include "access/skey.h"
#include "utils/geo_decls.h"
Go to the source code of this file.
Data Structures | |
struct | CommonEntry |
struct | ConsiderSplitContext |
struct | SplitInterval |
Defines | |
#define | LIMIT_RATIO 0.3 |
#define | PLACE_LEFT(box, off) |
#define | PLACE_RIGHT(box, off) |
#define | point_point_distance(p1, p2) |
#define | GeoStrategyNumberOffset 20 |
#define | PointStrategyNumberGroup 0 |
#define | BoxStrategyNumberGroup 1 |
#define | PolygonStrategyNumberGroup 2 |
#define | CircleStrategyNumberGroup 3 |
Functions | |
static bool | gist_box_leaf_consistent (BOX *key, BOX *query, StrategyNumber strategy) |
static double | size_box (BOX *box) |
static bool | rtree_internal_consistent (BOX *key, BOX *query, StrategyNumber strategy) |
static void | rt_box_union (BOX *n, BOX *a, BOX *b) |
Datum | gist_box_consistent (PG_FUNCTION_ARGS) |
static void | adjustBox (BOX *b, BOX *addon) |
Datum | gist_box_union (PG_FUNCTION_ARGS) |
Datum | gist_box_compress (PG_FUNCTION_ARGS) |
Datum | gist_box_decompress (PG_FUNCTION_ARGS) |
Datum | gist_box_penalty (PG_FUNCTION_ARGS) |
static void | fallbackSplit (GistEntryVector *entryvec, GIST_SPLITVEC *v) |
static int | interval_cmp_lower (const void *i1, const void *i2) |
static int | interval_cmp_upper (const void *i1, const void *i2) |
static float | non_negative (float val) |
static void | g_box_consider_split (ConsiderSplitContext *context, int dimNum, double rightLower, int minLeftCount, double leftUpper, int maxLeftCount) |
static double | box_penalty (BOX *original, BOX *new) |
static int | common_entry_cmp (const void *i1, const void *i2) |
Datum | gist_box_picksplit (PG_FUNCTION_ARGS) |
Datum | gist_box_same (PG_FUNCTION_ARGS) |
Datum | gist_poly_compress (PG_FUNCTION_ARGS) |
Datum | gist_poly_consistent (PG_FUNCTION_ARGS) |
Datum | gist_circle_compress (PG_FUNCTION_ARGS) |
Datum | gist_circle_consistent (PG_FUNCTION_ARGS) |
Datum | gist_point_compress (PG_FUNCTION_ARGS) |
static double | computeDistance (bool isLeaf, BOX *box, Point *point) |
static bool | gist_point_consistent_internal (StrategyNumber strategy, bool isLeaf, BOX *key, Point *query) |
Datum | gist_point_consistent (PG_FUNCTION_ARGS) |
Datum | gist_point_distance (PG_FUNCTION_ARGS) |
#define BoxStrategyNumberGroup 1 |
Definition at line 1317 of file gistproc.c.
Referenced by gist_point_consistent().
#define CircleStrategyNumberGroup 3 |
Definition at line 1319 of file gistproc.c.
Referenced by gist_point_consistent().
#define GeoStrategyNumberOffset 20 |
Definition at line 1315 of file gistproc.c.
Referenced by gist_point_consistent().
#define LIMIT_RATIO 0.3 |
Definition at line 32 of file gistproc.c.
Referenced by g_box_consider_split(), and gist_box_picksplit().
#define PLACE_LEFT | ( | box, | ||
off | ||||
) |
do { \ if (v->spl_nleft > 0) \ adjustBox(leftBox, box); \ else \ *leftBox = *(box); \ v->spl_left[v->spl_nleft++] = off; \ } while(0)
Referenced by gist_box_picksplit().
#define PLACE_RIGHT | ( | box, | ||
off | ||||
) |
do { \ if (v->spl_nright > 0) \ adjustBox(rightBox, box); \ else \ *rightBox = *(box); \ v->spl_right[v->spl_nright++] = off; \ } while(0)
Referenced by gist_box_picksplit().
#define point_point_distance | ( | p1, | ||
p2 | ||||
) |
Definition at line 1203 of file gistproc.c.
Referenced by computeDistance().
#define PointStrategyNumberGroup 0 |
Definition at line 1316 of file gistproc.c.
Referenced by gist_point_consistent(), and gist_point_distance().
#define PolygonStrategyNumberGroup 2 |
Definition at line 1318 of file gistproc.c.
Referenced by gist_point_consistent().
Definition at line 89 of file gistproc.c.
References BOX::high, BOX::low, Point::x, and Point::y.
Referenced by fallbackSplit(), gist_box_picksplit(), and gist_box_union().
Definition at line 432 of file gistproc.c.
References BOX::high, BOX::low, Max, Min, Point::x, and Point::y.
Referenced by gist_box_picksplit().
{ double union_width, union_height; union_width = Max(original->high.x, new->high.x) - Min(original->low.x, new->low.x); union_height = Max(original->high.y, new->high.y) - Min(original->low.y, new->low.y); return union_width * union_height - (original->high.x - original->low.x) * (original->high.y - original->low.y); }
static int common_entry_cmp | ( | const void * | i1, | |
const void * | i2 | |||
) | [static] |
Definition at line 449 of file gistproc.c.
Referenced by gist_box_picksplit().
{ double delta1 = ((const CommonEntry *) i1)->delta, delta2 = ((const CommonEntry *) i2)->delta; if (delta1 < delta2) return -1; else if (delta1 > delta2) return 1; else return 0; }
Definition at line 1208 of file gistproc.c.
References Assert, elog, ERROR, BOX::high, BOX::low, point_point_distance, Point::x, and Point::y.
Referenced by gist_point_distance().
{ double result = 0.0; if (isLeaf) { /* simple point to point distance */ result = point_point_distance(point, &box->low); } else if (point->x <= box->high.x && point->x >= box->low.x && point->y <= box->high.y && point->y >= box->low.y) { /* point inside the box */ result = 0.0; } else if (point->x <= box->high.x && point->x >= box->low.x) { /* point is over or below box */ Assert(box->low.y <= box->high.y); if (point->y > box->high.y) result = point->y - box->high.y; else if (point->y < box->low.y) result = box->low.y - point->y; else elog(ERROR, "inconsistent point values"); } else if (point->y <= box->high.y && point->y >= box->low.y) { /* point is to left or right of box */ Assert(box->low.x <= box->high.x); if (point->x > box->high.x) result = point->x - box->high.x; else if (point->x < box->low.x) result = box->low.x - point->x; else elog(ERROR, "inconsistent point values"); } else { /* closest point will be a vertex */ Point p; double subresult; result = point_point_distance(point, &box->low); subresult = point_point_distance(point, &box->high); if (result > subresult) result = subresult; p.x = box->low.x; p.y = box->high.y; subresult = point_point_distance(point, &p); if (result > subresult) result = subresult; p.x = box->high.x; p.y = box->low.y; subresult = point_point_distance(point, &p); if (result > subresult) result = subresult; } return result; }
static void fallbackSplit | ( | GistEntryVector * | entryvec, | |
GIST_SPLITVEC * | v | |||
) | [static] |
Definition at line 179 of file gistproc.c.
References adjustBox(), BoxPGetDatum, cur, DatumGetBoxP, FirstOffsetNumber, i, GISTENTRY::key, GistEntryVector::n, NULL, OffsetNumberNext, palloc(), GIST_SPLITVEC::spl_ldatum, GIST_SPLITVEC::spl_left, GIST_SPLITVEC::spl_nleft, GIST_SPLITVEC::spl_nright, GIST_SPLITVEC::spl_rdatum, GIST_SPLITVEC::spl_right, and GistEntryVector::vector.
Referenced by gist_box_picksplit().
{ OffsetNumber i, maxoff; BOX *unionL = NULL, *unionR = NULL; int nbytes; maxoff = entryvec->n - 1; nbytes = (maxoff + 2) * sizeof(OffsetNumber); v->spl_left = (OffsetNumber *) palloc(nbytes); v->spl_right = (OffsetNumber *) palloc(nbytes); v->spl_nleft = v->spl_nright = 0; for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { BOX *cur = DatumGetBoxP(entryvec->vector[i].key); if (i <= (maxoff - FirstOffsetNumber + 1) / 2) { v->spl_left[v->spl_nleft] = i; if (unionL == NULL) { unionL = (BOX *) palloc(sizeof(BOX)); *unionL = *cur; } else adjustBox(unionL, cur); v->spl_nleft++; } else { v->spl_right[v->spl_nright] = i; if (unionR == NULL) { unionR = (BOX *) palloc(sizeof(BOX)); *unionR = *cur; } else adjustBox(unionR, cur); v->spl_nright++; } } v->spl_ldatum = BoxPGetDatum(unionL); v->spl_rdatum = BoxPGetDatum(unionR); }
static void g_box_consider_split | ( | ConsiderSplitContext * | context, | |
int | dimNum, | |||
double | rightLower, | |||
int | minLeftCount, | |||
double | leftUpper, | |||
int | maxLeftCount | |||
) | [inline, static] |
Definition at line 324 of file gistproc.c.
References ConsiderSplitContext::boundingBox, ConsiderSplitContext::dim, ConsiderSplitContext::entriesCount, ConsiderSplitContext::first, BOX::high, ConsiderSplitContext::leftUpper, LIMIT_RATIO, BOX::low, Min, non_negative(), ConsiderSplitContext::overlap, ConsiderSplitContext::range, ConsiderSplitContext::ratio, ConsiderSplitContext::rightLower, Point::x, and Point::y.
Referenced by gist_box_picksplit().
{ int leftCount, rightCount; float4 ratio, overlap; double range; /* * Calculate entries distribution ratio assuming most uniform distribution * of common entries. */ if (minLeftCount >= (context->entriesCount + 1) / 2) { leftCount = minLeftCount; } else { if (maxLeftCount <= context->entriesCount / 2) leftCount = maxLeftCount; else leftCount = context->entriesCount / 2; } rightCount = context->entriesCount - leftCount; /* * Ratio of split - quotient between size of lesser group and total * entries count. */ ratio = ((float4) Min(leftCount, rightCount)) / ((float4) context->entriesCount); if (ratio > LIMIT_RATIO) { bool selectthis = false; /* * The ratio is acceptable, so compare current split with previously * selected one. Between splits of one dimension we search for minimal * overlap (allowing negative values) and minimal ration (between same * overlaps. We switch dimension if find less overlap (non-negative) * or less range with same overlap. */ if (dimNum == 0) range = context->boundingBox.high.x - context->boundingBox.low.x; else range = context->boundingBox.high.y - context->boundingBox.low.y; overlap = (leftUpper - rightLower) / range; /* If there is no previous selection, select this */ if (context->first) selectthis = true; else if (context->dim == dimNum) { /* * Within the same dimension, choose the new split if it has a * smaller overlap, or same overlap but better ratio. */ if (overlap < context->overlap || (overlap == context->overlap && ratio > context->ratio)) selectthis = true; } else { /* * Across dimensions, choose the new split if it has a smaller * *non-negative* overlap, or same *non-negative* overlap but * bigger range. This condition differs from the one described in * the article. On the datasets where leaf MBRs don't overlap * themselves, non-overlapping splits (i.e. splits which have zero * *non-negative* overlap) are frequently possible. In this case * splits tends to be along one dimension, because most distant * non-overlapping splits (i.e. having lowest negative overlap) * appears to be in the same dimension as in the previous split. * Therefore MBRs appear to be very prolonged along another * dimension, which leads to bad search performance. Using range * as the second split criteria makes MBRs more quadratic. Using * *non-negative* overlap instead of overlap as the first split * criteria gives to range criteria a chance to matter, because * non-overlapping splits are equivalent in this criteria. */ if (non_negative(overlap) < non_negative(context->overlap) || (range > context->range && non_negative(overlap) <= non_negative(context->overlap))) selectthis = true; } if (selectthis) { /* save information about selected split */ context->first = false; context->ratio = ratio; context->range = range; context->overlap = overlap; context->rightLower = rightLower; context->leftUpper = leftUpper; context->dim = dimNum; } } }
Datum gist_box_compress | ( | PG_FUNCTION_ARGS | ) |
Definition at line 137 of file gistproc.c.
References PG_GETARG_POINTER, and PG_RETURN_POINTER.
{ PG_RETURN_POINTER(PG_GETARG_POINTER(0)); }
Datum gist_box_consistent | ( | PG_FUNCTION_ARGS | ) |
Definition at line 59 of file gistproc.c.
References DatumGetBoxP, FALSE, gist_box_leaf_consistent(), GIST_LEAF, GISTENTRY::key, NULL, PG_GETARG_BOX_P, PG_GETARG_POINTER, PG_GETARG_UINT16, PG_RETURN_BOOL, and rtree_internal_consistent().
{ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); BOX *query = PG_GETARG_BOX_P(1); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); /* All cases served by this function are exact */ *recheck = false; 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)); }
Datum gist_box_decompress | ( | PG_FUNCTION_ARGS | ) |
Definition at line 149 of file gistproc.c.
References PG_GETARG_POINTER, and PG_RETURN_POINTER.
{ PG_RETURN_POINTER(PG_GETARG_POINTER(0)); }
static bool gist_box_leaf_consistent | ( | BOX * | key, | |
BOX * | query, | |||
StrategyNumber | strategy | |||
) | [static] |
Definition at line 860 of file gistproc.c.
References box_above(), box_below(), box_contain(), box_contained(), box_left(), box_overabove(), box_overbelow(), box_overlap(), box_overleft(), box_overright(), box_right(), box_same(), DatumGetBool, DirectFunctionCall2, PointerGetDatum, RTAboveStrategyNumber, RTBelowStrategyNumber, RTContainedByStrategyNumber, RTContainsStrategyNumber, RTLeftStrategyNumber, RTOldContainedByStrategyNumber, RTOldContainsStrategyNumber, RTOverAboveStrategyNumber, RTOverBelowStrategyNumber, RTOverlapStrategyNumber, RTOverLeftStrategyNumber, RTOverRightStrategyNumber, RTRightStrategyNumber, and RTSameStrategyNumber.
Referenced by gist_box_consistent().
{ 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: case RTOldContainsStrategyNumber: retval = DatumGetBool(DirectFunctionCall2(box_contain, PointerGetDatum(key), PointerGetDatum(query))); break; case RTContainedByStrategyNumber: case RTOldContainedByStrategyNumber: retval = DatumGetBool(DirectFunctionCall2(box_contained, PointerGetDatum(key), PointerGetDatum(query))); break; case RTOverBelowStrategyNumber: retval = DatumGetBool(DirectFunctionCall2(box_overbelow, PointerGetDatum(key), PointerGetDatum(query))); break; case RTBelowStrategyNumber: retval = DatumGetBool(DirectFunctionCall2(box_below, PointerGetDatum(key), PointerGetDatum(query))); break; case RTAboveStrategyNumber: retval = DatumGetBool(DirectFunctionCall2(box_above, PointerGetDatum(key), PointerGetDatum(query))); break; case RTOverAboveStrategyNumber: retval = DatumGetBool(DirectFunctionCall2(box_overabove, PointerGetDatum(key), PointerGetDatum(query))); break; default: retval = FALSE; } return retval; }
Datum gist_box_penalty | ( | PG_FUNCTION_ARGS | ) |
Definition at line 160 of file gistproc.c.
References DatumGetBoxP, GISTENTRY::key, PG_GETARG_POINTER, PG_RETURN_POINTER, rt_box_union(), and size_box().
{ GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1); float *result = (float *) PG_GETARG_POINTER(2); BOX *origbox = DatumGetBoxP(origentry->key); BOX *newbox = DatumGetBoxP(newentry->key); BOX unionbox; rt_box_union(&unionbox, origbox, newbox); *result = (float) (size_box(&unionbox) - size_box(origbox)); PG_RETURN_POINTER(result); }
Datum gist_box_picksplit | ( | PG_FUNCTION_ARGS | ) |
Definition at line 489 of file gistproc.c.
References Abs, adjustBox(), Assert, ConsiderSplitContext::boundingBox, box_penalty(), common_entry_cmp(), DatumGetBoxP, CommonEntry::delta, ConsiderSplitContext::dim, ConsiderSplitContext::entriesCount, fallbackSplit(), ConsiderSplitContext::first, FirstOffsetNumber, g_box_consider_split(), BOX::high, i, CommonEntry::index, interval_cmp_lower(), interval_cmp_upper(), GISTENTRY::key, ConsiderSplitContext::leftUpper, LIMIT_RATIO, BOX::low, lower(), SplitInterval::lower, Max, Min, GistEntryVector::n, OffsetNumberNext, palloc(), palloc0(), PG_GETARG_POINTER, PG_RETURN_POINTER, PLACE_LEFT, PLACE_RIGHT, PointerGetDatum, qsort, ConsiderSplitContext::rightLower, GIST_SPLITVEC::spl_ldatum, GIST_SPLITVEC::spl_left, GIST_SPLITVEC::spl_nleft, GIST_SPLITVEC::spl_nright, GIST_SPLITVEC::spl_rdatum, GIST_SPLITVEC::spl_right, upper(), SplitInterval::upper, GistEntryVector::vector, Point::x, and Point::y.
{ GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); OffsetNumber i, maxoff; ConsiderSplitContext context; BOX *box, *leftBox, *rightBox; int dim, commonEntriesCount; SplitInterval *intervalsLower, *intervalsUpper; CommonEntry *commonEntries; int nentries; memset(&context, 0, sizeof(ConsiderSplitContext)); maxoff = entryvec->n - 1; nentries = context.entriesCount = maxoff - FirstOffsetNumber + 1; /* Allocate arrays for intervals along axes */ intervalsLower = (SplitInterval *) palloc(nentries * sizeof(SplitInterval)); intervalsUpper = (SplitInterval *) palloc(nentries * sizeof(SplitInterval)); /* * Calculate the overall minimum bounding box over all the entries. */ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { box = DatumGetBoxP(entryvec->vector[i].key); if (i == FirstOffsetNumber) context.boundingBox = *box; else adjustBox(&context.boundingBox, box); } /* * Iterate over axes for optimal split searching. */ context.first = true; /* nothing selected yet */ for (dim = 0; dim < 2; dim++) { double leftUpper, rightLower; int i1, i2; /* Project each entry as an interval on the selected axis. */ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { box = DatumGetBoxP(entryvec->vector[i].key); if (dim == 0) { intervalsLower[i - FirstOffsetNumber].lower = box->low.x; intervalsLower[i - FirstOffsetNumber].upper = box->high.x; } else { intervalsLower[i - FirstOffsetNumber].lower = box->low.y; intervalsLower[i - FirstOffsetNumber].upper = box->high.y; } } /* * Make two arrays of intervals: one sorted by lower bound and another * sorted by upper bound. */ memcpy(intervalsUpper, intervalsLower, sizeof(SplitInterval) * nentries); qsort(intervalsLower, nentries, sizeof(SplitInterval), interval_cmp_lower); qsort(intervalsUpper, nentries, sizeof(SplitInterval), interval_cmp_upper); /*---- * The goal is to form a left and right interval, so that every entry * interval is contained by either left or right interval (or both). * * For example, with the intervals (0,1), (1,3), (2,3), (2,4): * * 0 1 2 3 4 * +-+ * +---+ * +-+ * +---+ * * The left and right intervals are of the form (0,a) and (b,4). * We first consider splits where b is the lower bound of an entry. * We iterate through all entries, and for each b, calculate the * smallest possible a. Then we consider splits where a is the * uppper bound of an entry, and for each a, calculate the greatest * possible b. * * In the above example, the first loop would consider splits: * b=0: (0,1)-(0,4) * b=1: (0,1)-(1,4) * b=2: (0,3)-(2,4) * * And the second loop: * a=1: (0,1)-(1,4) * a=3: (0,3)-(2,4) * a=4: (0,4)-(2,4) */ /* * Iterate over lower bound of right group, finding smallest possible * upper bound of left group. */ i1 = 0; i2 = 0; rightLower = intervalsLower[i1].lower; leftUpper = intervalsUpper[i2].lower; while (true) { /* * Find next lower bound of right group. */ while (i1 < nentries && rightLower == intervalsLower[i1].lower) { leftUpper = Max(leftUpper, intervalsLower[i1].upper); i1++; } if (i1 >= nentries) break; rightLower = intervalsLower[i1].lower; /* * Find count of intervals which anyway should be placed to the * left group. */ while (i2 < nentries && intervalsUpper[i2].upper <= leftUpper) i2++; /* * Consider found split. */ g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2); } /* * Iterate over upper bound of left group finding greates possible * lower bound of right group. */ i1 = nentries - 1; i2 = nentries - 1; rightLower = intervalsLower[i1].upper; leftUpper = intervalsUpper[i2].upper; while (true) { /* * Find next upper bound of left group. */ while (i2 >= 0 && leftUpper == intervalsUpper[i2].upper) { rightLower = Min(rightLower, intervalsUpper[i2].lower); i2--; } if (i2 < 0) break; leftUpper = intervalsUpper[i2].upper; /* * Find count of intervals which anyway should be placed to the * right group. */ while (i1 >= 0 && intervalsLower[i1].lower >= rightLower) i1--; /* * Consider found split. */ g_box_consider_split(&context, dim, rightLower, i1 + 1, leftUpper, i2 + 1); } } /* * If we failed to find any acceptable splits, use trivial split. */ if (context.first) { fallbackSplit(entryvec, v); PG_RETURN_POINTER(v); } /* * Ok, we have now selected the split across one axis. * * While considering the splits, we already determined that there will be * enough entries in both groups to reach the desired ratio, but we did * not memorize which entries go to which group. So determine that now. */ /* Allocate vectors for results */ v->spl_left = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber)); v->spl_right = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber)); v->spl_nleft = 0; v->spl_nright = 0; /* Allocate bounding boxes of left and right groups */ leftBox = palloc0(sizeof(BOX)); rightBox = palloc0(sizeof(BOX)); /* * Allocate an array for "common entries" - entries which can be placed to * either group without affecting overlap along selected axis. */ commonEntriesCount = 0; commonEntries = (CommonEntry *) palloc(nentries * sizeof(CommonEntry)); /* Helper macros to place an entry in the left or right group */ #define PLACE_LEFT(box, off) \ do { \ if (v->spl_nleft > 0) \ adjustBox(leftBox, box); \ else \ *leftBox = *(box); \ v->spl_left[v->spl_nleft++] = off; \ } while(0) #define PLACE_RIGHT(box, off) \ do { \ if (v->spl_nright > 0) \ adjustBox(rightBox, box); \ else \ *rightBox = *(box); \ v->spl_right[v->spl_nright++] = off; \ } while(0) /* * Distribute entries which can be distributed unambiguously, and collect * common entries. */ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { double lower, upper; /* * Get upper and lower bounds along selected axis. */ box = DatumGetBoxP(entryvec->vector[i].key); if (context.dim == 0) { lower = box->low.x; upper = box->high.x; } else { lower = box->low.y; upper = box->high.y; } if (upper <= context.leftUpper) { /* Fits to the left group */ if (lower >= context.rightLower) { /* Fits also to the right group, so "common entry" */ commonEntries[commonEntriesCount++].index = i; } else { /* Doesn't fit to the right group, so join to the left group */ PLACE_LEFT(box, i); } } else { /* * Each entry should fit on either left or right group. Since this * entry didn't fit on the left group, it better fit in the right * group. */ Assert(lower >= context.rightLower); /* Doesn't fit to the left group, so join to the right group */ PLACE_RIGHT(box, i); } } /* * Distribute "common entries", if any. */ if (commonEntriesCount > 0) { /* * Calculate minimum number of entries that must be placed in both * groups, to reach LIMIT_RATIO. */ int m = ceil(LIMIT_RATIO * (double) nentries); /* * Calculate delta between penalties of join "common entries" to * different groups. */ for (i = 0; i < commonEntriesCount; i++) { box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key); commonEntries[i].delta = Abs(box_penalty(leftBox, box) - box_penalty(rightBox, box)); } /* * Sort "common entries" by calculated deltas in order to distribute * the most ambiguous entries first. */ qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp); /* * Distribute "common entries" between groups. */ for (i = 0; i < commonEntriesCount; i++) { box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key); /* * Check if we have to place this entry in either group to achieve * LIMIT_RATIO. */ if (v->spl_nleft + (commonEntriesCount - i) <= m) PLACE_LEFT(box, commonEntries[i].index); else if (v->spl_nright + (commonEntriesCount - i) <= m) PLACE_RIGHT(box, commonEntries[i].index); else { /* Otherwise select the group by minimal penalty */ if (box_penalty(leftBox, box) < box_penalty(rightBox, box)) PLACE_LEFT(box, commonEntries[i].index); else PLACE_RIGHT(box, commonEntries[i].index); } } } v->spl_ldatum = PointerGetDatum(leftBox); v->spl_rdatum = PointerGetDatum(rightBox); PG_RETURN_POINTER(v); }
Datum gist_box_same | ( | PG_FUNCTION_ARGS | ) |
Definition at line 842 of file gistproc.c.
References BOX::high, BOX::low, NULL, PG_GETARG_BOX_P, PG_GETARG_POINTER, PG_RETURN_POINTER, Point::x, and Point::y.
{ BOX *b1 = PG_GETARG_BOX_P(0); BOX *b2 = PG_GETARG_BOX_P(1); bool *result = (bool *) PG_GETARG_POINTER(2); if (b1 && b2) *result = (b1->low.x == b2->low.x && b1->low.y == b2->low.y && b1->high.x == b2->high.x && b1->high.y == b2->high.y); else *result = (b1 == NULL && b2 == NULL); PG_RETURN_POINTER(result); }
Datum gist_box_union | ( | PG_FUNCTION_ARGS | ) |
Definition at line 107 of file gistproc.c.
References adjustBox(), cur, DatumGetBoxP, i, GISTENTRY::key, GistEntryVector::n, palloc(), PG_GETARG_POINTER, PG_RETURN_POINTER, and GistEntryVector::vector.
{ 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); }
Datum gist_circle_compress | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1105 of file gistproc.c.
References CIRCLE::center, DatumGetCircleP, FALSE, gistentryinit, BOX::high, GISTENTRY::key, GISTENTRY::leafkey, BOX::low, NULL, GISTENTRY::offset, GISTENTRY::page, palloc(), PG_GETARG_POINTER, PG_RETURN_POINTER, PointerGetDatum, CIRCLE::radius, GISTENTRY::rel, Point::x, and Point::y.
{ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *retval; if (entry->leafkey) { retval = palloc(sizeof(GISTENTRY)); if (DatumGetCircleP(entry->key) != NULL) { CIRCLE *in = DatumGetCircleP(entry->key); BOX *r; r = (BOX *) palloc(sizeof(BOX)); r->high.x = in->center.x + in->radius; r->low.x = in->center.x - in->radius; r->high.y = in->center.y + in->radius; r->low.y = in->center.y - in->radius; gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, FALSE); } else { gistentryinit(*retval, (Datum) 0, entry->rel, entry->page, entry->offset, FALSE); } } else retval = entry; PG_RETURN_POINTER(retval); }
Datum gist_circle_consistent | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1144 of file gistproc.c.
References CIRCLE::center, DatumGetBoxP, FALSE, BOX::high, GISTENTRY::key, BOX::low, NULL, PG_GETARG_CIRCLE_P, PG_GETARG_POINTER, PG_GETARG_UINT16, PG_RETURN_BOOL, CIRCLE::radius, rtree_internal_consistent(), Point::x, and Point::y.
Referenced by gist_point_consistent().
{ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); CIRCLE *query = PG_GETARG_CIRCLE_P(1); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); BOX bbox; bool result; /* All cases served by this function are inexact */ *recheck = true; if (DatumGetBoxP(entry->key) == NULL || query == NULL) PG_RETURN_BOOL(FALSE); /* * Since the operators require recheck anyway, we can just use * rtree_internal_consistent even at leaf nodes. (This works in part * because the index entries are bounding boxes not circles.) */ bbox.high.x = query->center.x + query->radius; bbox.low.x = query->center.x - query->radius; bbox.high.y = query->center.y + query->radius; bbox.low.y = query->center.y - query->radius; result = rtree_internal_consistent(DatumGetBoxP(entry->key), &bbox, strategy); PG_RETURN_BOOL(result); }
Datum gist_point_compress | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1182 of file gistproc.c.
References BoxPGetDatum, DatumGetPointP, FALSE, gistentryinit, BOX::high, GISTENTRY::key, GISTENTRY::leafkey, BOX::low, GISTENTRY::offset, GISTENTRY::page, palloc(), PG_GETARG_POINTER, PG_RETURN_POINTER, and GISTENTRY::rel.
{ 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); }
Datum gist_point_consistent | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1322 of file gistproc.c.
References Assert, BoxStrategyNumberGroup, circle_contain_pt(), CirclePGetDatum, CircleStrategyNumberGroup, DatumGetBool, DatumGetBoxP, DirectFunctionCall2, DirectFunctionCall5, elog, ERROR, GeoStrategyNumberOffset, gist_circle_consistent(), GIST_LEAF, gist_point_consistent_internal(), gist_poly_consistent(), BOX::high, Int16GetDatum, GISTENTRY::key, BOX::low, PG_GETARG_BOX_P, PG_GETARG_CIRCLE_P, PG_GETARG_POINT_P, PG_GETARG_POINTER, PG_GETARG_POLYGON_P, PG_GETARG_UINT16, PG_RETURN_BOOL, PointerGetDatum, PointPGetDatum, PointStrategyNumberGroup, poly_contain_pt(), PolygonPGetDatum, PolygonStrategyNumberGroup, RTOverlapStrategyNumber, Point::x, and Point::y.
{ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); bool *recheck = (bool *) PG_GETARG_POINTER(4); bool result; 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: { /* * The only operator in this group is point <@ box (on_pb), so * we needn't examine strategy again. * * For historical reasons, on_pb uses exact rather than fuzzy * comparisons. We could use box_overlap when at an internal * page, but that would lead to possibly visiting child pages * uselessly, because box_overlap uses fuzzy comparisons. * Instead we write a non-fuzzy overlap test. The same code * will also serve for leaf-page tests, since leaf keys have * high == low. */ BOX *query, *key; query = PG_GETARG_BOX_P(1); key = DatumGetBoxP(entry->key); result = (key->high.x >= query->low.x && key->low.x <= query->high.x && key->high.y >= query->low.y && key->low.y <= query->high.y); *recheck = false; } 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: elog(ERROR, "unknown strategy number: %d", strategy); result = false; /* keep compiler quiet */ } PG_RETURN_BOOL(result); }
static bool gist_point_consistent_internal | ( | StrategyNumber | strategy, | |
bool | isLeaf, | |||
BOX * | key, | |||
Point * | query | |||
) | [static] |
Definition at line 1274 of file gistproc.c.
References elog, ERROR, FPeq, FPge, FPgt, FPle, FPlt, BOX::high, BOX::low, RTAboveStrategyNumber, RTBelowStrategyNumber, RTLeftStrategyNumber, RTRightStrategyNumber, RTSameStrategyNumber, Point::x, and Point::y.
Referenced by gist_point_consistent().
{ 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) { /* key.high must equal key.low, so we can disregard it */ result = (FPeq(key->low.x, query->x) && FPeq(key->low.y, query->y)); } else { result = (FPle(query->x, key->high.x) && FPge(query->x, key->low.x) && FPle(query->y, key->high.y) && FPge(query->y, key->low.y)); } break; default: elog(ERROR, "unknown strategy number: %d", strategy); } return result; }
Datum gist_point_distance | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1433 of file gistproc.c.
References computeDistance(), DatumGetBoxP, elog, ERROR, GIST_LEAF, GISTENTRY::key, PG_GETARG_POINT_P, PG_GETARG_POINTER, PG_GETARG_UINT16, PG_RETURN_FLOAT8, and PointStrategyNumberGroup.
{ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); double distance; StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset; switch (strategyGroup) { case PointStrategyNumberGroup: distance = computeDistance(GIST_LEAF(entry), DatumGetBoxP(entry->key), PG_GETARG_POINT_P(1)); break; default: elog(ERROR, "unknown strategy number: %d", strategy); distance = 0.0; /* keep compiler quiet */ } PG_RETURN_FLOAT8(distance); }
Datum gist_poly_compress | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1031 of file gistproc.c.
References POLYGON::boundbox, DatumGetPointer, DatumGetPolygonP, FALSE, gistentryinit, GISTENTRY::key, GISTENTRY::leafkey, NULL, GISTENTRY::offset, GISTENTRY::page, palloc(), PG_GETARG_POINTER, PG_RETURN_POINTER, PointerGetDatum, and GISTENTRY::rel.
{ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *retval; if (entry->leafkey) { retval = palloc(sizeof(GISTENTRY)); if (DatumGetPointer(entry->key) != NULL) { POLYGON *in = DatumGetPolygonP(entry->key); BOX *r; r = (BOX *) palloc(sizeof(BOX)); memcpy((void *) r, (void *) &(in->boundbox), sizeof(BOX)); gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, FALSE); } else { gistentryinit(*retval, (Datum) 0, entry->rel, entry->page, entry->offset, FALSE); } } else retval = entry; PG_RETURN_POINTER(retval); }
Datum gist_poly_consistent | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1067 of file gistproc.c.
References POLYGON::boundbox, DatumGetBoxP, FALSE, GISTENTRY::key, NULL, PG_FREE_IF_COPY, PG_GETARG_POINTER, PG_GETARG_POLYGON_P, PG_GETARG_UINT16, PG_RETURN_BOOL, and rtree_internal_consistent().
Referenced by gist_point_consistent().
{ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); POLYGON *query = PG_GETARG_POLYGON_P(1); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); bool result; /* All cases served by this function are inexact */ *recheck = true; if (DatumGetBoxP(entry->key) == NULL || query == NULL) PG_RETURN_BOOL(FALSE); /* * Since the operators require recheck anyway, we can just use * rtree_internal_consistent even at leaf nodes. (This works in part * because the index entries are bounding boxes not polygons.) */ result = rtree_internal_consistent(DatumGetBoxP(entry->key), &(query->boundbox), strategy); /* Avoid memory leak if supplied poly is toasted */ PG_FREE_IF_COPY(query, 1); PG_RETURN_BOOL(result); }
static int interval_cmp_lower | ( | const void * | i1, | |
const void * | i2 | |||
) | [static] |
Definition at line 278 of file gistproc.c.
Referenced by gist_box_picksplit().
{ double lower1 = ((const SplitInterval *) i1)->lower, lower2 = ((const SplitInterval *) i2)->lower; if (lower1 < lower2) return -1; else if (lower1 > lower2) return 1; else return 0; }
static int interval_cmp_upper | ( | const void * | i1, | |
const void * | i2 | |||
) | [static] |
Definition at line 295 of file gistproc.c.
Referenced by gist_box_picksplit().
{ double upper1 = ((const SplitInterval *) i1)->upper, upper2 = ((const SplitInterval *) i2)->upper; if (upper1 < upper2) return -1; else if (upper1 > upper2) return 1; else return 0; }
static float non_negative | ( | float | val | ) | [inline, static] |
Definition at line 312 of file gistproc.c.
Referenced by g_box_consider_split().
static bool rtree_internal_consistent | ( | BOX * | key, | |
BOX * | query, | |||
StrategyNumber | strategy | |||
) | [static] |
Definition at line 953 of file gistproc.c.
References box_above(), box_below(), box_contain(), box_left(), box_overabove(), box_overbelow(), box_overlap(), box_overleft(), box_overright(), box_right(), DatumGetBool, DirectFunctionCall2, PointerGetDatum, RTAboveStrategyNumber, RTBelowStrategyNumber, RTContainedByStrategyNumber, RTContainsStrategyNumber, RTLeftStrategyNumber, RTOldContainedByStrategyNumber, RTOldContainsStrategyNumber, RTOverAboveStrategyNumber, RTOverBelowStrategyNumber, RTOverlapStrategyNumber, RTOverLeftStrategyNumber, RTOverRightStrategyNumber, RTRightStrategyNumber, and RTSameStrategyNumber.
Referenced by gist_box_consistent(), gist_circle_consistent(), and gist_poly_consistent().
{ bool retval; switch (strategy) { case RTLeftStrategyNumber: retval = !DatumGetBool(DirectFunctionCall2(box_overright, PointerGetDatum(key), PointerGetDatum(query))); break; case RTOverLeftStrategyNumber: retval = !DatumGetBool(DirectFunctionCall2(box_right, PointerGetDatum(key), PointerGetDatum(query))); break; case RTOverlapStrategyNumber: retval = DatumGetBool(DirectFunctionCall2(box_overlap, PointerGetDatum(key), PointerGetDatum(query))); break; case RTOverRightStrategyNumber: retval = !DatumGetBool(DirectFunctionCall2(box_left, PointerGetDatum(key), PointerGetDatum(query))); break; case RTRightStrategyNumber: retval = !DatumGetBool(DirectFunctionCall2(box_overleft, PointerGetDatum(key), PointerGetDatum(query))); break; case RTSameStrategyNumber: case RTContainsStrategyNumber: case RTOldContainsStrategyNumber: retval = DatumGetBool(DirectFunctionCall2(box_contain, PointerGetDatum(key), PointerGetDatum(query))); break; case RTContainedByStrategyNumber: case RTOldContainedByStrategyNumber: retval = DatumGetBool(DirectFunctionCall2(box_overlap, PointerGetDatum(key), PointerGetDatum(query))); break; case RTOverBelowStrategyNumber: retval = !DatumGetBool(DirectFunctionCall2(box_above, PointerGetDatum(key), PointerGetDatum(query))); break; case RTBelowStrategyNumber: retval = !DatumGetBool(DirectFunctionCall2(box_overabove, PointerGetDatum(key), PointerGetDatum(query))); break; case RTAboveStrategyNumber: retval = !DatumGetBool(DirectFunctionCall2(box_overbelow, PointerGetDatum(key), PointerGetDatum(query))); break; case RTOverAboveStrategyNumber: retval = !DatumGetBool(DirectFunctionCall2(box_below, PointerGetDatum(key), PointerGetDatum(query))); break; default: retval = FALSE; } return retval; }
static double size_box | ( | BOX * | box | ) | [static] |