From fa850a5ebbb78cad1e57128a331e780379a44f41 Mon Sep 17 00:00:00 2001 From: Andrey Date: Sun, 25 Aug 2019 12:42:36 +0500 Subject: [PATCH v10 1/2] Add sort support for point gist_point_sortsupport --- src/backend/access/gist/gistproc.c | 86 ++++++++++++++++++++++++++++++ src/include/catalog/pg_proc.dat | 3 ++ 2 files changed, 89 insertions(+) diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c index 9ace64c3c4..f7fb60910d 100644 --- a/src/backend/access/gist/gistproc.c +++ b/src/backend/access/gist/gistproc.c @@ -24,12 +24,18 @@ #include "utils/builtins.h" #include "utils/float.h" #include "utils/geo_decls.h" +#include "utils/sortsupport.h" static bool gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy); static bool rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy); +static int64 part_bits32_by2(uint32 x); +static int64 interleave_bits32(uint32 x, uint32 y); +static inline uint64 point_zorder_internal(Point *p); +static int gist_bbox_fastcmp(Datum x, Datum y, SortSupport ssup); + /* Minimum accepted ratio of split */ #define LIMIT_RATIO 0.3 @@ -1540,3 +1546,83 @@ gist_poly_distance(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(distance); } + +/* Z-order routines */ +/* Interleave 32 bits with zeroes */ +static int64 +part_bits32_by2(uint32 x) +{ + uint64 n = x; + + n = (n | (n << 16)) & UINT64CONST(0x0000FFFF0000FFFF); + n = (n | (n << 8)) & UINT64CONST(0x00FF00FF00FF00FF); + n = (n | (n << 4)) & UINT64CONST(0x0F0F0F0F0F0F0F0F); + n = (n | (n << 2)) & UINT64CONST(0x3333333333333333); + n = (n | (n << 1)) & UINT64CONST(0x5555555555555555); + + return n; +} + +/* + * Compute Z-order for integers. Also called Morton code. + */ +static int64 +interleave_bits32(uint32 x, uint32 y) +{ + return part_bits32_by2(x) | (part_bits32_by2(y) << 1); +} + +/* Compute Z-order for Point */ +static inline uint64 +point_zorder_internal(Point *p) +{ + /* + * In this function we need to compute Morton codes for non-integral + * components p->x and p->y. But Morton codes are defined only for + * integral values. + * We expect floats to be in IEEE format, and the sort order of IEEE + * floats is mostly correlated to the binary sort order of the bits + * reinterpreted as an int. It isn't in some special cases, but for this + * use case we don't really care about that, we're just trying to + * encourage locality. + * There is a big jump in integer value (whether signed or + * unsigned) as you cross from positive to negative floats, and then the + * sort order is reversed. This can have negative effect on searches when + * query window touches many quadrants simulatously. In worst case this + * seaches can be x4 more costly. + * We generate a Morton code that interleaves the bits of N integers + * to produce a single integer that preserves locality: things that were + * close in the N dimensional space are close in the resulting integer. + */ + union { + float f; + uint32 i; + } a,b; + a.f = p->x; + b.f = p->y; + if (isnan(a.f)) + a.i = PG_INT32_MAX; + if (isnan(b.f)) + b.i = PG_INT32_MAX; + return interleave_bits32(a.i, b.i); +} + +static int +gist_bbox_fastcmp(Datum x, Datum y, SortSupport ssup) +{ + Point *p1 = &(DatumGetBoxP(x)->low); + Point *p2 = &(DatumGetBoxP(y)->low); + uint64 z1 = point_zorder_internal(p1); + uint64 z2 = point_zorder_internal(p2); + + return z1 == z2 ? 0 : z1 > z2 ? 1 : -1; +} + +Datum +gist_point_sortsupport(PG_FUNCTION_ARGS) +{ + SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0); + + ssup->comparator = gist_bbox_fastcmp; + PG_RETURN_VOID(); +} diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 082a11f270..7e09e022f7 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -8044,6 +8044,9 @@ proname => 'gist_poly_distance', prorettype => 'float8', proargtypes => 'internal polygon int2 oid internal', prosrc => 'gist_poly_distance' }, +{ oid => '3435', descr => 'sort support', + proname => 'gist_point_sortsupport', prorettype => 'void', + proargtypes => 'internal', prosrc => 'gist_point_sortsupport' }, # GIN array support { oid => '2743', descr => 'GIN array support', -- 2.24.3 (Apple Git-128)