1/*-------------------------------------------------------------------------
4 * Support procedures for GiSTs over 2-D objects (boxes, polygons, circles,
7 * This gives R-tree behavior, with Guttman's poly-time split algorithm.
10 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
14 * src/backend/access/gist/gistproc.c
16 *-------------------------------------------------------------------------
25#include "utils/fmgrprotos.h"
43/* Minimum accepted ratio of split */
44 #define LIMIT_RATIO 0.3
47/**************************************************
49 **************************************************/
52 * Calculates union of two boxes, a and b. The result is stored in *n.
64 * Size of a BOX for penalty-calculation purposes.
65 * The result can be +Infinity, but not NaN.
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.
75 * The less-than cases should not happen, but if they do, say "zero".
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.
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.
106 * The GiST Consistent method for boxes
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.
119 /* Oid subtype = PG_GETARG_OID(3); */
122 /* All cases served by this function are exact */
129 * if entry is not leaf, use rtree_internal_consistent, else use
130 * gist_box_leaf_consistent
143 * Increase BOX b to include addon.
149 b->high.x = addon->
high.
x;
151 b->low.x = addon->
low.
x;
153 b->high.y = addon->
high.
y;
155 b->low.y = addon->
low.
y;
159 * The GiST Union method for boxes
161 * returns the minimal bounding box that encloses all the entries in entryvec
173 numranges = entryvec->
n;
176 memcpy(pageunion,
cur,
sizeof(
BOX));
178 for (
i = 1;
i < numranges;
i++)
183 *sizep =
sizeof(
BOX);
189 * We store boxes as boxes in GiST indexes, so we do not need
190 * compress, decompress, or fetch functions.
194 * The GiST Penalty method for boxes (also used for points)
196 * As in the R-tree paper, we use change in area as our penalty metric
212 * Trivial split: half of entries will be placed on one page
213 * and another half - to another
224 maxoff = entryvec->
n - 1;
268 * Represents information about an entry that can be placed to either group
269 * without affecting overlap over selected axis ("common entry").
273 /* Index of entry in the initial array */
275 /* Delta between penalties of entry insertion into different groups */
280 * Context for g_box_consider_split. Contains information about currently
281 * selected split and some general information.
288 /* Information about currently selected split follows */
290 bool first;
/* true if no split was selected yet */
297 int dim;
/* axis of this split */
303 * Interval represents projection of box to axis.
312 * Interval comparison function by lower bound of the interval;
324 * Interval comparison function by upper bound of the interval;
336 * Replace negative (or NaN) value with zero.
348 * Consider replacement of currently selected split with the better one.
352 float8 rightLower,
int minLeftCount,
353 float8 leftUpper,
int maxLeftCount)
362 * Calculate entries distribution ratio assuming most uniform distribution
367 leftCount = minLeftCount;
371 if (maxLeftCount <= context->entriesCount / 2)
372 leftCount = maxLeftCount;
379 * Ratio of split - quotient between size of lesser group and total
386 bool selectthis =
false;
389 * The ratio is acceptable, so compare current split with previously
390 * selected one. Between splits of one dimension we search for minimal
391 * overlap (allowing negative values) and minimal ration (between same
392 * overlaps. We switch dimension if find less overlap (non-negative)
393 * or less range with same overlap.
404 /* If there is no previous selection, select this */
407 else if (context->
dim == dimNum)
410 * Within the same dimension, choose the new split if it has a
411 * smaller overlap, or same overlap but better ratio.
413 if (overlap < context->overlap ||
414 (overlap == context->
overlap && ratio > context->
ratio))
420 * Across dimensions, choose the new split if it has a smaller
421 * *non-negative* overlap, or same *non-negative* overlap but
422 * bigger range. This condition differs from the one described in
423 * the article. On the datasets where leaf MBRs don't overlap
424 * themselves, non-overlapping splits (i.e. splits which have zero
425 * *non-negative* overlap) are frequently possible. In this case
426 * splits tends to be along one dimension, because most distant
427 * non-overlapping splits (i.e. having lowest negative overlap)
428 * appears to be in the same dimension as in the previous split.
429 * Therefore MBRs appear to be very prolonged along another
430 * dimension, which leads to bad search performance. Using range
431 * as the second split criteria makes MBRs more quadratic. Using
432 * *non-negative* overlap instead of overlap as the first split
433 * criteria gives to range criteria a chance to matter, because
434 * non-overlapping splits are equivalent in this criteria.
444 /* save information about selected split */
445 context->
first =
false;
446 context->
ratio = ratio;
451 context->
dim = dimNum;
457 * Compare common entries by their deltas.
469 * --------------------------------------------------------------------------
470 * Double sorting split algorithm. This is used for both boxes and points.
472 * The algorithm finds split of boxes by considering splits along each axis.
473 * Each entry is first projected as an interval on the X-axis, and different
474 * ways to split the intervals into two groups are considered, trying to
475 * minimize the overlap of the groups. Then the same is repeated for the
476 * Y-axis, and the overall best split is chosen. The quality of a split is
477 * determined by overlap along that axis and some other criteria (see
478 * g_box_consider_split).
480 * After that, all the entries are divided into three groups:
482 * 1) Entries which should be placed to the left group
483 * 2) Entries which should be placed to the right group
484 * 3) "Common entries" which can be placed to any of groups without affecting
485 * of overlap along selected axis.
487 * The common entries are distributed by minimizing penalty.
490 * "A new double sorting-based node splitting algorithm for R-tree", A. Korotkov
491 * http://syrcose.ispras.ru/2011/files/SYRCoSE2011_Proceedings.pdf#page=36
492 * --------------------------------------------------------------------------
514 maxoff = entryvec->
n - 1;
517 /* Allocate arrays for intervals along axes */
522 * Calculate the overall minimum bounding box over all the entries.
534 * Iterate over axes for optimal split searching.
536 context.
first =
true;
/* nothing selected yet */
537 for (dim = 0; dim < 2; dim++)
544 /* Project each entry as an interval on the selected axis. */
561 * Make two arrays of intervals: one sorted by lower bound and another
562 * sorted by upper bound.
564 memcpy(intervalsUpper, intervalsLower,
572 * The goal is to form a left and right interval, so that every entry
573 * interval is contained by either left or right interval (or both).
575 * For example, with the intervals (0,1), (1,3), (2,3), (2,4):
583 * The left and right intervals are of the form (0,a) and (b,4).
584 * We first consider splits where b is the lower bound of an entry.
585 * We iterate through all entries, and for each b, calculate the
586 * smallest possible a. Then we consider splits where a is the
587 * upper bound of an entry, and for each a, calculate the greatest
590 * In the above example, the first loop would consider splits:
595 * And the second loop:
602 * Iterate over lower bound of right group, finding smallest possible
603 * upper bound of left group.
607 rightLower = intervalsLower[i1].
lower;
608 leftUpper = intervalsUpper[i2].
lower;
612 * Find next lower bound of right group.
614 while (i1 < nentries &&
618 leftUpper = intervalsLower[i1].
upper;
623 rightLower = intervalsLower[i1].
lower;
626 * Find count of intervals which anyway should be placed to the
629 while (i2 < nentries &&
634 * Consider found split.
640 * Iterate over upper bound of left group finding greatest possible
641 * lower bound of right group.
645 rightLower = intervalsLower[i1].
upper;
646 leftUpper = intervalsUpper[i2].
upper;
650 * Find next upper bound of left group.
655 rightLower = intervalsUpper[i2].
lower;
660 leftUpper = intervalsUpper[i2].
upper;
663 * Find count of intervals which anyway should be placed to the
666 while (i1 >= 0 &&
float8_ge(intervalsLower[i1].
lower, rightLower))
670 * Consider found split.
673 rightLower, i1 + 1, leftUpper, i2 + 1);
678 * If we failed to find any acceptable splits, use trivial split.
687 * Ok, we have now selected the split across one axis.
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.
694 /* Allocate vectors for results */
700 /* Allocate bounding boxes of left and right groups */
705 * Allocate an array for "common entries" - entries which can be placed to
706 * either group without affecting overlap along selected axis.
708 commonEntriesCount = 0;
711 /* Helper macros to place an entry in the left or right group */
712#define PLACE_LEFT(box, off) \
714 if (v->spl_nleft > 0) \
715 adjustBox(leftBox, box); \
718 v->spl_left[v->spl_nleft++] = off; \
721#define PLACE_RIGHT(box, off) \
723 if (v->spl_nright > 0) \
724 adjustBox(rightBox, box); \
726 *rightBox = *(box); \
727 v->spl_right[v->spl_nright++] = off; \
731 * Distribute entries which can be distributed unambiguously, and collect
740 * Get upper and lower bounds along selected axis.
743 if (context.
dim == 0)
756 /* Fits to the left group */
759 /* Fits also to the right group, so "common entry" */
760 commonEntries[commonEntriesCount++].
index =
i;
764 /* Doesn't fit to the right group, so join to the left group */
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
777 /* Doesn't fit to the left group, so join to the right group */
783 * Distribute "common entries", if any.
785 if (commonEntriesCount > 0)
788 * Calculate minimum number of entries that must be placed in both
789 * groups, to reach LIMIT_RATIO.
794 * Calculate delta between penalties of join "common entries" to
797 for (
i = 0;
i < commonEntriesCount;
i++)
805 * Sort "common entries" by calculated deltas in order to distribute
806 * the most ambiguous entries first.
811 * Distribute "common entries" between groups.
813 for (
i = 0;
i < commonEntriesCount;
i++)
818 * Check if we have to place this entry in either group to achieve
821 if (v->
spl_nleft + (commonEntriesCount -
i) <= m)
823 else if (v->
spl_nright + (commonEntriesCount -
i) <= m)
827 /* Otherwise select the group by minimal penalty */
844 * This is used for boxes, points, circles, and polygons, all of which store
845 * boxes as GiST index entries.
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().
864 *result = (b1 == NULL && b2 == NULL);
869 * Leaf-level consistency for boxes: just apply the query operator
939 elog(
ERROR,
"unrecognized strategy number: %d", strategy);
940 retval =
false;
/* keep compiler quiet */
946/*****************************************
947 * Common rtree functions (for boxes, polygons, and circles)
948 *****************************************/
951 * Internal-page consistency for all these types
953 * We can use the same function since all types use bounding boxes as the
954 * internal-page representation.
1020 elog(
ERROR,
"unrecognized strategy number: %d", strategy);
1021 retval =
false;
/* keep compiler quiet */
1027/**************************************************
1029 **************************************************/
1032 * GiST compress for polygons: represent a polygon by its bounding box
1059 * The GiST Consistent method for polygons
1068 /* Oid subtype = PG_GETARG_OID(3); */
1072 /* All cases served by this function are inexact */
1079 * Since the operators require recheck anyway, we can just use
1080 * rtree_internal_consistent even at leaf nodes. (This works in part
1081 * because the index entries are bounding boxes not polygons.)
1086 /* Avoid memory leak if supplied poly is toasted */
1092/**************************************************
1094 **************************************************/
1097 * GiST compress for circles: represent a circle by its bounding box
1127 * The GiST Consistent method for circles
1136 /* Oid subtype = PG_GETARG_OID(3); */
1141 /* All cases served by this function are inexact */
1148 * Since the operators require recheck anyway, we can just use
1149 * rtree_internal_consistent even at leaf nodes. (This works in part
1150 * because the index entries are bounding boxes not circles.)
1163/**************************************************
1165 **************************************************/
1172 if (entry->
leafkey)
/* Point, actually */
1178 box->
high = box->
low = *point;
1190 * GiST Fetch method for point
1192 * Get point coordinates from its bounding box coordinates and form new
1216 #define point_point_distance(p1,p2) \
1217 DatumGetFloat8(DirectFunctionCall2(point_distance, \
1218 PointPGetDatum(p1), PointPGetDatum(p2)))
1227 /* simple point to point distance */
1230 else if (point->
x <= box->
high.
x && point->
x >= box->
low.
x &&
1231 point->
y <= box->
high.
y && point->
y >= box->
low.
y)
1233 /* point inside the box */
1236 else if (point->
x <= box->
high.
x && point->
x >= box->
low.
x)
1238 /* point is over or below box */
1240 if (point->
y > box->
high.
y)
1242 else if (point->
y < box->
low.
y)
1245 elog(
ERROR,
"inconsistent point values");
1247 else if (point->
y <= box->
high.
y && point->
y >= box->
low.
y)
1249 /* point is to left or right of box */
1251 if (point->
x > box->
high.
x)
1253 else if (point->
x < box->
low.
x)
1256 elog(
ERROR,
"inconsistent point values");
1260 /* closest point will be a vertex */
1267 if (result > subresult)
1273 if (result > subresult)
1279 if (result > subresult)
1290 bool result =
false;
1295 result =
FPlt(
key->low.x, query->
x);
1298 result =
FPgt(
key->high.x, query->
x);
1301 result =
FPgt(
key->high.y, query->
y);
1304 result =
FPlt(
key->low.y, query->
y);
1309 /* key.high must equal key.low, so we can disregard it */
1310 result = (
FPeq(
key->low.x, query->
x) &&
1315 result = (
FPle(query->
x,
key->high.x) &&
1322 elog(
ERROR,
"unrecognized strategy number: %d", strategy);
1323 result =
false;
/* keep compiler quiet */
1330 #define GeoStrategyNumberOffset 20
1331 #define PointStrategyNumberGroup 0
1332 #define BoxStrategyNumberGroup 1
1333 #define PolygonStrategyNumberGroup 2
1334 #define CircleStrategyNumberGroup 3
1346 * We have to remap these strategy numbers to get this klugy
1347 * classification logic to work.
1355 switch (strategyGroup)
1367 * The only operator in this group is point <@ box (on_pb), so
1368 * we needn't examine strategy again.
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
1384 result = (
key->high.x >= query->
low.
x &&
1386 key->high.y >= query->
low.
y &&
1404 * We are on leaf page and quick check shows overlapping
1405 * of polygon's bounding box and point
1431 * We are on leaf page and quick check shows overlapping
1432 * of polygon's bounding box and point
1446 elog(
ERROR,
"unrecognized strategy number: %d", strategy);
1447 result =
false;
/* keep compiler quiet */
1462 switch (strategyGroup)
1470 elog(
ERROR,
"unrecognized strategy number: %d", strategy);
1471 distance = 0.0;
/* keep compiler quiet */
1484 switch (strategyGroup)
1492 elog(
ERROR,
"unrecognized strategy number: %d", strategy);
1493 distance = 0.0;
/* keep compiler quiet */
1506 /* Oid subtype = PG_GETARG_OID(3); */
1507 /* bool *recheck = (bool *) PG_GETARG_POINTER(4); */
1516 * The inexact GiST distance methods for geometric types that store bounding
1519 * Compute lossy distance from point to index entries. The result is inexact
1520 * because index entries are bounding boxes, not the exact shapes of the
1521 * indexed geometric types. We use distance from point to MBR of index entry.
1522 * This is a lower bound estimate of distance from point to indexed geometric
1532 /* Oid subtype = PG_GETARG_OID(3); */
1549 /* Oid subtype = PG_GETARG_OID(3); */
1560 * Z-order routines for fast index build
1564 * Compute Z-value of a point
1566 * Z-order (also known as Morton Code) maps a two-dimensional point to a
1567 * single integer, in a way that preserves locality. Points that are close in
1568 * the two-dimensional space are mapped to integer that are not far from each
1569 * other. We do that by interleaving the bits in the X and Y components.
1571 * Morton Code is normally defined only for integers, but the X and Y values
1572 * of a point are floating point. We expect floats to be in IEEE format.
1580 /* Interleave the bits */
1584/* Interleave 32 bits with zeroes */
1590 n = (n | (n << 16)) &
UINT64CONST(0x0000FFFF0000FFFF);
1591 n = (n | (n << 8)) &
UINT64CONST(0x00FF00FF00FF00FF);
1592 n = (n | (n << 4)) &
UINT64CONST(0x0F0F0F0F0F0F0F0F);
1593 n = (n | (n << 2)) &
UINT64CONST(0x3333333333333333);
1594 n = (n | (n << 1)) &
UINT64CONST(0x5555555555555555);
1600 * Convert a 32-bit IEEE float to uint32 in a way that preserves the ordering
1607 * IEEE 754 floating point format
1608 * ------------------------------
1610 * IEEE 754 floating point numbers have this format:
1614 * s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm
1616 * sign mantissa (23 bits)
1618 * Infinity has all bits in the exponent set and the mantissa is all
1619 * zeros. Negative infinity is the same but with the sign bit set.
1621 * NaNs are represented with all bits in the exponent set, and the least
1622 * significant bit in the mantissa also set. The rest of the mantissa bits
1623 * can be used to distinguish different kinds of NaNs.
1625 * The IEEE format has the nice property that when you take the bit
1626 * representation and interpret it as an integer, the order is preserved,
1627 * except for the sign. That holds for the +-Infinity values too.
1632 * In order to have a smooth transition from negative to positive numbers,
1633 * we map floats to unsigned integers like this:
1635 * x < 0 to range 0-7FFFFFFF
1636 * x = 0 to value 8000000 (both positive and negative zero)
1637 * x > 0 to range 8000001-FFFFFFFF
1639 * We don't care to distinguish different kind of NaNs, so they are all
1640 * mapped to the same arbitrary value, FFFFFFFF. Because of the IEEE bit
1641 * representation of NaNs, there aren't any non-NaN values that would be
1642 * mapped to FFFFFFFF. In fact, there is a range of unused values on both
1643 * ends of the uint32 space.
1657 /* Check the sign bit */
1658 if ((u.i & 0x80000000) != 0)
1661 * Map the negative value to range 0-7FFFFFFF. This flips the sign
1662 * bit to 0 in the same instruction.
1664 Assert(f <= 0);
/* can be -0 */
1669 /* Map the positive value (or 0) to range 80000000-FFFFFFFF */
1678 * Compare the Z-order of points
1689 * Do a quick check for equality first. It's not clear if this is worth it
1690 * in general, but certainly is when used as tie-breaker with abbreviated
1693 if (p1->
x == p2->
x && p1->
y == p2->
y)
1707 * Abbreviated version of Z-order comparison
1709 * The abbreviated format is a Z-order value computed from the two 32-bit
1710 * floats. Now that sizeof(Datum) is always 8, the 64-bit Z-order value
1711 * always fits fully in the abbreviated Datum.
1725 * We never consider aborting the abbreviation.
1727 * On 64-bit systems, the abbreviation is not lossy so it is always
1728 * worthwhile. (Perhaps it's not on 32-bit systems, but we don't bother
1729 * with logic to decide.)
1738 * Sort support routine for fast GiST index build by sorting.
int float8_cmp_internal(float8 a, float8 b)
static float8 float8_min(const float8 val1, const float8 val2)
static float8 float8_mul(const float8 val1, const float8 val2)
static float4 float4_div(const float4 val1, const float4 val2)
static float8 float8_pl(const float8 val1, const float8 val2)
static float8 float8_mi(const float8 val1, const float8 val2)
static float8 get_float8_infinity(void)
static bool float8_ge(const float8 val1, const float8 val2)
static float8 float8_max(const float8 val1, const float8 val2)
static bool float8_le(const float8 val1, const float8 val2)
static bool float8_eq(const float8 val1, const float8 val2)
static float8 float8_div(const float8 val1, const float8 val2)
static bool float8_lt(const float8 val1, const float8 val2)
static bool float8_gt(const float8 val1, const float8 val2)
#define PG_FREE_IF_COPY(ptr, n)
#define DirectFunctionCall2(func, arg1, arg2)
#define PG_RETURN_FLOAT8(x)
#define PG_GETARG_POINTER(n)
#define PG_GETARG_DATUM(n)
#define PG_GETARG_UINT16(n)
#define DirectFunctionCall5(func, arg1, arg2, arg3, arg4, arg5)
#define PG_RETURN_POINTER(x)
#define PG_RETURN_BOOL(x)
static bool FPlt(double A, double B)
#define PG_GETARG_POINT_P(n)
static bool FPge(double A, double B)
static Datum PolygonPGetDatum(const POLYGON *X)
static Point * DatumGetPointP(Datum X)
static Datum PointPGetDatum(const Point *X)
static POLYGON * DatumGetPolygonP(Datum X)
static BOX * DatumGetBoxP(Datum X)
#define PG_GETARG_BOX_P(n)
#define PG_GETARG_POLYGON_P(n)
static CIRCLE * DatumGetCircleP(Datum X)
static Datum CirclePGetDatum(const CIRCLE *X)
#define PG_GETARG_CIRCLE_P(n)
static bool FPgt(double A, double B)
static bool FPle(double A, double B)
static Datum BoxPGetDatum(const BOX *X)
static bool FPeq(double A, double B)
Datum box_left(PG_FUNCTION_ARGS)
Datum box_right(PG_FUNCTION_ARGS)
Datum box_same(PG_FUNCTION_ARGS)
Datum poly_contain_pt(PG_FUNCTION_ARGS)
Datum box_below(PG_FUNCTION_ARGS)
Datum box_overright(PG_FUNCTION_ARGS)
Datum box_overabove(PG_FUNCTION_ARGS)
Datum box_overlap(PG_FUNCTION_ARGS)
Datum box_contain(PG_FUNCTION_ARGS)
Datum circle_contain_pt(PG_FUNCTION_ARGS)
Datum box_overbelow(PG_FUNCTION_ARGS)
Datum box_contained(PG_FUNCTION_ARGS)
Datum box_overleft(PG_FUNCTION_ARGS)
Datum box_above(PG_FUNCTION_ARGS)
#define gistentryinit(e, k, r, pg, o, l)
static void adjustBox(BOX *b, const BOX *addon)
static void fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
Datum gist_box_penalty(PG_FUNCTION_ARGS)
#define BoxStrategyNumberGroup
Datum gist_box_picksplit(PG_FUNCTION_ARGS)
Datum gist_circle_compress(PG_FUNCTION_ARGS)
static bool rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy)
Datum gist_box_consistent(PG_FUNCTION_ARGS)
static int interval_cmp_upper(const void *i1, const void *i2)
static int gist_bbox_zorder_cmp(Datum a, Datum b, SortSupport ssup)
Datum gist_box_distance(PG_FUNCTION_ARGS)
#define point_point_distance(p1, p2)
static float8 gist_bbox_distance(GISTENTRY *entry, Datum query, StrategyNumber strategy)
Datum gist_poly_compress(PG_FUNCTION_ARGS)
static void rt_box_union(BOX *n, const BOX *a, const BOX *b)
#define GeoStrategyNumberOffset
#define PLACE_RIGHT(box, off)
Datum gist_poly_distance(PG_FUNCTION_ARGS)
static void g_box_consider_split(ConsiderSplitContext *context, int dimNum, float8 rightLower, int minLeftCount, float8 leftUpper, int maxLeftCount)
Datum gist_point_distance(PG_FUNCTION_ARGS)
static float8 box_penalty(const BOX *original, const BOX *new)
Datum gist_circle_distance(PG_FUNCTION_ARGS)
static Datum gist_bbox_zorder_abbrev_convert(Datum original, SortSupport ssup)
#define CircleStrategyNumberGroup
static uint64 part_bits32_by2(uint32 x)
Datum gist_point_sortsupport(PG_FUNCTION_ARGS)
#define PointStrategyNumberGroup
Datum gist_box_union(PG_FUNCTION_ARGS)
static int interval_cmp_lower(const void *i1, const void *i2)
static float8 size_box(const BOX *box)
static uint32 ieee_float32_to_uint32(float f)
Datum gist_circle_consistent(PG_FUNCTION_ARGS)
static bool gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
static int common_entry_cmp(const void *i1, const void *i2)
#define PolygonStrategyNumberGroup
Datum gist_poly_consistent(PG_FUNCTION_ARGS)
Datum gist_point_compress(PG_FUNCTION_ARGS)
static uint64 point_zorder_internal(float4 x, float4 y)
Datum gist_point_consistent(PG_FUNCTION_ARGS)
static bool gist_point_consistent_internal(StrategyNumber strategy, bool isLeaf, BOX *key, Point *query)
Datum gist_box_same(PG_FUNCTION_ARGS)
#define PLACE_LEFT(box, off)
static bool gist_bbox_zorder_abbrev_abort(int memtupcount, SortSupport ssup)
static float8 computeDistance(bool isLeaf, BOX *box, Point *point)
Datum gist_point_fetch(PG_FUNCTION_ARGS)
static float non_negative(float val)
Assert(PointerIsAligned(start, uint64))
void * palloc0(Size size)
#define OffsetNumberNext(offsetNumber)
#define FirstOffsetNumber
Datum lower(PG_FUNCTION_ARGS)
Datum upper(PG_FUNCTION_ARGS)
#define qsort(a, b, c, d)
static bool DatumGetBool(Datum X)
static Datum PointerGetDatum(const void *X)
static Datum UInt64GetDatum(uint64 X)
static Datum Int16GetDatum(int16 X)
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
struct SortSupportData * SortSupport
#define RTOverlapStrategyNumber
#define RTLeftStrategyNumber
#define RTOverRightStrategyNumber
#define RTRightStrategyNumber
#define RTSameStrategyNumber
#define RTOverAboveStrategyNumber
#define RTOldBelowStrategyNumber
#define RTContainsStrategyNumber
#define RTOverBelowStrategyNumber
#define RTBelowStrategyNumber
#define RTOldAboveStrategyNumber
#define RTAboveStrategyNumber
#define RTOverLeftStrategyNumber
#define RTContainedByStrategyNumber
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
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)
int ssup_datum_unsigned_cmp(Datum x, Datum y, SortSupport ssup)