PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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 <math.h>
21
22#include "access/gist.h"
23#include "access/stratnum.h"
24#include "utils/float.h"
25#include "utils/fmgrprotos.h"
26#include "utils/geo_decls.h"
27#include "utils/sortsupport.h"
28
29
30static bool gist_box_leaf_consistent(BOX *key, BOX *query,
31 StrategyNumber strategy);
32static bool rtree_internal_consistent(BOX *key, BOX *query,
33 StrategyNumber strategy);
34
37static uint32 ieee_float32_to_uint32(float f);
40static bool gist_bbox_zorder_abbrev_abort(int memtupcount, SortSupport ssup);
41
42
43/* Minimum accepted ratio of split */
44#define LIMIT_RATIO 0.3
45
46
47/**************************************************
48 * Box ops
49 **************************************************/
50
51/*
52 * Calculates union of two boxes, a and b. The result is stored in *n.
53 */
54static void
55rt_box_union(BOX *n, const BOX *a, const BOX *b)
56{
57 n->high.x = float8_max(a->high.x, b->high.x);
58 n->high.y = float8_max(a->high.y, b->high.y);
59 n->low.x = float8_min(a->low.x, b->low.x);
60 n->low.y = float8_min(a->low.y, b->low.y);
61}
62
63/*
64 * Size of a BOX for penalty-calculation purposes.
65 * The result can be +Infinity, but not NaN.
66 */
67static float8
69{
70 /*
71 * Check for zero-width cases. Note that we define the size of a zero-
72 * by-infinity box as zero. It's important to special-case this somehow,
73 * as naively multiplying infinity by zero will produce NaN.
74 *
75 * The less-than cases should not happen, but if they do, say "zero".
76 */
77 if (float8_le(box->high.x, box->low.x) ||
78 float8_le(box->high.y, box->low.y))
79 return 0.0;
80
81 /*
82 * We treat NaN as larger than +Infinity, so any distance involving a NaN
83 * and a non-NaN is infinite. Note the previous check eliminated the
84 * possibility that the low fields are NaNs.
85 */
86 if (isnan(box->high.x) || isnan(box->high.y))
87 return get_float8_infinity();
88 return float8_mul(float8_mi(box->high.x, box->low.x),
89 float8_mi(box->high.y, box->low.y));
90}
91
92/*
93 * Return amount by which the union of the two boxes is larger than
94 * the original BOX's area. The result can be +Infinity, but not NaN.
95 */
96static float8
97box_penalty(const BOX *original, const BOX *new)
98{
100
101 rt_box_union(&unionbox, original, new);
102 return float8_mi(size_box(&unionbox), size_box(original));
103}
104
105/*
106 * The GiST Consistent method for boxes
107 *
108 * Should return false if for all data items x below entry,
109 * the predicate x op query must be false, where op is the oper
110 * corresponding to strategy in the pg_amop table.
111 */
112Datum
114{
115 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
116 BOX *query = PG_GETARG_BOX_P(1);
118#ifdef NOT_USED
119 Oid subtype = PG_GETARG_OID(3);
120#endif
121 bool *recheck = (bool *) PG_GETARG_POINTER(4);
122
123 /* All cases served by this function are exact */
124 *recheck = false;
125
126 if (DatumGetBoxP(entry->key) == NULL || query == NULL)
127 PG_RETURN_BOOL(false);
128
129 /*
130 * if entry is not leaf, use rtree_internal_consistent, else use
131 * gist_box_leaf_consistent
132 */
133 if (GIST_LEAF(entry))
135 query,
136 strategy));
137 else
139 query,
140 strategy));
141}
142
143/*
144 * Increase BOX b to include addon.
145 */
146static void
148{
149 if (float8_lt(b->high.x, addon->high.x))
150 b->high.x = addon->high.x;
151 if (float8_gt(b->low.x, addon->low.x))
152 b->low.x = addon->low.x;
153 if (float8_lt(b->high.y, addon->high.y))
154 b->high.y = addon->high.y;
155 if (float8_gt(b->low.y, addon->low.y))
156 b->low.y = addon->low.y;
157}
158
159/*
160 * The GiST Union method for boxes
161 *
162 * returns the minimal bounding box that encloses all the entries in entryvec
163 */
164Datum
166{
168 int *sizep = (int *) PG_GETARG_POINTER(1);
169 int numranges,
170 i;
171 BOX *cur,
172 *pageunion;
173
174 numranges = entryvec->n;
176 cur = DatumGetBoxP(entryvec->vector[0].key);
177 memcpy(pageunion, cur, sizeof(BOX));
178
179 for (i = 1; i < numranges; i++)
180 {
181 cur = DatumGetBoxP(entryvec->vector[i].key);
183 }
184 *sizep = sizeof(BOX);
185
187}
188
189/*
190 * We store boxes as boxes in GiST indexes, so we do not need
191 * compress, decompress, or fetch functions.
192 */
193
194/*
195 * The GiST Penalty method for boxes (also used for points)
196 *
197 * As in the R-tree paper, we use change in area as our penalty metric
198 */
199Datum
211
212/*
213 * Trivial split: half of entries will be placed on one page
214 * and another half - to another
215 */
216static void
218{
220 maxoff;
221 BOX *unionL = NULL,
222 *unionR = NULL;
223 int nbytes;
224
225 maxoff = entryvec->n - 1;
226
227 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
228 v->spl_left = (OffsetNumber *) palloc(nbytes);
229 v->spl_right = (OffsetNumber *) palloc(nbytes);
230 v->spl_nleft = v->spl_nright = 0;
231
232 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
233 {
234 BOX *cur = DatumGetBoxP(entryvec->vector[i].key);
235
236 if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
237 {
238 v->spl_left[v->spl_nleft] = i;
239 if (unionL == NULL)
240 {
242 *unionL = *cur;
243 }
244 else
246
247 v->spl_nleft++;
248 }
249 else
250 {
251 v->spl_right[v->spl_nright] = i;
252 if (unionR == NULL)
253 {
255 *unionR = *cur;
256 }
257 else
259
260 v->spl_nright++;
261 }
262 }
263
266}
267
268/*
269 * Represents information about an entry that can be placed to either group
270 * without affecting overlap over selected axis ("common entry").
271 */
272typedef struct
273{
274 /* Index of entry in the initial array */
275 int index;
276 /* Delta between penalties of entry insertion into different groups */
279
280/*
281 * Context for g_box_consider_split. Contains information about currently
282 * selected split and some general information.
283 */
284typedef struct
285{
286 int entriesCount; /* total number of entries being split */
287 BOX boundingBox; /* minimum bounding box across all entries */
288
289 /* Information about currently selected split follows */
290
291 bool first; /* true if no split was selected yet */
292
293 float8 leftUpper; /* upper bound of left interval */
294 float8 rightLower; /* lower bound of right interval */
295
298 int dim; /* axis of this split */
299 float8 range; /* width of general MBR projection to the
300 * selected axis */
302
303/*
304 * Interval represents projection of box to axis.
305 */
306typedef struct
307{
311
312/*
313 * Interval comparison function by lower bound of the interval;
314 */
315static int
316interval_cmp_lower(const void *i1, const void *i2)
317{
318 float8 lower1 = ((const SplitInterval *) i1)->lower,
319 lower2 = ((const SplitInterval *) i2)->lower;
320
322}
323
324/*
325 * Interval comparison function by upper bound of the interval;
326 */
327static int
328interval_cmp_upper(const void *i1, const void *i2)
329{
330 float8 upper1 = ((const SplitInterval *) i1)->upper,
331 upper2 = ((const SplitInterval *) i2)->upper;
332
334}
335
336/*
337 * Replace negative (or NaN) value with zero.
338 */
339static inline float
341{
342 if (val >= 0.0f)
343 return val;
344 else
345 return 0.0f;
346}
347
348/*
349 * Consider replacement of currently selected split with the better one.
350 */
351static inline void
353 float8 rightLower, int minLeftCount,
354 float8 leftUpper, int maxLeftCount)
355{
356 int leftCount,
358 float4 ratio,
359 overlap;
361
362 /*
363 * Calculate entries distribution ratio assuming most uniform distribution
364 * of common entries.
365 */
366 if (minLeftCount >= (context->entriesCount + 1) / 2)
367 {
369 }
370 else
371 {
372 if (maxLeftCount <= context->entriesCount / 2)
374 else
375 leftCount = context->entriesCount / 2;
376 }
377 rightCount = context->entriesCount - leftCount;
378
379 /*
380 * Ratio of split - quotient between size of lesser group and total
381 * entries count.
382 */
383 ratio = float4_div(Min(leftCount, rightCount), context->entriesCount);
384
385 if (ratio > LIMIT_RATIO)
386 {
387 bool selectthis = false;
388
389 /*
390 * The ratio is acceptable, so compare current split with previously
391 * selected one. Between splits of one dimension we search for minimal
392 * overlap (allowing negative values) and minimal ration (between same
393 * overlaps. We switch dimension if find less overlap (non-negative)
394 * or less range with same overlap.
395 */
396 if (dimNum == 0)
397 range = float8_mi(context->boundingBox.high.x,
398 context->boundingBox.low.x);
399 else
400 range = float8_mi(context->boundingBox.high.y,
401 context->boundingBox.low.y);
402
403 overlap = float8_div(float8_mi(leftUpper, rightLower), range);
404
405 /* If there is no previous selection, select this */
406 if (context->first)
407 selectthis = true;
408 else if (context->dim == dimNum)
409 {
410 /*
411 * Within the same dimension, choose the new split if it has a
412 * smaller overlap, or same overlap but better ratio.
413 */
414 if (overlap < context->overlap ||
415 (overlap == context->overlap && ratio > context->ratio))
416 selectthis = true;
417 }
418 else
419 {
420 /*
421 * Across dimensions, choose the new split if it has a smaller
422 * *non-negative* overlap, or same *non-negative* overlap but
423 * bigger range. This condition differs from the one described in
424 * the article. On the datasets where leaf MBRs don't overlap
425 * themselves, non-overlapping splits (i.e. splits which have zero
426 * *non-negative* overlap) are frequently possible. In this case
427 * splits tends to be along one dimension, because most distant
428 * non-overlapping splits (i.e. having lowest negative overlap)
429 * appears to be in the same dimension as in the previous split.
430 * Therefore MBRs appear to be very prolonged along another
431 * dimension, which leads to bad search performance. Using range
432 * as the second split criteria makes MBRs more quadratic. Using
433 * *non-negative* overlap instead of overlap as the first split
434 * criteria gives to range criteria a chance to matter, because
435 * non-overlapping splits are equivalent in this criteria.
436 */
437 if (non_negative(overlap) < non_negative(context->overlap) ||
438 (range > context->range &&
439 non_negative(overlap) <= non_negative(context->overlap)))
440 selectthis = true;
441 }
442
443 if (selectthis)
444 {
445 /* save information about selected split */
446 context->first = false;
447 context->ratio = ratio;
448 context->range = range;
449 context->overlap = overlap;
450 context->rightLower = rightLower;
451 context->leftUpper = leftUpper;
452 context->dim = dimNum;
453 }
454 }
455}
456
457/*
458 * Compare common entries by their deltas.
459 */
460static int
461common_entry_cmp(const void *i1, const void *i2)
462{
463 float8 delta1 = ((const CommonEntry *) i1)->delta,
464 delta2 = ((const CommonEntry *) i2)->delta;
465
467}
468
469/*
470 * --------------------------------------------------------------------------
471 * Double sorting split algorithm. This is used for both boxes and points.
472 *
473 * The algorithm finds split of boxes by considering splits along each axis.
474 * Each entry is first projected as an interval on the X-axis, and different
475 * ways to split the intervals into two groups are considered, trying to
476 * minimize the overlap of the groups. Then the same is repeated for the
477 * Y-axis, and the overall best split is chosen. The quality of a split is
478 * determined by overlap along that axis and some other criteria (see
479 * g_box_consider_split).
480 *
481 * After that, all the entries are divided into three groups:
482 *
483 * 1) Entries which should be placed to the left group
484 * 2) Entries which should be placed to the right group
485 * 3) "Common entries" which can be placed to any of groups without affecting
486 * of overlap along selected axis.
487 *
488 * The common entries are distributed by minimizing penalty.
489 *
490 * For details see:
491 * "A new double sorting-based node splitting algorithm for R-tree", A. Korotkov
492 * http://syrcose.ispras.ru/2011/files/SYRCoSE2011_Proceedings.pdf#page=36
493 * --------------------------------------------------------------------------
494 */
495Datum
497{
501 maxoff;
502 ConsiderSplitContext context;
503 BOX *box,
504 *leftBox,
505 *rightBox;
506 int dim,
511 int nentries;
512
513 memset(&context, 0, sizeof(ConsiderSplitContext));
514
515 maxoff = entryvec->n - 1;
516 nentries = context.entriesCount = maxoff - FirstOffsetNumber + 1;
517
518 /* Allocate arrays for intervals along axes */
519 intervalsLower = (SplitInterval *) palloc(nentries * sizeof(SplitInterval));
520 intervalsUpper = (SplitInterval *) palloc(nentries * sizeof(SplitInterval));
521
522 /*
523 * Calculate the overall minimum bounding box over all the entries.
524 */
525 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
526 {
527 box = DatumGetBoxP(entryvec->vector[i].key);
528 if (i == FirstOffsetNumber)
529 context.boundingBox = *box;
530 else
531 adjustBox(&context.boundingBox, box);
532 }
533
534 /*
535 * Iterate over axes for optimal split searching.
536 */
537 context.first = true; /* nothing selected yet */
538 for (dim = 0; dim < 2; dim++)
539 {
540 float8 leftUpper,
541 rightLower;
542 int i1,
543 i2;
544
545 /* Project each entry as an interval on the selected axis. */
546 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
547 {
548 box = DatumGetBoxP(entryvec->vector[i].key);
549 if (dim == 0)
550 {
551 intervalsLower[i - FirstOffsetNumber].lower = box->low.x;
552 intervalsLower[i - FirstOffsetNumber].upper = box->high.x;
553 }
554 else
555 {
556 intervalsLower[i - FirstOffsetNumber].lower = box->low.y;
557 intervalsLower[i - FirstOffsetNumber].upper = box->high.y;
558 }
559 }
560
561 /*
562 * Make two arrays of intervals: one sorted by lower bound and another
563 * sorted by upper bound.
564 */
566 sizeof(SplitInterval) * nentries);
567 qsort(intervalsLower, nentries, sizeof(SplitInterval),
569 qsort(intervalsUpper, nentries, sizeof(SplitInterval),
571
572 /*----
573 * The goal is to form a left and right interval, so that every entry
574 * interval is contained by either left or right interval (or both).
575 *
576 * For example, with the intervals (0,1), (1,3), (2,3), (2,4):
577 *
578 * 0 1 2 3 4
579 * +-+
580 * +---+
581 * +-+
582 * +---+
583 *
584 * The left and right intervals are of the form (0,a) and (b,4).
585 * We first consider splits where b is the lower bound of an entry.
586 * We iterate through all entries, and for each b, calculate the
587 * smallest possible a. Then we consider splits where a is the
588 * upper bound of an entry, and for each a, calculate the greatest
589 * possible b.
590 *
591 * In the above example, the first loop would consider splits:
592 * b=0: (0,1)-(0,4)
593 * b=1: (0,1)-(1,4)
594 * b=2: (0,3)-(2,4)
595 *
596 * And the second loop:
597 * a=1: (0,1)-(1,4)
598 * a=3: (0,3)-(2,4)
599 * a=4: (0,4)-(2,4)
600 */
601
602 /*
603 * Iterate over lower bound of right group, finding smallest possible
604 * upper bound of left group.
605 */
606 i1 = 0;
607 i2 = 0;
608 rightLower = intervalsLower[i1].lower;
609 leftUpper = intervalsUpper[i2].lower;
610 while (true)
611 {
612 /*
613 * Find next lower bound of right group.
614 */
615 while (i1 < nentries &&
616 float8_eq(rightLower, intervalsLower[i1].lower))
617 {
618 if (float8_lt(leftUpper, intervalsLower[i1].upper))
619 leftUpper = intervalsLower[i1].upper;
620 i1++;
621 }
622 if (i1 >= nentries)
623 break;
624 rightLower = intervalsLower[i1].lower;
625
626 /*
627 * Find count of intervals which anyway should be placed to the
628 * left group.
629 */
630 while (i2 < nentries &&
631 float8_le(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 && float8_eq(leftUpper, intervalsUpper[i2].upper))
654 {
655 if (float8_gt(rightLower, intervalsUpper[i2].lower))
656 rightLower = intervalsUpper[i2].lower;
657 i2--;
658 }
659 if (i2 < 0)
660 break;
661 leftUpper = intervalsUpper[i2].upper;
662
663 /*
664 * Find count of intervals which anyway should be placed to the
665 * right group.
666 */
667 while (i1 >= 0 && float8_ge(intervalsLower[i1].lower, rightLower))
668 i1--;
669
670 /*
671 * Consider found split.
672 */
673 g_box_consider_split(&context, dim,
674 rightLower, i1 + 1, leftUpper, i2 + 1);
675 }
676 }
677
678 /*
679 * If we failed to find any acceptable splits, use trivial split.
680 */
681 if (context.first)
682 {
685 }
686
687 /*
688 * Ok, we have now selected the split across one axis.
689 *
690 * While considering the splits, we already determined that there will be
691 * enough entries in both groups to reach the desired ratio, but we did
692 * not memorize which entries go to which group. So determine that now.
693 */
694
695 /* Allocate vectors for results */
696 v->spl_left = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber));
697 v->spl_right = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber));
698 v->spl_nleft = 0;
699 v->spl_nright = 0;
700
701 /* Allocate bounding boxes of left and right groups */
704
705 /*
706 * Allocate an array for "common entries" - entries which can be placed to
707 * either group without affecting overlap along selected axis.
708 */
710 commonEntries = (CommonEntry *) palloc(nentries * sizeof(CommonEntry));
711
712 /* Helper macros to place an entry in the left or right group */
713#define PLACE_LEFT(box, off) \
714 do { \
715 if (v->spl_nleft > 0) \
716 adjustBox(leftBox, box); \
717 else \
718 *leftBox = *(box); \
719 v->spl_left[v->spl_nleft++] = off; \
720 } while(0)
721
722#define PLACE_RIGHT(box, off) \
723 do { \
724 if (v->spl_nright > 0) \
725 adjustBox(rightBox, box); \
726 else \
727 *rightBox = *(box); \
728 v->spl_right[v->spl_nright++] = off; \
729 } while(0)
730
731 /*
732 * Distribute entries which can be distributed unambiguously, and collect
733 * common entries.
734 */
735 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
736 {
738 upper;
739
740 /*
741 * Get upper and lower bounds along selected axis.
742 */
743 box = DatumGetBoxP(entryvec->vector[i].key);
744 if (context.dim == 0)
745 {
746 lower = box->low.x;
747 upper = box->high.x;
748 }
749 else
750 {
751 lower = box->low.y;
752 upper = box->high.y;
753 }
754
755 if (float8_le(upper, context.leftUpper))
756 {
757 /* Fits to the left group */
758 if (float8_ge(lower, context.rightLower))
759 {
760 /* Fits also to the right group, so "common entry" */
762 }
763 else
764 {
765 /* Doesn't fit to the right group, so join to the left group */
766 PLACE_LEFT(box, i);
767 }
768 }
769 else
770 {
771 /*
772 * Each entry should fit on either left or right group. Since this
773 * entry didn't fit on the left group, it better fit in the right
774 * group.
775 */
776 Assert(float8_ge(lower, context.rightLower));
777
778 /* Doesn't fit to the left group, so join to the right group */
779 PLACE_RIGHT(box, i);
780 }
781 }
782
783 /*
784 * Distribute "common entries", if any.
785 */
786 if (commonEntriesCount > 0)
787 {
788 /*
789 * Calculate minimum number of entries that must be placed in both
790 * groups, to reach LIMIT_RATIO.
791 */
792 int m = ceil(LIMIT_RATIO * nentries);
793
794 /*
795 * Calculate delta between penalties of join "common entries" to
796 * different groups.
797 */
798 for (i = 0; i < commonEntriesCount; i++)
799 {
800 box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
803 }
804
805 /*
806 * Sort "common entries" by calculated deltas in order to distribute
807 * the most ambiguous entries first.
808 */
810
811 /*
812 * Distribute "common entries" between groups.
813 */
814 for (i = 0; i < commonEntriesCount; i++)
815 {
816 box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
817
818 /*
819 * Check if we have to place this entry in either group to achieve
820 * LIMIT_RATIO.
821 */
822 if (v->spl_nleft + (commonEntriesCount - i) <= m)
824 else if (v->spl_nright + (commonEntriesCount - i) <= m)
826 else
827 {
828 /* Otherwise select the group by minimal penalty */
831 else
833 }
834 }
835 }
836
840}
841
842/*
843 * Equality method
844 *
845 * This is used for boxes, points, circles, and polygons, all of which store
846 * boxes as GiST index entries.
847 *
848 * Returns true only when boxes are exactly the same. We can't use fuzzy
849 * comparisons here without breaking index consistency; therefore, this isn't
850 * equivalent to box_same().
851 */
852Datum
854{
855 BOX *b1 = PG_GETARG_BOX_P(0);
856 BOX *b2 = PG_GETARG_BOX_P(1);
857 bool *result = (bool *) PG_GETARG_POINTER(2);
858
859 if (b1 && b2)
860 *result = (float8_eq(b1->low.x, b2->low.x) &&
861 float8_eq(b1->low.y, b2->low.y) &&
862 float8_eq(b1->high.x, b2->high.x) &&
863 float8_eq(b1->high.y, b2->high.y));
864 else
865 *result = (b1 == NULL && b2 == NULL);
866 PG_RETURN_POINTER(result);
867}
868
869/*
870 * Leaf-level consistency for boxes: just apply the query operator
871 */
872static bool
874{
875 bool retval;
876
877 switch (strategy)
878 {
881 PointerGetDatum(key),
882 PointerGetDatum(query)));
883 break;
886 PointerGetDatum(key),
887 PointerGetDatum(query)));
888 break;
891 PointerGetDatum(key),
892 PointerGetDatum(query)));
893 break;
896 PointerGetDatum(key),
897 PointerGetDatum(query)));
898 break;
901 PointerGetDatum(key),
902 PointerGetDatum(query)));
903 break;
906 PointerGetDatum(key),
907 PointerGetDatum(query)));
908 break;
911 PointerGetDatum(key),
912 PointerGetDatum(query)));
913 break;
916 PointerGetDatum(key),
917 PointerGetDatum(query)));
918 break;
921 PointerGetDatum(key),
922 PointerGetDatum(query)));
923 break;
926 PointerGetDatum(key),
927 PointerGetDatum(query)));
928 break;
931 PointerGetDatum(key),
932 PointerGetDatum(query)));
933 break;
936 PointerGetDatum(key),
937 PointerGetDatum(query)));
938 break;
939 default:
940 elog(ERROR, "unrecognized strategy number: %d", strategy);
941 retval = false; /* keep compiler quiet */
942 break;
943 }
944 return retval;
945}
946
947/*****************************************
948 * Common rtree functions (for boxes, polygons, and circles)
949 *****************************************/
950
951/*
952 * Internal-page consistency for all these types
953 *
954 * We can use the same function since all types use bounding boxes as the
955 * internal-page representation.
956 */
957static bool
959{
960 bool retval;
961
962 switch (strategy)
963 {
966 PointerGetDatum(key),
967 PointerGetDatum(query)));
968 break;
971 PointerGetDatum(key),
972 PointerGetDatum(query)));
973 break;
976 PointerGetDatum(key),
977 PointerGetDatum(query)));
978 break;
981 PointerGetDatum(key),
982 PointerGetDatum(query)));
983 break;
986 PointerGetDatum(key),
987 PointerGetDatum(query)));
988 break;
992 PointerGetDatum(key),
993 PointerGetDatum(query)));
994 break;
997 PointerGetDatum(key),
998 PointerGetDatum(query)));
999 break;
1002 PointerGetDatum(key),
1003 PointerGetDatum(query)));
1004 break;
1007 PointerGetDatum(key),
1008 PointerGetDatum(query)));
1009 break;
1012 PointerGetDatum(key),
1013 PointerGetDatum(query)));
1014 break;
1017 PointerGetDatum(key),
1018 PointerGetDatum(query)));
1019 break;
1020 default:
1021 elog(ERROR, "unrecognized strategy number: %d", strategy);
1022 retval = false; /* keep compiler quiet */
1023 break;
1024 }
1025 return retval;
1026}
1027
1028/**************************************************
1029 * Polygon ops
1030 **************************************************/
1031
1032/*
1033 * GiST compress for polygons: represent a polygon by its bounding box
1034 */
1035Datum
1037{
1038 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1039 GISTENTRY *retval;
1040
1041 if (entry->leafkey)
1042 {
1043 POLYGON *in = DatumGetPolygonP(entry->key);
1044 BOX *r;
1045
1046 r = palloc_object(BOX);
1047 memcpy(r, &(in->boundbox), sizeof(BOX));
1048
1049 retval = palloc_object(GISTENTRY);
1050 gistentryinit(*retval, PointerGetDatum(r),
1051 entry->rel, entry->page,
1052 entry->offset, false);
1053 }
1054 else
1055 retval = entry;
1056 PG_RETURN_POINTER(retval);
1057}
1058
1059/*
1060 * The GiST Consistent method for polygons
1061 */
1062Datum
1064{
1065 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1066 POLYGON *query = PG_GETARG_POLYGON_P(1);
1068#ifdef NOT_USED
1069 Oid subtype = PG_GETARG_OID(3);
1070#endif
1071 bool *recheck = (bool *) PG_GETARG_POINTER(4);
1072 bool result;
1073
1074 /* All cases served by this function are inexact */
1075 *recheck = true;
1076
1077 if (DatumGetBoxP(entry->key) == NULL || query == NULL)
1078 PG_RETURN_BOOL(false);
1079
1080 /*
1081 * Since the operators require recheck anyway, we can just use
1082 * rtree_internal_consistent even at leaf nodes. (This works in part
1083 * because the index entries are bounding boxes not polygons.)
1084 */
1086 &(query->boundbox), strategy);
1087
1088 /* Avoid memory leak if supplied poly is toasted */
1089 PG_FREE_IF_COPY(query, 1);
1090
1091 PG_RETURN_BOOL(result);
1092}
1093
1094/**************************************************
1095 * Circle ops
1096 **************************************************/
1097
1098/*
1099 * GiST compress for circles: represent a circle by its bounding box
1100 */
1101Datum
1103{
1104 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1105 GISTENTRY *retval;
1106
1107 if (entry->leafkey)
1108 {
1109 CIRCLE *in = DatumGetCircleP(entry->key);
1110 BOX *r;
1111
1112 r = palloc_object(BOX);
1113 r->high.x = float8_pl(in->center.x, in->radius);
1114 r->low.x = float8_mi(in->center.x, in->radius);
1115 r->high.y = float8_pl(in->center.y, in->radius);
1116 r->low.y = float8_mi(in->center.y, in->radius);
1117
1118 retval = palloc_object(GISTENTRY);
1119 gistentryinit(*retval, PointerGetDatum(r),
1120 entry->rel, entry->page,
1121 entry->offset, false);
1122 }
1123 else
1124 retval = entry;
1125 PG_RETURN_POINTER(retval);
1126}
1127
1128/*
1129 * The GiST Consistent method for circles
1130 */
1131Datum
1133{
1134 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1135 CIRCLE *query = PG_GETARG_CIRCLE_P(1);
1137#ifdef NOT_USED
1138 Oid subtype = PG_GETARG_OID(3);
1139#endif
1140 bool *recheck = (bool *) PG_GETARG_POINTER(4);
1141 BOX bbox;
1142 bool result;
1143
1144 /* All cases served by this function are inexact */
1145 *recheck = true;
1146
1147 if (DatumGetBoxP(entry->key) == NULL || query == NULL)
1148 PG_RETURN_BOOL(false);
1149
1150 /*
1151 * Since the operators require recheck anyway, we can just use
1152 * rtree_internal_consistent even at leaf nodes. (This works in part
1153 * because the index entries are bounding boxes not circles.)
1154 */
1155 bbox.high.x = float8_pl(query->center.x, query->radius);
1156 bbox.low.x = float8_mi(query->center.x, query->radius);
1157 bbox.high.y = float8_pl(query->center.y, query->radius);
1158 bbox.low.y = float8_mi(query->center.y, query->radius);
1159
1161 &bbox, strategy);
1162
1163 PG_RETURN_BOOL(result);
1164}
1165
1166/**************************************************
1167 * Point ops
1168 **************************************************/
1169
1170Datum
1172{
1173 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1174
1175 if (entry->leafkey) /* Point, actually */
1176 {
1178 Point *point = DatumGetPointP(entry->key);
1180
1181 box->high = box->low = *point;
1182
1183 gistentryinit(*retval, BoxPGetDatum(box),
1184 entry->rel, entry->page, entry->offset, false);
1185
1186 PG_RETURN_POINTER(retval);
1187 }
1188
1189 PG_RETURN_POINTER(entry);
1190}
1191
1192/*
1193 * GiST Fetch method for point
1194 *
1195 * Get point coordinates from its bounding box coordinates and form new
1196 * gistentry.
1197 */
1198Datum
1200{
1201 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1202 BOX *in = DatumGetBoxP(entry->key);
1203 Point *r;
1204 GISTENTRY *retval;
1205
1206 retval = palloc_object(GISTENTRY);
1207
1208 r = palloc_object(Point);
1209 r->x = in->high.x;
1210 r->y = in->high.y;
1211 gistentryinit(*retval, PointerGetDatum(r),
1212 entry->rel, entry->page,
1213 entry->offset, false);
1214
1215 PG_RETURN_POINTER(retval);
1216}
1217
1218
1219#define point_point_distance(p1,p2) \
1220 DatumGetFloat8(DirectFunctionCall2(point_distance, \
1221 PointPGetDatum(p1), PointPGetDatum(p2)))
1222
1223static float8
1225{
1226 float8 result = 0.0;
1227
1228 if (isLeaf)
1229 {
1230 /* simple point to point distance */
1231 result = point_point_distance(point, &box->low);
1232 }
1233 else if (point->x <= box->high.x && point->x >= box->low.x &&
1234 point->y <= box->high.y && point->y >= box->low.y)
1235 {
1236 /* point inside the box */
1237 result = 0.0;
1238 }
1239 else if (point->x <= box->high.x && point->x >= box->low.x)
1240 {
1241 /* point is over or below box */
1242 Assert(box->low.y <= box->high.y);
1243 if (point->y > box->high.y)
1244 result = float8_mi(point->y, box->high.y);
1245 else if (point->y < box->low.y)
1246 result = float8_mi(box->low.y, point->y);
1247 else
1248 elog(ERROR, "inconsistent point values");
1249 }
1250 else if (point->y <= box->high.y && point->y >= box->low.y)
1251 {
1252 /* point is to left or right of box */
1253 Assert(box->low.x <= box->high.x);
1254 if (point->x > box->high.x)
1255 result = float8_mi(point->x, box->high.x);
1256 else if (point->x < box->low.x)
1257 result = float8_mi(box->low.x, point->x);
1258 else
1259 elog(ERROR, "inconsistent point values");
1260 }
1261 else
1262 {
1263 /* closest point will be a vertex */
1264 Point p;
1266
1267 result = point_point_distance(point, &box->low);
1268
1270 if (result > subresult)
1271 result = subresult;
1272
1273 p.x = box->low.x;
1274 p.y = box->high.y;
1276 if (result > subresult)
1277 result = subresult;
1278
1279 p.x = box->high.x;
1280 p.y = box->low.y;
1282 if (result > subresult)
1283 result = subresult;
1284 }
1285
1286 return result;
1287}
1288
1289static bool
1291 bool isLeaf, BOX *key, Point *query)
1292{
1293 bool result = false;
1294
1295 switch (strategy)
1296 {
1298 result = FPlt(key->low.x, query->x);
1299 break;
1301 result = FPgt(key->high.x, query->x);
1302 break;
1304 result = FPgt(key->high.y, query->y);
1305 break;
1307 result = FPlt(key->low.y, query->y);
1308 break;
1310 if (isLeaf)
1311 {
1312 /* key.high must equal key.low, so we can disregard it */
1313 result = (FPeq(key->low.x, query->x) &&
1314 FPeq(key->low.y, query->y));
1315 }
1316 else
1317 {
1318 result = (FPle(query->x, key->high.x) &&
1319 FPge(query->x, key->low.x) &&
1320 FPle(query->y, key->high.y) &&
1321 FPge(query->y, key->low.y));
1322 }
1323 break;
1324 default:
1325 elog(ERROR, "unrecognized strategy number: %d", strategy);
1326 result = false; /* keep compiler quiet */
1327 break;
1328 }
1329
1330 return result;
1331}
1332
1333#define GeoStrategyNumberOffset 20
1334#define PointStrategyNumberGroup 0
1335#define BoxStrategyNumberGroup 1
1336#define PolygonStrategyNumberGroup 2
1337#define CircleStrategyNumberGroup 3
1338
1339Datum
1341{
1342 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1344 bool *recheck = (bool *) PG_GETARG_POINTER(4);
1345 bool result;
1347
1348 /*
1349 * We have to remap these strategy numbers to get this klugy
1350 * classification logic to work.
1351 */
1352 if (strategy == RTOldBelowStrategyNumber)
1353 strategy = RTBelowStrategyNumber;
1354 else if (strategy == RTOldAboveStrategyNumber)
1355 strategy = RTAboveStrategyNumber;
1356
1358 switch (strategyGroup)
1359 {
1362 GIST_LEAF(entry),
1363 DatumGetBoxP(entry->key),
1365 *recheck = false;
1366 break;
1368 {
1369 /*
1370 * The only operator in this group is point <@ box (on_pb), so
1371 * we needn't examine strategy again.
1372 *
1373 * For historical reasons, on_pb uses exact rather than fuzzy
1374 * comparisons. We could use box_overlap when at an internal
1375 * page, but that would lead to possibly visiting child pages
1376 * uselessly, because box_overlap uses fuzzy comparisons.
1377 * Instead we write a non-fuzzy overlap test. The same code
1378 * will also serve for leaf-page tests, since leaf keys have
1379 * high == low.
1380 */
1381 BOX *query,
1382 *key;
1383
1384 query = PG_GETARG_BOX_P(1);
1385 key = DatumGetBoxP(entry->key);
1386
1387 result = (key->high.x >= query->low.x &&
1388 key->low.x <= query->high.x &&
1389 key->high.y >= query->low.y &&
1390 key->low.y <= query->high.y);
1391 *recheck = false;
1392 }
1393 break;
1395 {
1396 POLYGON *query = PG_GETARG_POLYGON_P(1);
1397
1399 PointerGetDatum(entry),
1400 PolygonPGetDatum(query),
1402 0, PointerGetDatum(recheck)));
1403
1404 if (GIST_LEAF(entry) && result)
1405 {
1406 /*
1407 * We are on leaf page and quick check shows overlapping
1408 * of polygon's bounding box and point
1409 */
1410 BOX *box = DatumGetBoxP(entry->key);
1411
1412 Assert(box->high.x == box->low.x
1413 && box->high.y == box->low.y);
1415 PolygonPGetDatum(query),
1416 PointPGetDatum(&box->high)));
1417 *recheck = false;
1418 }
1419 }
1420 break;
1422 {
1423 CIRCLE *query = PG_GETARG_CIRCLE_P(1);
1424
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);
1442 CirclePGetDatum(query),
1443 PointPGetDatum(&box->high)));
1444 *recheck = false;
1445 }
1446 }
1447 break;
1448 default:
1449 elog(ERROR, "unrecognized strategy number: %d", strategy);
1450 result = false; /* keep compiler quiet */
1451 break;
1452 }
1453
1454 PG_RETURN_BOOL(result);
1455}
1456
1457Datum
1459{
1460 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1462 float8 distance;
1464
1465 switch (strategyGroup)
1466 {
1468 distance = computeDistance(GIST_LEAF(entry),
1469 DatumGetBoxP(entry->key),
1471 break;
1472 default:
1473 elog(ERROR, "unrecognized strategy number: %d", strategy);
1474 distance = 0.0; /* keep compiler quiet */
1475 break;
1476 }
1477
1478 PG_RETURN_FLOAT8(distance);
1479}
1480
1481static float8
1483{
1484 float8 distance;
1486
1487 switch (strategyGroup)
1488 {
1490 distance = computeDistance(false,
1491 DatumGetBoxP(entry->key),
1492 DatumGetPointP(query));
1493 break;
1494 default:
1495 elog(ERROR, "unrecognized strategy number: %d", strategy);
1496 distance = 0.0; /* keep compiler quiet */
1497 }
1498
1499 return distance;
1500}
1501
1502Datum
1504{
1505 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1506 Datum query = PG_GETARG_DATUM(1);
1508#ifdef NOT_USED
1509 Oid subtype = PG_GETARG_OID(3);
1510 bool *recheck = (bool *) PG_GETARG_POINTER(4);
1511#endif
1512 float8 distance;
1513
1514 distance = gist_bbox_distance(entry, query, strategy);
1515
1516 PG_RETURN_FLOAT8(distance);
1517}
1518
1519/*
1520 * The inexact GiST distance methods for geometric types that store bounding
1521 * boxes.
1522 *
1523 * Compute lossy distance from point to index entries. The result is inexact
1524 * because index entries are bounding boxes, not the exact shapes of the
1525 * indexed geometric types. We use distance from point to MBR of index entry.
1526 * This is a lower bound estimate of distance from point to indexed geometric
1527 * type.
1528 */
1529Datum
1531{
1532 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1533 Datum query = PG_GETARG_DATUM(1);
1535#ifdef NOT_USED
1536 Oid subtype = PG_GETARG_OID(3);
1537#endif
1538 bool *recheck = (bool *) PG_GETARG_POINTER(4);
1539 float8 distance;
1540
1541 distance = gist_bbox_distance(entry, query, strategy);
1542 *recheck = true;
1543
1544 PG_RETURN_FLOAT8(distance);
1545}
1546
1547Datum
1549{
1550 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1551 Datum query = PG_GETARG_DATUM(1);
1553#ifdef NOT_USED
1554 Oid subtype = PG_GETARG_OID(3);
1555#endif
1556 bool *recheck = (bool *) PG_GETARG_POINTER(4);
1557 float8 distance;
1558
1559 distance = gist_bbox_distance(entry, query, strategy);
1560 *recheck = true;
1561
1562 PG_RETURN_FLOAT8(distance);
1563}
1564
1565/*
1566 * Z-order routines for fast index build
1567 */
1568
1569/*
1570 * Compute Z-value of a point
1571 *
1572 * Z-order (also known as Morton Code) maps a two-dimensional point to a
1573 * single integer, in a way that preserves locality. Points that are close in
1574 * the two-dimensional space are mapped to integer that are not far from each
1575 * other. We do that by interleaving the bits in the X and Y components.
1576 *
1577 * Morton Code is normally defined only for integers, but the X and Y values
1578 * of a point are floating point. We expect floats to be in IEEE format.
1579 */
1580static uint64
1582{
1585
1586 /* Interleave the bits */
1587 return part_bits32_by2(ix) | (part_bits32_by2(iy) << 1);
1588}
1589
1590/* Interleave 32 bits with zeroes */
1591static uint64
1593{
1594 uint64 n = x;
1595
1596 n = (n | (n << 16)) & UINT64CONST(0x0000FFFF0000FFFF);
1597 n = (n | (n << 8)) & UINT64CONST(0x00FF00FF00FF00FF);
1598 n = (n | (n << 4)) & UINT64CONST(0x0F0F0F0F0F0F0F0F);
1599 n = (n | (n << 2)) & UINT64CONST(0x3333333333333333);
1600 n = (n | (n << 1)) & UINT64CONST(0x5555555555555555);
1601
1602 return n;
1603}
1604
1605/*
1606 * Convert a 32-bit IEEE float to uint32 in a way that preserves the ordering
1607 */
1608static uint32
1610{
1611 /*----
1612 *
1613 * IEEE 754 floating point format
1614 * ------------------------------
1615 *
1616 * IEEE 754 floating point numbers have this format:
1617 *
1618 * exponent (8 bits)
1619 * |
1620 * s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm
1621 * | |
1622 * sign mantissa (23 bits)
1623 *
1624 * Infinity has all bits in the exponent set and the mantissa is all
1625 * zeros. Negative infinity is the same but with the sign bit set.
1626 *
1627 * NaNs are represented with all bits in the exponent set, and the least
1628 * significant bit in the mantissa also set. The rest of the mantissa bits
1629 * can be used to distinguish different kinds of NaNs.
1630 *
1631 * The IEEE format has the nice property that when you take the bit
1632 * representation and interpret it as an integer, the order is preserved,
1633 * except for the sign. That holds for the +-Infinity values too.
1634 *
1635 * Mapping to uint32
1636 * -----------------
1637 *
1638 * In order to have a smooth transition from negative to positive numbers,
1639 * we map floats to unsigned integers like this:
1640 *
1641 * x < 0 to range 0-7FFFFFFF
1642 * x = 0 to value 8000000 (both positive and negative zero)
1643 * x > 0 to range 8000001-FFFFFFFF
1644 *
1645 * We don't care to distinguish different kind of NaNs, so they are all
1646 * mapped to the same arbitrary value, FFFFFFFF. Because of the IEEE bit
1647 * representation of NaNs, there aren't any non-NaN values that would be
1648 * mapped to FFFFFFFF. In fact, there is a range of unused values on both
1649 * ends of the uint32 space.
1650 */
1651 if (isnan(f))
1652 return 0xFFFFFFFF;
1653 else
1654 {
1655 union
1656 {
1657 float f;
1658 uint32 i;
1659 } u;
1660
1661 u.f = f;
1662
1663 /* Check the sign bit */
1664 if ((u.i & 0x80000000) != 0)
1665 {
1666 /*
1667 * Map the negative value to range 0-7FFFFFFF. This flips the sign
1668 * bit to 0 in the same instruction.
1669 */
1670 Assert(f <= 0); /* can be -0 */
1671 u.i ^= 0xFFFFFFFF;
1672 }
1673 else
1674 {
1675 /* Map the positive value (or 0) to range 80000000-FFFFFFFF */
1676 u.i |= 0x80000000;
1677 }
1678
1679 return u.i;
1680 }
1681}
1682
1683/*
1684 * Compare the Z-order of points
1685 */
1686static int
1688{
1689 Point *p1 = &(DatumGetBoxP(a)->low);
1690 Point *p2 = &(DatumGetBoxP(b)->low);
1691 uint64 z1;
1692 uint64 z2;
1693
1694 /*
1695 * Do a quick check for equality first. It's not clear if this is worth it
1696 * in general, but certainly is when used as tie-breaker with abbreviated
1697 * keys,
1698 */
1699 if (p1->x == p2->x && p1->y == p2->y)
1700 return 0;
1701
1702 z1 = point_zorder_internal(p1->x, p1->y);
1703 z2 = point_zorder_internal(p2->x, p2->y);
1704 if (z1 > z2)
1705 return 1;
1706 else if (z1 < z2)
1707 return -1;
1708 else
1709 return 0;
1710}
1711
1712/*
1713 * Abbreviated version of Z-order comparison
1714 *
1715 * The abbreviated format is a Z-order value computed from the two 32-bit
1716 * floats. Now that sizeof(Datum) is always 8, the 64-bit Z-order value
1717 * always fits fully in the abbreviated Datum.
1718 */
1719static Datum
1721{
1722 Point *p = &(DatumGetBoxP(original)->low);
1723 uint64 z;
1724
1725 z = point_zorder_internal(p->x, p->y);
1726
1727 return UInt64GetDatum(z);
1728}
1729
1730/*
1731 * We never consider aborting the abbreviation.
1732 *
1733 * On 64-bit systems, the abbreviation is not lossy so it is always
1734 * worthwhile. (Perhaps it's not on 32-bit systems, but we don't bother
1735 * with logic to decide.)
1736 */
1737static bool
1739{
1740 return false;
1741}
1742
1743/*
1744 * Sort support routine for fast GiST index build by sorting.
1745 */
1746Datum
#define Min(x, y)
Definition c.h:997
#define Assert(condition)
Definition c.h:873
double float8
Definition c.h:644
uint64_t uint64
Definition c.h:547
uint32_t uint32
Definition c.h:546
float float4
Definition c.h:643
#define UINT64CONST(x)
Definition c.h:561
struct cursor * cur
Definition ecpg.c:29
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define palloc_object(type)
Definition fe_memutils.h:74
#define palloc0_object(type)
Definition fe_memutils.h:75
int float8_cmp_internal(float8 a, float8 b)
Definition float.c:910
static float8 float8_min(const float8 val1, const float8 val2)
Definition float.h:295
static float8 float8_mul(const float8 val1, const float8 val2)
Definition float.h:163
static float4 float4_div(const float4 val1, const float4 val2)
Definition float.h:177
static float8 float8_pl(const float8 val1, const float8 val2)
Definition float.h:113
static float8 float8_mi(const float8 val1, const float8 val2)
Definition float.h:137
static float8 get_float8_infinity(void)
Definition float.h:65
static bool float8_ge(const float8 val1, const float8 val2)
Definition float.h:283
static float8 float8_max(const float8 val1, const float8 val2)
Definition float.h:307
static bool float8_le(const float8 val1, const float8 val2)
Definition float.h:259
static bool float8_eq(const float8 val1, const float8 val2)
Definition float.h:223
static float8 float8_div(const float8 val1, const float8 val2)
Definition float.h:193
static bool float8_lt(const float8 val1, const float8 val2)
Definition float.h:247
static bool float8_gt(const float8 val1, const float8 val2)
Definition float.h:271
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define PG_FREE_IF_COPY(ptr, n)
Definition fmgr.h:260
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define DirectFunctionCall2(func, arg1, arg2)
Definition fmgr.h:686
#define PG_RETURN_FLOAT8(x)
Definition fmgr.h:369
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_GETARG_DATUM(n)
Definition fmgr.h:268
#define PG_GETARG_UINT16(n)
Definition fmgr.h:272
#define DirectFunctionCall5(func, arg1, arg2, arg3, arg4, arg5)
Definition fmgr.h:692
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
static bool FPlt(double A, double B)
Definition geo_decls.h:59
#define PG_GETARG_POINT_P(n)
Definition geo_decls.h:184
static bool FPge(double A, double B)
Definition geo_decls.h:77
static Datum PolygonPGetDatum(const POLYGON *X)
Definition geo_decls.h:256
static Point * DatumGetPointP(Datum X)
Definition geo_decls.h:175
static Datum PointPGetDatum(const Point *X)
Definition geo_decls.h:180
static POLYGON * DatumGetPolygonP(Datum X)
Definition geo_decls.h:246
static BOX * DatumGetBoxP(Datum X)
Definition geo_decls.h:233
#define PG_GETARG_BOX_P(n)
Definition geo_decls.h:242
#define PG_GETARG_POLYGON_P(n)
Definition geo_decls.h:260
static CIRCLE * DatumGetCircleP(Datum X)
Definition geo_decls.h:265
static Datum CirclePGetDatum(const CIRCLE *X)
Definition geo_decls.h:270
#define PG_GETARG_CIRCLE_P(n)
Definition geo_decls.h:274
static bool FPgt(double A, double B)
Definition geo_decls.h:71
static bool FPle(double A, double B)
Definition geo_decls.h:65
static Datum BoxPGetDatum(const BOX *X)
Definition geo_decls.h:238
static bool FPeq(double A, double B)
Definition geo_decls.h:47
Datum box_left(PG_FUNCTION_ARGS)
Definition geo_ops.c:583
Datum box_right(PG_FUNCTION_ARGS)
Definition geo_ops.c:609
Datum box_same(PG_FUNCTION_ARGS)
Definition geo_ops.c:551
Datum poly_contain_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4008
Datum box_below(PG_FUNCTION_ARGS)
Definition geo_ops.c:635
Datum box_overright(PG_FUNCTION_ARGS)
Definition geo_ops.c:624
Datum box_overabove(PG_FUNCTION_ARGS)
Definition geo_ops.c:670
Datum box_overlap(PG_FUNCTION_ARGS)
Definition geo_ops.c:563
Datum box_contain(PG_FUNCTION_ARGS)
Definition geo_ops.c:692
Datum circle_contain_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5082
Datum box_overbelow(PG_FUNCTION_ARGS)
Definition geo_ops.c:647
Datum box_contained(PG_FUNCTION_ARGS)
Definition geo_ops.c:681
Datum box_overleft(PG_FUNCTION_ARGS)
Definition geo_ops.c:598
Datum box_above(PG_FUNCTION_ARGS)
Definition geo_ops.c:658
#define GIST_LEAF(entry)
Definition gist.h:171
#define gistentryinit(e, k, r, pg, o, l)
Definition gist.h:245
static void adjustBox(BOX *b, const BOX *addon)
Definition gistproc.c:147
static void fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
Definition gistproc.c:217
Datum gist_box_penalty(PG_FUNCTION_ARGS)
Definition gistproc.c:200
#define BoxStrategyNumberGroup
Definition gistproc.c:1335
Datum gist_box_picksplit(PG_FUNCTION_ARGS)
Definition gistproc.c:496
Datum gist_circle_compress(PG_FUNCTION_ARGS)
Definition gistproc.c:1102
static bool rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy)
Definition gistproc.c:958
Datum gist_box_consistent(PG_FUNCTION_ARGS)
Definition gistproc.c:113
static int interval_cmp_upper(const void *i1, const void *i2)
Definition gistproc.c:328
static int gist_bbox_zorder_cmp(Datum a, Datum b, SortSupport ssup)
Definition gistproc.c:1687
Datum gist_box_distance(PG_FUNCTION_ARGS)
Definition gistproc.c:1503
#define point_point_distance(p1, p2)
Definition gistproc.c:1219
#define LIMIT_RATIO
Definition gistproc.c:44
static float8 gist_bbox_distance(GISTENTRY *entry, Datum query, StrategyNumber strategy)
Definition gistproc.c:1482
Datum gist_poly_compress(PG_FUNCTION_ARGS)
Definition gistproc.c:1036
static void rt_box_union(BOX *n, const BOX *a, const BOX *b)
Definition gistproc.c:55
#define GeoStrategyNumberOffset
Definition gistproc.c:1333
#define PLACE_RIGHT(box, off)
Datum gist_poly_distance(PG_FUNCTION_ARGS)
Definition gistproc.c:1548
static void g_box_consider_split(ConsiderSplitContext *context, int dimNum, float8 rightLower, int minLeftCount, float8 leftUpper, int maxLeftCount)
Definition gistproc.c:352
Datum gist_point_distance(PG_FUNCTION_ARGS)
Definition gistproc.c:1458
static float8 box_penalty(const BOX *original, const BOX *new)
Definition gistproc.c:97
Datum gist_circle_distance(PG_FUNCTION_ARGS)
Definition gistproc.c:1530
static Datum gist_bbox_zorder_abbrev_convert(Datum original, SortSupport ssup)
Definition gistproc.c:1720
#define CircleStrategyNumberGroup
Definition gistproc.c:1337
static uint64 part_bits32_by2(uint32 x)
Definition gistproc.c:1592
Datum gist_point_sortsupport(PG_FUNCTION_ARGS)
Definition gistproc.c:1747
#define PointStrategyNumberGroup
Definition gistproc.c:1334
Datum gist_box_union(PG_FUNCTION_ARGS)
Definition gistproc.c:165
static int interval_cmp_lower(const void *i1, const void *i2)
Definition gistproc.c:316
static float8 size_box(const BOX *box)
Definition gistproc.c:68
static uint32 ieee_float32_to_uint32(float f)
Definition gistproc.c:1609
Datum gist_circle_consistent(PG_FUNCTION_ARGS)
Definition gistproc.c:1132
static bool gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
Definition gistproc.c:873
static int common_entry_cmp(const void *i1, const void *i2)
Definition gistproc.c:461
#define PolygonStrategyNumberGroup
Definition gistproc.c:1336
Datum gist_poly_consistent(PG_FUNCTION_ARGS)
Definition gistproc.c:1063
Datum gist_point_compress(PG_FUNCTION_ARGS)
Definition gistproc.c:1171
static uint64 point_zorder_internal(float4 x, float4 y)
Definition gistproc.c:1581
Datum gist_point_consistent(PG_FUNCTION_ARGS)
Definition gistproc.c:1340
static bool gist_point_consistent_internal(StrategyNumber strategy, bool isLeaf, BOX *key, Point *query)
Definition gistproc.c:1290
Datum gist_box_same(PG_FUNCTION_ARGS)
Definition gistproc.c:853
#define PLACE_LEFT(box, off)
static bool gist_bbox_zorder_abbrev_abort(int memtupcount, SortSupport ssup)
Definition gistproc.c:1738
static float8 computeDistance(bool isLeaf, BOX *box, Point *point)
Definition gistproc.c:1224
Datum gist_point_fetch(PG_FUNCTION_ARGS)
Definition gistproc.c:1199
static float non_negative(float val)
Definition gistproc.c:340
long val
Definition informix.c:689
int y
Definition isn.c:76
int b
Definition isn.c:74
int x
Definition isn.c:75
int a
Definition isn.c:73
int i
Definition isn.c:77
void * palloc(Size size)
Definition mcxt.c:1387
#define OffsetNumberNext(offsetNumber)
Definition off.h:52
uint16 OffsetNumber
Definition off.h:24
#define FirstOffsetNumber
Definition off.h:27
Datum lower(PG_FUNCTION_ARGS)
Datum upper(PG_FUNCTION_ARGS)
#define qsort(a, b, c, d)
Definition port.h:495
static bool DatumGetBool(Datum X)
Definition postgres.h:100
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
static Datum UInt64GetDatum(uint64 X)
Definition postgres.h:443
static Datum Int16GetDatum(int16 X)
Definition postgres.h:182
uint64_t Datum
Definition postgres.h:70
unsigned int Oid
static int fb(int x)
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
struct SortSupportData * SortSupport
Definition sortsupport.h:58
uint16 StrategyNumber
Definition stratnum.h:22
#define RTOverlapStrategyNumber
Definition stratnum.h:53
#define RTLeftStrategyNumber
Definition stratnum.h:51
#define RTOverRightStrategyNumber
Definition stratnum.h:54
#define RTRightStrategyNumber
Definition stratnum.h:55
#define RTSameStrategyNumber
Definition stratnum.h:56
#define RTOverAboveStrategyNumber
Definition stratnum.h:62
#define RTOldBelowStrategyNumber
Definition stratnum.h:79
#define RTContainsStrategyNumber
Definition stratnum.h:57
#define RTOverBelowStrategyNumber
Definition stratnum.h:59
#define RTBelowStrategyNumber
Definition stratnum.h:60
#define RTOldAboveStrategyNumber
Definition stratnum.h:80
#define RTAboveStrategyNumber
Definition stratnum.h:61
#define RTOverLeftStrategyNumber
Definition stratnum.h:52
#define RTContainedByStrategyNumber
Definition stratnum.h:58
Point low
Definition geo_decls.h:142
Point high
Definition geo_decls.h:141
float8 radius
Definition geo_decls.h:164
Point center
Definition geo_decls.h:163
float8 delta
Definition gistproc.c:277
OffsetNumber offset
Definition gist.h:164
Datum key
Definition gist.h:161
Page page
Definition gist.h:163
Relation rel
Definition gist.h:162
bool leafkey
Definition gist.h:165
int spl_nleft
Definition gist.h:144
OffsetNumber * spl_right
Definition gist.h:148
Datum spl_ldatum
Definition gist.h:145
Datum spl_rdatum
Definition gist.h:150
int spl_nright
Definition gist.h:149
OffsetNumber * spl_left
Definition gist.h:143
BOX boundbox
Definition geo_decls.h:154
float8 y
Definition geo_decls.h:98
float8 x
Definition geo_decls.h:97
int(* comparator)(Datum x, Datum y, SortSupport ssup)
Datum(* abbrev_converter)(Datum original, SortSupport ssup)
int(* abbrev_full_comparator)(Datum x, Datum y, SortSupport ssup)
bool(* abbrev_abort)(int memtupcount, SortSupport ssup)
float8 upper
Definition gistproc.c:309
float8 lower
Definition gistproc.c:308
Definition type.h:96
int ssup_datum_unsigned_cmp(Datum x, Datum y, SortSupport ssup)
Definition tuplesort.c:3122