PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
gistproc.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * gistproc.c
4  * Support procedures for GiSTs over 2-D objects (boxes, polygons, circles,
5  * points).
6  *
7  * This gives R-tree behavior, with Guttman's poly-time split algorithm.
8  *
9  *
10  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
11  * Portions Copyright (c) 1994, Regents of the University of California
12  *
13  * IDENTIFICATION
14  * src/backend/access/gist/gistproc.c
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres.h"
19 
20 #include "access/gist.h"
21 #include "access/stratnum.h"
22 #include "utils/geo_decls.h"
23 
24 
25 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
26  StrategyNumber strategy);
27 static double size_box(BOX *box);
28 static bool rtree_internal_consistent(BOX *key, BOX *query,
29  StrategyNumber strategy);
30 
31 /* Minimum accepted ratio of split */
32 #define LIMIT_RATIO 0.3
33 
34 
35 /**************************************************
36  * Box ops
37  **************************************************/
38 
39 /*
40  * Calculates union of two boxes, a and b. The result is stored in *n.
41  */
42 static void
43 rt_box_union(BOX *n, BOX *a, BOX *b)
44 {
45  n->high.x = Max(a->high.x, b->high.x);
46  n->high.y = Max(a->high.y, b->high.y);
47  n->low.x = Min(a->low.x, b->low.x);
48  n->low.y = Min(a->low.y, b->low.y);
49 }
50 
51 /*
52  * The GiST Consistent method for boxes
53  *
54  * Should return false if for all data items x below entry,
55  * the predicate x op query must be FALSE, where op is the oper
56  * corresponding to strategy in the pg_amop table.
57  */
58 Datum
60 {
61  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
62  BOX *query = PG_GETARG_BOX_P(1);
64 
65  /* Oid subtype = PG_GETARG_OID(3); */
66  bool *recheck = (bool *) PG_GETARG_POINTER(4);
67 
68  /* All cases served by this function are exact */
69  *recheck = false;
70 
71  if (DatumGetBoxP(entry->key) == NULL || query == NULL)
73 
74  /*
75  * if entry is not leaf, use rtree_internal_consistent, else use
76  * gist_box_leaf_consistent
77  */
78  if (GIST_LEAF(entry))
80  query,
81  strategy));
82  else
84  query,
85  strategy));
86 }
87 
88 static void
89 adjustBox(BOX *b, BOX *addon)
90 {
91  if (b->high.x < addon->high.x)
92  b->high.x = addon->high.x;
93  if (b->low.x > addon->low.x)
94  b->low.x = addon->low.x;
95  if (b->high.y < addon->high.y)
96  b->high.y = addon->high.y;
97  if (b->low.y > addon->low.y)
98  b->low.y = addon->low.y;
99 }
100 
101 /*
102  * The GiST Union method for boxes
103  *
104  * returns the minimal bounding box that encloses all the entries in entryvec
105  */
106 Datum
108 {
110  int *sizep = (int *) PG_GETARG_POINTER(1);
111  int numranges,
112  i;
113  BOX *cur,
114  *pageunion;
115 
116  numranges = entryvec->n;
117  pageunion = (BOX *) palloc(sizeof(BOX));
118  cur = DatumGetBoxP(entryvec->vector[0].key);
119  memcpy((void *) pageunion, (void *) cur, sizeof(BOX));
120 
121  for (i = 1; i < numranges; i++)
122  {
123  cur = DatumGetBoxP(entryvec->vector[i].key);
124  adjustBox(pageunion, cur);
125  }
126  *sizep = sizeof(BOX);
127 
128  PG_RETURN_POINTER(pageunion);
129 }
130 
131 /*
132  * GiST Compress methods for boxes
133  *
134  * do not do anything.
135  */
136 Datum
138 {
140 }
141 
142 /*
143  * GiST DeCompress method for boxes (also used for points, polygons
144  * and circles)
145  *
146  * do not do anything --- we just use the stored box as is.
147  */
148 Datum
150 {
152 }
153 
154 /*
155  * GiST Fetch method for boxes
156  * do not do anything --- we just return the stored box as is.
157  */
158 Datum
160 {
162 }
163 
164 /*
165  * The GiST Penalty method for boxes (also used for points)
166  *
167  * As in the R-tree paper, we use change in area as our penalty metric
168  */
169 Datum
171 {
172  GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
173  GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
174  float *result = (float *) PG_GETARG_POINTER(2);
175  BOX *origbox = DatumGetBoxP(origentry->key);
176  BOX *newbox = DatumGetBoxP(newentry->key);
177  BOX unionbox;
178 
179  rt_box_union(&unionbox, origbox, newbox);
180  *result = (float) (size_box(&unionbox) - size_box(origbox));
181  PG_RETURN_POINTER(result);
182 }
183 
184 /*
185  * Trivial split: half of entries will be placed on one page
186  * and another half - to another
187  */
188 static void
190 {
191  OffsetNumber i,
192  maxoff;
193  BOX *unionL = NULL,
194  *unionR = NULL;
195  int nbytes;
196 
197  maxoff = entryvec->n - 1;
198 
199  nbytes = (maxoff + 2) * sizeof(OffsetNumber);
200  v->spl_left = (OffsetNumber *) palloc(nbytes);
201  v->spl_right = (OffsetNumber *) palloc(nbytes);
202  v->spl_nleft = v->spl_nright = 0;
203 
204  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
205  {
206  BOX *cur = DatumGetBoxP(entryvec->vector[i].key);
207 
208  if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
209  {
210  v->spl_left[v->spl_nleft] = i;
211  if (unionL == NULL)
212  {
213  unionL = (BOX *) palloc(sizeof(BOX));
214  *unionL = *cur;
215  }
216  else
217  adjustBox(unionL, cur);
218 
219  v->spl_nleft++;
220  }
221  else
222  {
223  v->spl_right[v->spl_nright] = i;
224  if (unionR == NULL)
225  {
226  unionR = (BOX *) palloc(sizeof(BOX));
227  *unionR = *cur;
228  }
229  else
230  adjustBox(unionR, cur);
231 
232  v->spl_nright++;
233  }
234  }
235 
236  v->spl_ldatum = BoxPGetDatum(unionL);
237  v->spl_rdatum = BoxPGetDatum(unionR);
238 }
239 
240 /*
241  * Represents information about an entry that can be placed to either group
242  * without affecting overlap over selected axis ("common entry").
243  */
244 typedef struct
245 {
246  /* Index of entry in the initial array */
247  int index;
248  /* Delta between penalties of entry insertion into different groups */
249  double delta;
250 } CommonEntry;
251 
252 /*
253  * Context for g_box_consider_split. Contains information about currently
254  * selected split and some general information.
255  */
256 typedef struct
257 {
258  int entriesCount; /* total number of entries being split */
259  BOX boundingBox; /* minimum bounding box across all entries */
260 
261  /* Information about currently selected split follows */
262 
263  bool first; /* true if no split was selected yet */
264 
265  double leftUpper; /* upper bound of left interval */
266  double rightLower; /* lower bound of right interval */
267 
270  int dim; /* axis of this split */
271  double range; /* width of general MBR projection to the
272  * selected axis */
274 
275 /*
276  * Interval represents projection of box to axis.
277  */
278 typedef struct
279 {
280  double lower,
281  upper;
282 } SplitInterval;
283 
284 /*
285  * Interval comparison function by lower bound of the interval;
286  */
287 static int
288 interval_cmp_lower(const void *i1, const void *i2)
289 {
290  double lower1 = ((const SplitInterval *) i1)->lower,
291  lower2 = ((const SplitInterval *) i2)->lower;
292 
293  if (lower1 < lower2)
294  return -1;
295  else if (lower1 > lower2)
296  return 1;
297  else
298  return 0;
299 }
300 
301 /*
302  * Interval comparison function by upper bound of the interval;
303  */
304 static int
305 interval_cmp_upper(const void *i1, const void *i2)
306 {
307  double upper1 = ((const SplitInterval *) i1)->upper,
308  upper2 = ((const SplitInterval *) i2)->upper;
309 
310  if (upper1 < upper2)
311  return -1;
312  else if (upper1 > upper2)
313  return 1;
314  else
315  return 0;
316 }
317 
318 /*
319  * Replace negative value with zero.
320  */
321 static inline float
323 {
324  if (val >= 0.0f)
325  return val;
326  else
327  return 0.0f;
328 }
329 
330 /*
331  * Consider replacement of currently selected split with the better one.
332  */
333 static inline void
335  double rightLower, int minLeftCount,
336  double leftUpper, int maxLeftCount)
337 {
338  int leftCount,
339  rightCount;
340  float4 ratio,
341  overlap;
342  double range;
343 
344  /*
345  * Calculate entries distribution ratio assuming most uniform distribution
346  * of common entries.
347  */
348  if (minLeftCount >= (context->entriesCount + 1) / 2)
349  {
350  leftCount = minLeftCount;
351  }
352  else
353  {
354  if (maxLeftCount <= context->entriesCount / 2)
355  leftCount = maxLeftCount;
356  else
357  leftCount = context->entriesCount / 2;
358  }
359  rightCount = context->entriesCount - leftCount;
360 
361  /*
362  * Ratio of split - quotient between size of lesser group and total
363  * entries count.
364  */
365  ratio = ((float4) Min(leftCount, rightCount)) /
366  ((float4) context->entriesCount);
367 
368  if (ratio > LIMIT_RATIO)
369  {
370  bool selectthis = false;
371 
372  /*
373  * The ratio is acceptable, so compare current split with previously
374  * selected one. Between splits of one dimension we search for minimal
375  * overlap (allowing negative values) and minimal ration (between same
376  * overlaps. We switch dimension if find less overlap (non-negative)
377  * or less range with same overlap.
378  */
379  if (dimNum == 0)
380  range = context->boundingBox.high.x - context->boundingBox.low.x;
381  else
382  range = context->boundingBox.high.y - context->boundingBox.low.y;
383 
384  overlap = (leftUpper - rightLower) / range;
385 
386  /* If there is no previous selection, select this */
387  if (context->first)
388  selectthis = true;
389  else if (context->dim == dimNum)
390  {
391  /*
392  * Within the same dimension, choose the new split if it has a
393  * smaller overlap, or same overlap but better ratio.
394  */
395  if (overlap < context->overlap ||
396  (overlap == context->overlap && ratio > context->ratio))
397  selectthis = true;
398  }
399  else
400  {
401  /*
402  * Across dimensions, choose the new split if it has a smaller
403  * *non-negative* overlap, or same *non-negative* overlap but
404  * bigger range. This condition differs from the one described in
405  * the article. On the datasets where leaf MBRs don't overlap
406  * themselves, non-overlapping splits (i.e. splits which have zero
407  * *non-negative* overlap) are frequently possible. In this case
408  * splits tends to be along one dimension, because most distant
409  * non-overlapping splits (i.e. having lowest negative overlap)
410  * appears to be in the same dimension as in the previous split.
411  * Therefore MBRs appear to be very prolonged along another
412  * dimension, which leads to bad search performance. Using range
413  * as the second split criteria makes MBRs more quadratic. Using
414  * *non-negative* overlap instead of overlap as the first split
415  * criteria gives to range criteria a chance to matter, because
416  * non-overlapping splits are equivalent in this criteria.
417  */
418  if (non_negative(overlap) < non_negative(context->overlap) ||
419  (range > context->range &&
420  non_negative(overlap) <= non_negative(context->overlap)))
421  selectthis = true;
422  }
423 
424  if (selectthis)
425  {
426  /* save information about selected split */
427  context->first = false;
428  context->ratio = ratio;
429  context->range = range;
430  context->overlap = overlap;
431  context->rightLower = rightLower;
432  context->leftUpper = leftUpper;
433  context->dim = dimNum;
434  }
435  }
436 }
437 
438 /*
439  * Return increase of original BOX area by new BOX area insertion.
440  */
441 static double
442 box_penalty(BOX *original, BOX *new)
443 {
444  double union_width,
445  union_height;
446 
447  union_width = Max(original->high.x, new->high.x) -
448  Min(original->low.x, new->low.x);
449  union_height = Max(original->high.y, new->high.y) -
450  Min(original->low.y, new->low.y);
451  return union_width * union_height - (original->high.x - original->low.x) *
452  (original->high.y - original->low.y);
453 }
454 
455 /*
456  * Compare common entries by their deltas.
457  */
458 static int
459 common_entry_cmp(const void *i1, const void *i2)
460 {
461  double delta1 = ((const CommonEntry *) i1)->delta,
462  delta2 = ((const CommonEntry *) i2)->delta;
463 
464  if (delta1 < delta2)
465  return -1;
466  else if (delta1 > delta2)
467  return 1;
468  else
469  return 0;
470 }
471 
472 /*
473  * --------------------------------------------------------------------------
474  * Double sorting split algorithm. This is used for both boxes and points.
475  *
476  * The algorithm finds split of boxes by considering splits along each axis.
477  * Each entry is first projected as an interval on the X-axis, and different
478  * ways to split the intervals into two groups are considered, trying to
479  * minimize the overlap of the groups. Then the same is repeated for the
480  * Y-axis, and the overall best split is chosen. The quality of a split is
481  * determined by overlap along that axis and some other criteria (see
482  * g_box_consider_split).
483  *
484  * After that, all the entries are divided into three groups:
485  *
486  * 1) Entries which should be placed to the left group
487  * 2) Entries which should be placed to the right group
488  * 3) "Common entries" which can be placed to any of groups without affecting
489  * of overlap along selected axis.
490  *
491  * The common entries are distributed by minimizing penalty.
492  *
493  * For details see:
494  * "A new double sorting-based node splitting algorithm for R-tree", A. Korotkov
495  * http://syrcose.ispras.ru/2011/files/SYRCoSE2011_Proceedings.pdf#page=36
496  * --------------------------------------------------------------------------
497  */
498 Datum
500 {
503  OffsetNumber i,
504  maxoff;
505  ConsiderSplitContext context;
506  BOX *box,
507  *leftBox,
508  *rightBox;
509  int dim,
510  commonEntriesCount;
511  SplitInterval *intervalsLower,
512  *intervalsUpper;
513  CommonEntry *commonEntries;
514  int nentries;
515 
516  memset(&context, 0, sizeof(ConsiderSplitContext));
517 
518  maxoff = entryvec->n - 1;
519  nentries = context.entriesCount = maxoff - FirstOffsetNumber + 1;
520 
521  /* Allocate arrays for intervals along axes */
522  intervalsLower = (SplitInterval *) palloc(nentries * sizeof(SplitInterval));
523  intervalsUpper = (SplitInterval *) palloc(nentries * sizeof(SplitInterval));
524 
525  /*
526  * Calculate the overall minimum bounding box over all the entries.
527  */
528  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
529  {
530  box = DatumGetBoxP(entryvec->vector[i].key);
531  if (i == FirstOffsetNumber)
532  context.boundingBox = *box;
533  else
534  adjustBox(&context.boundingBox, box);
535  }
536 
537  /*
538  * Iterate over axes for optimal split searching.
539  */
540  context.first = true; /* nothing selected yet */
541  for (dim = 0; dim < 2; dim++)
542  {
543  double leftUpper,
544  rightLower;
545  int i1,
546  i2;
547 
548  /* Project each entry as an interval on the selected axis. */
549  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
550  {
551  box = DatumGetBoxP(entryvec->vector[i].key);
552  if (dim == 0)
553  {
554  intervalsLower[i - FirstOffsetNumber].lower = box->low.x;
555  intervalsLower[i - FirstOffsetNumber].upper = box->high.x;
556  }
557  else
558  {
559  intervalsLower[i - FirstOffsetNumber].lower = box->low.y;
560  intervalsLower[i - FirstOffsetNumber].upper = box->high.y;
561  }
562  }
563 
564  /*
565  * Make two arrays of intervals: one sorted by lower bound and another
566  * sorted by upper bound.
567  */
568  memcpy(intervalsUpper, intervalsLower,
569  sizeof(SplitInterval) * nentries);
570  qsort(intervalsLower, nentries, sizeof(SplitInterval),
572  qsort(intervalsUpper, nentries, sizeof(SplitInterval),
574 
575  /*----
576  * The goal is to form a left and right interval, so that every entry
577  * interval is contained by either left or right interval (or both).
578  *
579  * For example, with the intervals (0,1), (1,3), (2,3), (2,4):
580  *
581  * 0 1 2 3 4
582  * +-+
583  * +---+
584  * +-+
585  * +---+
586  *
587  * The left and right intervals are of the form (0,a) and (b,4).
588  * We first consider splits where b is the lower bound of an entry.
589  * We iterate through all entries, and for each b, calculate the
590  * smallest possible a. Then we consider splits where a is the
591  * upper bound of an entry, and for each a, calculate the greatest
592  * possible b.
593  *
594  * In the above example, the first loop would consider splits:
595  * b=0: (0,1)-(0,4)
596  * b=1: (0,1)-(1,4)
597  * b=2: (0,3)-(2,4)
598  *
599  * And the second loop:
600  * a=1: (0,1)-(1,4)
601  * a=3: (0,3)-(2,4)
602  * a=4: (0,4)-(2,4)
603  */
604 
605  /*
606  * Iterate over lower bound of right group, finding smallest possible
607  * upper bound of left group.
608  */
609  i1 = 0;
610  i2 = 0;
611  rightLower = intervalsLower[i1].lower;
612  leftUpper = intervalsUpper[i2].lower;
613  while (true)
614  {
615  /*
616  * Find next lower bound of right group.
617  */
618  while (i1 < nentries && rightLower == intervalsLower[i1].lower)
619  {
620  leftUpper = Max(leftUpper, intervalsLower[i1].upper);
621  i1++;
622  }
623  if (i1 >= nentries)
624  break;
625  rightLower = intervalsLower[i1].lower;
626 
627  /*
628  * Find count of intervals which anyway should be placed to the
629  * left group.
630  */
631  while (i2 < nentries && intervalsUpper[i2].upper <= leftUpper)
632  i2++;
633 
634  /*
635  * Consider found split.
636  */
637  g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
638  }
639 
640  /*
641  * Iterate over upper bound of left group finding greatest possible
642  * lower bound of right group.
643  */
644  i1 = nentries - 1;
645  i2 = nentries - 1;
646  rightLower = intervalsLower[i1].upper;
647  leftUpper = intervalsUpper[i2].upper;
648  while (true)
649  {
650  /*
651  * Find next upper bound of left group.
652  */
653  while (i2 >= 0 && leftUpper == intervalsUpper[i2].upper)
654  {
655  rightLower = Min(rightLower, intervalsUpper[i2].lower);
656  i2--;
657  }
658  if (i2 < 0)
659  break;
660  leftUpper = intervalsUpper[i2].upper;
661 
662  /*
663  * Find count of intervals which anyway should be placed to the
664  * right group.
665  */
666  while (i1 >= 0 && intervalsLower[i1].lower >= rightLower)
667  i1--;
668 
669  /*
670  * Consider found split.
671  */
672  g_box_consider_split(&context, dim,
673  rightLower, i1 + 1, leftUpper, i2 + 1);
674  }
675  }
676 
677  /*
678  * If we failed to find any acceptable splits, use trivial split.
679  */
680  if (context.first)
681  {
682  fallbackSplit(entryvec, v);
684  }
685 
686  /*
687  * Ok, we have now selected the split across one axis.
688  *
689  * While considering the splits, we already determined that there will be
690  * enough entries in both groups to reach the desired ratio, but we did
691  * not memorize which entries go to which group. So determine that now.
692  */
693 
694  /* Allocate vectors for results */
695  v->spl_left = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber));
696  v->spl_right = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber));
697  v->spl_nleft = 0;
698  v->spl_nright = 0;
699 
700  /* Allocate bounding boxes of left and right groups */
701  leftBox = palloc0(sizeof(BOX));
702  rightBox = palloc0(sizeof(BOX));
703 
704  /*
705  * Allocate an array for "common entries" - entries which can be placed to
706  * either group without affecting overlap along selected axis.
707  */
708  commonEntriesCount = 0;
709  commonEntries = (CommonEntry *) palloc(nentries * sizeof(CommonEntry));
710 
711  /* Helper macros to place an entry in the left or right group */
712 #define PLACE_LEFT(box, off) \
713  do { \
714  if (v->spl_nleft > 0) \
715  adjustBox(leftBox, box); \
716  else \
717  *leftBox = *(box); \
718  v->spl_left[v->spl_nleft++] = off; \
719  } while(0)
720 
721 #define PLACE_RIGHT(box, off) \
722  do { \
723  if (v->spl_nright > 0) \
724  adjustBox(rightBox, box); \
725  else \
726  *rightBox = *(box); \
727  v->spl_right[v->spl_nright++] = off; \
728  } while(0)
729 
730  /*
731  * Distribute entries which can be distributed unambiguously, and collect
732  * common entries.
733  */
734  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
735  {
736  double lower,
737  upper;
738 
739  /*
740  * Get upper and lower bounds along selected axis.
741  */
742  box = DatumGetBoxP(entryvec->vector[i].key);
743  if (context.dim == 0)
744  {
745  lower = box->low.x;
746  upper = box->high.x;
747  }
748  else
749  {
750  lower = box->low.y;
751  upper = box->high.y;
752  }
753 
754  if (upper <= context.leftUpper)
755  {
756  /* Fits to the left group */
757  if (lower >= context.rightLower)
758  {
759  /* Fits also to the right group, so "common entry" */
760  commonEntries[commonEntriesCount++].index = i;
761  }
762  else
763  {
764  /* Doesn't fit to the right group, so join to the left group */
765  PLACE_LEFT(box, i);
766  }
767  }
768  else
769  {
770  /*
771  * Each entry should fit on either left or right group. Since this
772  * entry didn't fit on the left group, it better fit in the right
773  * group.
774  */
775  Assert(lower >= context.rightLower);
776 
777  /* Doesn't fit to the left group, so join to the right group */
778  PLACE_RIGHT(box, i);
779  }
780  }
781 
782  /*
783  * Distribute "common entries", if any.
784  */
785  if (commonEntriesCount > 0)
786  {
787  /*
788  * Calculate minimum number of entries that must be placed in both
789  * groups, to reach LIMIT_RATIO.
790  */
791  int m = ceil(LIMIT_RATIO * (double) nentries);
792 
793  /*
794  * Calculate delta between penalties of join "common entries" to
795  * different groups.
796  */
797  for (i = 0; i < commonEntriesCount; i++)
798  {
799  box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
800  commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
801  box_penalty(rightBox, box));
802  }
803 
804  /*
805  * Sort "common entries" by calculated deltas in order to distribute
806  * the most ambiguous entries first.
807  */
808  qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);
809 
810  /*
811  * Distribute "common entries" between groups.
812  */
813  for (i = 0; i < commonEntriesCount; i++)
814  {
815  box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
816 
817  /*
818  * Check if we have to place this entry in either group to achieve
819  * LIMIT_RATIO.
820  */
821  if (v->spl_nleft + (commonEntriesCount - i) <= m)
822  PLACE_LEFT(box, commonEntries[i].index);
823  else if (v->spl_nright + (commonEntriesCount - i) <= m)
824  PLACE_RIGHT(box, commonEntries[i].index);
825  else
826  {
827  /* Otherwise select the group by minimal penalty */
828  if (box_penalty(leftBox, box) < box_penalty(rightBox, box))
829  PLACE_LEFT(box, commonEntries[i].index);
830  else
831  PLACE_RIGHT(box, commonEntries[i].index);
832  }
833  }
834  }
835 
836  v->spl_ldatum = PointerGetDatum(leftBox);
837  v->spl_rdatum = PointerGetDatum(rightBox);
839 }
840 
841 /*
842  * Equality method
843  *
844  * This is used for boxes, points, circles, and polygons, all of which store
845  * boxes as GiST index entries.
846  *
847  * Returns true only when boxes are exactly the same. We can't use fuzzy
848  * comparisons here without breaking index consistency; therefore, this isn't
849  * equivalent to box_same().
850  */
851 Datum
853 {
854  BOX *b1 = PG_GETARG_BOX_P(0);
855  BOX *b2 = PG_GETARG_BOX_P(1);
856  bool *result = (bool *) PG_GETARG_POINTER(2);
857 
858  if (b1 && b2)
859  *result = (b1->low.x == b2->low.x && b1->low.y == b2->low.y &&
860  b1->high.x == b2->high.x && b1->high.y == b2->high.y);
861  else
862  *result = (b1 == NULL && b2 == NULL);
863  PG_RETURN_POINTER(result);
864 }
865 
866 /*
867  * Leaf-level consistency for boxes: just apply the query operator
868  */
869 static bool
871 {
872  bool retval;
873 
874  switch (strategy)
875  {
878  PointerGetDatum(key),
879  PointerGetDatum(query)));
880  break;
883  PointerGetDatum(key),
884  PointerGetDatum(query)));
885  break;
888  PointerGetDatum(key),
889  PointerGetDatum(query)));
890  break;
893  PointerGetDatum(key),
894  PointerGetDatum(query)));
895  break;
898  PointerGetDatum(key),
899  PointerGetDatum(query)));
900  break;
903  PointerGetDatum(key),
904  PointerGetDatum(query)));
905  break;
909  PointerGetDatum(key),
910  PointerGetDatum(query)));
911  break;
915  PointerGetDatum(key),
916  PointerGetDatum(query)));
917  break;
920  PointerGetDatum(key),
921  PointerGetDatum(query)));
922  break;
925  PointerGetDatum(key),
926  PointerGetDatum(query)));
927  break;
930  PointerGetDatum(key),
931  PointerGetDatum(query)));
932  break;
935  PointerGetDatum(key),
936  PointerGetDatum(query)));
937  break;
938  default:
939  elog(ERROR, "unrecognized strategy number: %d", strategy);
940  retval = false; /* keep compiler quiet */
941  break;
942  }
943  return retval;
944 }
945 
946 static double
948 {
949  if (box->high.x <= box->low.x || box->high.y <= box->low.y)
950  return 0.0;
951  return (box->high.x - box->low.x) * (box->high.y - box->low.y);
952 }
953 
954 /*****************************************
955  * Common rtree functions (for boxes, polygons, and circles)
956  *****************************************/
957 
958 /*
959  * Internal-page consistency for all these types
960  *
961  * We can use the same function since all types use bounding boxes as the
962  * internal-page representation.
963  */
964 static bool
966 {
967  bool retval;
968 
969  switch (strategy)
970  {
973  PointerGetDatum(key),
974  PointerGetDatum(query)));
975  break;
978  PointerGetDatum(key),
979  PointerGetDatum(query)));
980  break;
983  PointerGetDatum(key),
984  PointerGetDatum(query)));
985  break;
988  PointerGetDatum(key),
989  PointerGetDatum(query)));
990  break;
993  PointerGetDatum(key),
994  PointerGetDatum(query)));
995  break;
1000  PointerGetDatum(key),
1001  PointerGetDatum(query)));
1002  break;
1006  PointerGetDatum(key),
1007  PointerGetDatum(query)));
1008  break;
1011  PointerGetDatum(key),
1012  PointerGetDatum(query)));
1013  break;
1014  case RTBelowStrategyNumber:
1016  PointerGetDatum(key),
1017  PointerGetDatum(query)));
1018  break;
1019  case RTAboveStrategyNumber:
1021  PointerGetDatum(key),
1022  PointerGetDatum(query)));
1023  break;
1026  PointerGetDatum(key),
1027  PointerGetDatum(query)));
1028  break;
1029  default:
1030  elog(ERROR, "unrecognized strategy number: %d", strategy);
1031  retval = false; /* keep compiler quiet */
1032  break;
1033  }
1034  return retval;
1035 }
1036 
1037 /**************************************************
1038  * Polygon ops
1039  **************************************************/
1040 
1041 /*
1042  * GiST compress for polygons: represent a polygon by its bounding box
1043  */
1044 Datum
1046 {
1047  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1048  GISTENTRY *retval;
1049 
1050  if (entry->leafkey)
1051  {
1052  POLYGON *in = DatumGetPolygonP(entry->key);
1053  BOX *r;
1054 
1055  r = (BOX *) palloc(sizeof(BOX));
1056  memcpy((void *) r, (void *) &(in->boundbox), sizeof(BOX));
1057 
1058  retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
1059  gistentryinit(*retval, PointerGetDatum(r),
1060  entry->rel, entry->page,
1061  entry->offset, FALSE);
1062  }
1063  else
1064  retval = entry;
1065  PG_RETURN_POINTER(retval);
1066 }
1067 
1068 /*
1069  * The GiST Consistent method for polygons
1070  */
1071 Datum
1073 {
1074  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1075  POLYGON *query = PG_GETARG_POLYGON_P(1);
1077 
1078  /* Oid subtype = PG_GETARG_OID(3); */
1079  bool *recheck = (bool *) PG_GETARG_POINTER(4);
1080  bool result;
1081 
1082  /* All cases served by this function are inexact */
1083  *recheck = true;
1084 
1085  if (DatumGetBoxP(entry->key) == NULL || query == NULL)
1087 
1088  /*
1089  * Since the operators require recheck anyway, we can just use
1090  * rtree_internal_consistent even at leaf nodes. (This works in part
1091  * because the index entries are bounding boxes not polygons.)
1092  */
1093  result = rtree_internal_consistent(DatumGetBoxP(entry->key),
1094  &(query->boundbox), strategy);
1095 
1096  /* Avoid memory leak if supplied poly is toasted */
1097  PG_FREE_IF_COPY(query, 1);
1098 
1099  PG_RETURN_BOOL(result);
1100 }
1101 
1102 /**************************************************
1103  * Circle ops
1104  **************************************************/
1105 
1106 /*
1107  * GiST compress for circles: represent a circle by its bounding box
1108  */
1109 Datum
1111 {
1112  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1113  GISTENTRY *retval;
1114 
1115  if (entry->leafkey)
1116  {
1117  CIRCLE *in = DatumGetCircleP(entry->key);
1118  BOX *r;
1119 
1120  r = (BOX *) palloc(sizeof(BOX));
1121  r->high.x = in->center.x + in->radius;
1122  r->low.x = in->center.x - in->radius;
1123  r->high.y = in->center.y + in->radius;
1124  r->low.y = in->center.y - in->radius;
1125 
1126  retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
1127  gistentryinit(*retval, PointerGetDatum(r),
1128  entry->rel, entry->page,
1129  entry->offset, FALSE);
1130  }
1131  else
1132  retval = entry;
1133  PG_RETURN_POINTER(retval);
1134 }
1135 
1136 /*
1137  * The GiST Consistent method for circles
1138  */
1139 Datum
1141 {
1142  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1143  CIRCLE *query = PG_GETARG_CIRCLE_P(1);
1145 
1146  /* Oid subtype = PG_GETARG_OID(3); */
1147  bool *recheck = (bool *) PG_GETARG_POINTER(4);
1148  BOX bbox;
1149  bool result;
1150 
1151  /* All cases served by this function are inexact */
1152  *recheck = true;
1153 
1154  if (DatumGetBoxP(entry->key) == NULL || query == NULL)
1156 
1157  /*
1158  * Since the operators require recheck anyway, we can just use
1159  * rtree_internal_consistent even at leaf nodes. (This works in part
1160  * because the index entries are bounding boxes not circles.)
1161  */
1162  bbox.high.x = query->center.x + query->radius;
1163  bbox.low.x = query->center.x - query->radius;
1164  bbox.high.y = query->center.y + query->radius;
1165  bbox.low.y = query->center.y - query->radius;
1166 
1167  result = rtree_internal_consistent(DatumGetBoxP(entry->key),
1168  &bbox, strategy);
1169 
1170  PG_RETURN_BOOL(result);
1171 }
1172 
1173 /**************************************************
1174  * Point ops
1175  **************************************************/
1176 
1177 Datum
1179 {
1180  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1181 
1182  if (entry->leafkey) /* Point, actually */
1183  {
1184  BOX *box = palloc(sizeof(BOX));
1185  Point *point = DatumGetPointP(entry->key);
1186  GISTENTRY *retval = palloc(sizeof(GISTENTRY));
1187 
1188  box->high = box->low = *point;
1189 
1190  gistentryinit(*retval, BoxPGetDatum(box),
1191  entry->rel, entry->page, entry->offset, FALSE);
1192 
1193  PG_RETURN_POINTER(retval);
1194  }
1195 
1196  PG_RETURN_POINTER(entry);
1197 }
1198 
1199 /*
1200  * GiST Fetch method for point
1201  *
1202  * Get point coordinates from its bounding box coordinates and form new
1203  * gistentry.
1204  */
1205 Datum
1207 {
1208  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1209  BOX *in = DatumGetBoxP(entry->key);
1210  Point *r;
1211  GISTENTRY *retval;
1212 
1213  retval = palloc(sizeof(GISTENTRY));
1214 
1215  r = (Point *) palloc(sizeof(Point));
1216  r->x = in->high.x;
1217  r->y = in->high.y;
1218  gistentryinit(*retval, PointerGetDatum(r),
1219  entry->rel, entry->page,
1220  entry->offset, FALSE);
1221 
1222  PG_RETURN_POINTER(retval);
1223 }
1224 
1225 
1226 #define point_point_distance(p1,p2) \
1227  DatumGetFloat8(DirectFunctionCall2(point_distance, \
1228  PointPGetDatum(p1), PointPGetDatum(p2)))
1229 
1230 static double
1231 computeDistance(bool isLeaf, BOX *box, Point *point)
1232 {
1233  double result = 0.0;
1234 
1235  if (isLeaf)
1236  {
1237  /* simple point to point distance */
1238  result = point_point_distance(point, &box->low);
1239  }
1240  else if (point->x <= box->high.x && point->x >= box->low.x &&
1241  point->y <= box->high.y && point->y >= box->low.y)
1242  {
1243  /* point inside the box */
1244  result = 0.0;
1245  }
1246  else if (point->x <= box->high.x && point->x >= box->low.x)
1247  {
1248  /* point is over or below box */
1249  Assert(box->low.y <= box->high.y);
1250  if (point->y > box->high.y)
1251  result = point->y - box->high.y;
1252  else if (point->y < box->low.y)
1253  result = box->low.y - point->y;
1254  else
1255  elog(ERROR, "inconsistent point values");
1256  }
1257  else if (point->y <= box->high.y && point->y >= box->low.y)
1258  {
1259  /* point is to left or right of box */
1260  Assert(box->low.x <= box->high.x);
1261  if (point->x > box->high.x)
1262  result = point->x - box->high.x;
1263  else if (point->x < box->low.x)
1264  result = box->low.x - point->x;
1265  else
1266  elog(ERROR, "inconsistent point values");
1267  }
1268  else
1269  {
1270  /* closest point will be a vertex */
1271  Point p;
1272  double subresult;
1273 
1274  result = point_point_distance(point, &box->low);
1275 
1276  subresult = point_point_distance(point, &box->high);
1277  if (result > subresult)
1278  result = subresult;
1279 
1280  p.x = box->low.x;
1281  p.y = box->high.y;
1282  subresult = point_point_distance(point, &p);
1283  if (result > subresult)
1284  result = subresult;
1285 
1286  p.x = box->high.x;
1287  p.y = box->low.y;
1288  subresult = point_point_distance(point, &p);
1289  if (result > subresult)
1290  result = subresult;
1291  }
1292 
1293  return result;
1294 }
1295 
1296 static bool
1298  bool isLeaf, BOX *key, Point *query)
1299 {
1300  bool result = false;
1301 
1302  switch (strategy)
1303  {
1304  case RTLeftStrategyNumber:
1305  result = FPlt(key->low.x, query->x);
1306  break;
1307  case RTRightStrategyNumber:
1308  result = FPgt(key->high.x, query->x);
1309  break;
1310  case RTAboveStrategyNumber:
1311  result = FPgt(key->high.y, query->y);
1312  break;
1313  case RTBelowStrategyNumber:
1314  result = FPlt(key->low.y, query->y);
1315  break;
1316  case RTSameStrategyNumber:
1317  if (isLeaf)
1318  {
1319  /* key.high must equal key.low, so we can disregard it */
1320  result = (FPeq(key->low.x, query->x) &&
1321  FPeq(key->low.y, query->y));
1322  }
1323  else
1324  {
1325  result = (FPle(query->x, key->high.x) &&
1326  FPge(query->x, key->low.x) &&
1327  FPle(query->y, key->high.y) &&
1328  FPge(query->y, key->low.y));
1329  }
1330  break;
1331  default:
1332  elog(ERROR, "unrecognized strategy number: %d", strategy);
1333  result = false; /* keep compiler quiet */
1334  break;
1335  }
1336 
1337  return result;
1338 }
1339 
1340 #define GeoStrategyNumberOffset 20
1341 #define PointStrategyNumberGroup 0
1342 #define BoxStrategyNumberGroup 1
1343 #define PolygonStrategyNumberGroup 2
1344 #define CircleStrategyNumberGroup 3
1345 
1346 Datum
1348 {
1349  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1351  bool *recheck = (bool *) PG_GETARG_POINTER(4);
1352  bool result;
1353  StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
1354 
1355  switch (strategyGroup)
1356  {
1359  GIST_LEAF(entry),
1360  DatumGetBoxP(entry->key),
1361  PG_GETARG_POINT_P(1));
1362  *recheck = false;
1363  break;
1365  {
1366  /*
1367  * The only operator in this group is point <@ box (on_pb), so
1368  * we needn't examine strategy again.
1369  *
1370  * For historical reasons, on_pb uses exact rather than fuzzy
1371  * comparisons. We could use box_overlap when at an internal
1372  * page, but that would lead to possibly visiting child pages
1373  * uselessly, because box_overlap uses fuzzy comparisons.
1374  * Instead we write a non-fuzzy overlap test. The same code
1375  * will also serve for leaf-page tests, since leaf keys have
1376  * high == low.
1377  */
1378  BOX *query,
1379  *key;
1380 
1381  query = PG_GETARG_BOX_P(1);
1382  key = DatumGetBoxP(entry->key);
1383 
1384  result = (key->high.x >= query->low.x &&
1385  key->low.x <= query->high.x &&
1386  key->high.y >= query->low.y &&
1387  key->low.y <= query->high.y);
1388  *recheck = false;
1389  }
1390  break;
1392  {
1393  POLYGON *query = PG_GETARG_POLYGON_P(1);
1394 
1397  PointerGetDatum(entry),
1398  PolygonPGetDatum(query),
1400  0, PointerGetDatum(recheck)));
1401 
1402  if (GIST_LEAF(entry) && result)
1403  {
1404  /*
1405  * We are on leaf page and quick check shows overlapping
1406  * of polygon's bounding box and point
1407  */
1408  BOX *box = DatumGetBoxP(entry->key);
1409 
1410  Assert(box->high.x == box->low.x
1411  && box->high.y == box->low.y);
1414  PolygonPGetDatum(query),
1415  PointPGetDatum(&box->high)));
1416  *recheck = false;
1417  }
1418  }
1419  break;
1421  {
1422  CIRCLE *query = PG_GETARG_CIRCLE_P(1);
1423 
1426  PointerGetDatum(entry),
1427  CirclePGetDatum(query),
1429  0, PointerGetDatum(recheck)));
1430 
1431  if (GIST_LEAF(entry) && result)
1432  {
1433  /*
1434  * We are on leaf page and quick check shows overlapping
1435  * of polygon's bounding box and point
1436  */
1437  BOX *box = DatumGetBoxP(entry->key);
1438 
1439  Assert(box->high.x == box->low.x
1440  && box->high.y == box->low.y);
1443  CirclePGetDatum(query),
1444  PointPGetDatum(&box->high)));
1445  *recheck = false;
1446  }
1447  }
1448  break;
1449  default:
1450  elog(ERROR, "unrecognized strategy number: %d", strategy);
1451  result = false; /* keep compiler quiet */
1452  break;
1453  }
1454 
1455  PG_RETURN_BOOL(result);
1456 }
1457 
1458 Datum
1460 {
1461  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1463  double distance;
1464  StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
1465 
1466  switch (strategyGroup)
1467  {
1469  distance = computeDistance(GIST_LEAF(entry),
1470  DatumGetBoxP(entry->key),
1471  PG_GETARG_POINT_P(1));
1472  break;
1473  default:
1474  elog(ERROR, "unrecognized strategy number: %d", strategy);
1475  distance = 0.0; /* keep compiler quiet */
1476  break;
1477  }
1478 
1479  PG_RETURN_FLOAT8(distance);
1480 }
1481 
1482 /*
1483  * The inexact GiST distance method for geometric types that store bounding
1484  * boxes.
1485  *
1486  * Compute lossy distance from point to index entries. The result is inexact
1487  * because index entries are bounding boxes, not the exact shapes of the
1488  * indexed geometric types. We use distance from point to MBR of index entry.
1489  * This is a lower bound estimate of distance from point to indexed geometric
1490  * type.
1491  */
1492 static double
1494  StrategyNumber strategy, bool *recheck)
1495 {
1496  double distance;
1497  StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;
1498 
1499  /* Bounding box distance is always inexact. */
1500  *recheck = true;
1501 
1502  switch (strategyGroup)
1503  {
1505  distance = computeDistance(false,
1506  DatumGetBoxP(entry->key),
1507  DatumGetPointP(query));
1508  break;
1509  default:
1510  elog(ERROR, "unrecognized strategy number: %d", strategy);
1511  distance = 0.0; /* keep compiler quiet */
1512  }
1513 
1514  return distance;
1515 }
1516 
1517 Datum
1519 {
1520  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1521  Datum query = PG_GETARG_DATUM(1);
1523 
1524  /* Oid subtype = PG_GETARG_OID(3); */
1525  bool *recheck = (bool *) PG_GETARG_POINTER(4);
1526  double distance;
1527 
1528  distance = gist_bbox_distance(entry, query, strategy, recheck);
1529 
1530  PG_RETURN_FLOAT8(distance);
1531 }
1532 
1533 Datum
1535 {
1536  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1537  Datum query = PG_GETARG_DATUM(1);
1539 
1540  /* Oid subtype = PG_GETARG_OID(3); */
1541  bool *recheck = (bool *) PG_GETARG_POINTER(4);
1542  double distance;
1543 
1544  distance = gist_bbox_distance(entry, query, strategy, recheck);
1545 
1546  PG_RETURN_FLOAT8(distance);
1547 }
#define GIST_LEAF(entry)
Definition: gist.h:133
Datum box_right(PG_FUNCTION_ARGS)
Definition: geo_ops.c:564
Relation rel
Definition: gist.h:124
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:305
Datum box_contained(PG_FUNCTION_ARGS)
Definition: geo_ops.c:636
static bool rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy)
Definition: gistproc.c:965
#define GeoStrategyNumberOffset
Definition: gistproc.c:1340
Datum box_same(PG_FUNCTION_ARGS)
Definition: geo_ops.c:504
Definition: geo_decls.h:102
static struct cvec * range(struct vars *v, celt a, celt b, int cases)
Definition: regc_locale.c:403
#define PLACE_LEFT(box, off)
#define BoxStrategyNumberGroup
Definition: gistproc.c:1342
static bool gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
Definition: gistproc.c:870
Datum gist_box_decompress(PG_FUNCTION_ARGS)
Definition: gistproc.c:149
#define PG_GETARG_BOX_P(n)
Definition: geo_decls.h:161
Datum box_left(PG_FUNCTION_ARGS)
Definition: geo_ops.c:538
Datum gist_box_fetch(PG_FUNCTION_ARGS)
Definition: gistproc.c:159
#define RTOldContainsStrategyNumber
Definition: stratnum.h:56
static double size_box(BOX *box)
Definition: gistproc.c:947
#define RTOldContainedByStrategyNumber
Definition: stratnum.h:57
#define RTLeftStrategyNumber
Definition: stratnum.h:44
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:43
static void adjustBox(BOX *b, BOX *addon)
Definition: gistproc.c:89
static int interval_cmp_lower(const void *i1, const void *i2)
Definition: gistproc.c:288
Datum box_overright(PG_FUNCTION_ARGS)
Definition: geo_ops.c:579
#define CircleStrategyNumberGroup
Definition: gistproc.c:1344
#define PointerGetDatum(X)
Definition: postgres.h:564
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:224
static int interval_cmp_upper(const void *i1, const void *i2)
Definition: gistproc.c:305
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:310
#define Min(x, y)
Definition: c.h:798
double radius
Definition: geo_decls.h:127
#define PolygonPGetDatum(X)
Definition: geo_decls.h:166
Datum gist_point_consistent(PG_FUNCTION_ARGS)
Definition: gistproc.c:1347
double y
Definition: geo_decls.h:60
Datum box_overlap(PG_FUNCTION_ARGS)
Definition: geo_ops.c:518
OffsetNumber * spl_left
Definition: gist.h:105
Datum spl_rdatum
Definition: gist.h:112
#define Int16GetDatum(X)
Definition: postgres.h:459
#define RTOverBelowStrategyNumber
Definition: stratnum.h:52
static int common_entry_cmp(const void *i1, const void *i2)
Definition: gistproc.c:459
int32 n
Definition: gist.h:160
Datum gist_box_same(PG_FUNCTION_ARGS)
Definition: gistproc.c:852
Datum gist_box_picksplit(PG_FUNCTION_ARGS)
Definition: gistproc.c:499
struct cursor * cur
Definition: ecpg.c:28
uint16 StrategyNumber
Definition: stratnum.h:22
static double box_penalty(BOX *original, BOX *new)
Definition: gistproc.c:442
#define RTContainedByStrategyNumber
Definition: stratnum.h:51
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:232
Datum poly_contain_pt(PG_FUNCTION_ARGS)
Definition: geo_ops.c:3976
Datum gist_point_fetch(PG_FUNCTION_ARGS)
Definition: gistproc.c:1206
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:74
int spl_nleft
Definition: gist.h:106
#define PLACE_RIGHT(box, off)
#define RTBelowStrategyNumber
Definition: stratnum.h:53
#define PG_GETARG_POLYGON_P(n)
Definition: geo_decls.h:167
Datum gist_box_consistent(PG_FUNCTION_ARGS)
Definition: gistproc.c:59
#define PointStrategyNumberGroup
Definition: gistproc.c:1341
Datum gist_poly_compress(PG_FUNCTION_ARGS)
Definition: gistproc.c:1045
uint16 OffsetNumber
Definition: off.h:24
Page page
Definition: gist.h:125
double delta
Definition: gistproc.c:249
#define Abs(x)
Definition: c.h:804
double x
Definition: geo_decls.h:60
Definition: type.h:90
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:161
#define RTOverAboveStrategyNumber
Definition: stratnum.h:55
#define CirclePGetDatum(X)
Definition: geo_decls.h:172
#define FPgt(A, B)
Definition: geo_decls.h:41
Datum gist_point_distance(PG_FUNCTION_ARGS)
Definition: gistproc.c:1459
#define point_point_distance(p1, p2)
Definition: gistproc.c:1226
#define ERROR
Definition: elog.h:43
#define FALSE
Definition: c.h:218
int spl_nright
Definition: gist.h:111
#define PG_GETARG_POINT_P(n)
Definition: geo_decls.h:139
static void g_box_consider_split(ConsiderSplitContext *context, int dimNum, double rightLower, int minLeftCount, double leftUpper, int maxLeftCount)
Definition: gistproc.c:334
Datum box_contain(PG_FUNCTION_ARGS)
Definition: geo_ops.c:650
static void rt_box_union(BOX *n, BOX *a, BOX *b)
Definition: gistproc.c:43
Datum key
Definition: gist.h:123
Datum box_above(PG_FUNCTION_ARGS)
Definition: geo_ops.c:613
#define DatumGetCircleP(X)
Definition: geo_decls.h:171
#define FirstOffsetNumber
Definition: off.h:27
#define DatumGetBool(X)
Definition: postgres.h:401
#define RTSameStrategyNumber
Definition: stratnum.h:49
static void fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
Definition: gistproc.c:189
#define RTOverRightStrategyNumber
Definition: stratnum.h:47
static double gist_bbox_distance(GISTENTRY *entry, Datum query, StrategyNumber strategy, bool *recheck)
Definition: gistproc.c:1493
static bool gist_point_consistent_internal(StrategyNumber strategy, bool isLeaf, BOX *key, Point *query)
Definition: gistproc.c:1297
double lower
Definition: gistproc.c:280
bool leafkey
Definition: gist.h:127
#define DirectFunctionCall5(func, arg1, arg2, arg3, arg4, arg5)
Definition: fmgr.h:556
#define FPeq(A, B)
Definition: geo_decls.h:37
Point low
Definition: geo_decls.h:104
float float4
Definition: c.h:376
#define RTOverLeftStrategyNumber
Definition: stratnum.h:45
void * palloc0(Size size)
Definition: mcxt.c:923
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:303
uintptr_t Datum
Definition: postgres.h:374
Datum circle_contain_pt(PG_FUNCTION_ARGS)
Definition: geo_ops.c:5005
Datum gist_circle_consistent(PG_FUNCTION_ARGS)
Definition: gistproc.c:1140
Datum gist_box_compress(PG_FUNCTION_ARGS)
Definition: gistproc.c:137
Datum box_overbelow(PG_FUNCTION_ARGS)
Definition: geo_ops.c:602
#define PolygonStrategyNumberGroup
Definition: gistproc.c:1343
#define LIMIT_RATIO
Definition: gistproc.c:32
#define PG_GETARG_CIRCLE_P(n)
Definition: geo_decls.h:173
#define BoxPGetDatum(X)
Definition: geo_decls.h:160
Datum gist_box_penalty(PG_FUNCTION_ARGS)
Definition: gistproc.c:170
BOX boundbox
Definition: geo_decls.h:117
Datum gist_circle_compress(PG_FUNCTION_ARGS)
Definition: gistproc.c:1110
#define Max(x, y)
Definition: c.h:792
Datum box_below(PG_FUNCTION_ARGS)
Definition: geo_ops.c:590
#define RTAboveStrategyNumber
Definition: stratnum.h:54
static double computeDistance(bool isLeaf, BOX *box, Point *point)
Definition: gistproc.c:1231
#define FPlt(A, B)
Definition: geo_decls.h:39
Datum spl_ldatum
Definition: gist.h:107
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:169
#define RTRightStrategyNumber
Definition: stratnum.h:48
#define DatumGetPointP(X)
Definition: geo_decls.h:137
static float non_negative(float val)
Definition: gistproc.c:322
Datum box_overleft(PG_FUNCTION_ARGS)
Definition: geo_ops.c:553
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
OffsetNumber * spl_right
Definition: gist.h:110
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:216
#define RTContainsStrategyNumber
Definition: stratnum.h:50
Datum gist_poly_consistent(PG_FUNCTION_ARGS)
Definition: gistproc.c:1072
#define DatumGetBoxP(X)
Definition: geo_decls.h:159
Datum gist_point_compress(PG_FUNCTION_ARGS)
Definition: gistproc.c:1178
Point high
Definition: geo_decls.h:104
#define PG_GETARG_UINT16(n)
Definition: fmgr.h:228
#define DatumGetPolygonP(X)
Definition: geo_decls.h:164
Point center
Definition: geo_decls.h:126
Datum gist_circle_distance(PG_FUNCTION_ARGS)
Definition: gistproc.c:1518
void * palloc(Size size)
Definition: mcxt.c:894
Datum gist_box_union(PG_FUNCTION_ARGS)
Definition: gistproc.c:107
#define FPge(A, B)
Definition: geo_decls.h:42
int i
#define RTOverlapStrategyNumber
Definition: stratnum.h:46
#define PG_FUNCTION_ARGS
Definition: fmgr.h:150
Datum box_overabove(PG_FUNCTION_ARGS)
Definition: geo_ops.c:625
#define elog
Definition: elog.h:218
#define FPle(A, B)
Definition: geo_decls.h:40
#define qsort(a, b, c, d)
Definition: port.h:438
double upper
Definition: gistproc.c:280
OffsetNumber offset
Definition: gist.h:126
Datum gist_poly_distance(PG_FUNCTION_ARGS)
Definition: gistproc.c:1534
long val
Definition: informix.c:689
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:550
#define PointPGetDatum(X)
Definition: geo_decls.h:138