41 #include "access/gist.h"
42 #include "access/itup.h"
43 #include "access/skey.h"
45 #include "../postgis_config.h"
50 #include "lwgeom_pg.h"
51 #include "gserialized_gist.h"
59 # ifdef HAVE_GNU_ISFINITE
62 # define isfinite finite
70 #define LIMIT_RATIO 0.1
75 #if POSTGIS_DEBUG_LEVEL > 0
76 static int geog_counter_leaf = 0;
77 static int geog_counter_internal = 0;
84 Datum
gidx_in(PG_FUNCTION_ARGS);
104 #if POSTGIS_PGSQL_VERSION > 94
109 #if POSTGIS_PGSQL_VERSION > 94
114 #if POSTGIS_PGSQL_VERSION > 94
128 GIDX *c = (GIDX*)palloc(VARSIZE(b));
129 POSTGIS_DEBUGF(5,
"copied gidx (%p) to gidx (%p)", b, c);
130 memcpy((
void*)c, (
void*)b, VARSIZE(b));
141 POSTGIS_DEBUGF(5,
"validating gidx (%s)", gidx_to_string(b));
142 for (i = 0; i < GIDX_NDIMS(b); i++)
144 if (GIDX_GET_MIN(b, i) > GIDX_GET_MAX(b, i))
146 float tmp = GIDX_GET_MIN(b, i);
147 GIDX_SET_MIN(b, i, GIDX_GET_MAX(b, i));
148 GIDX_SET_MAX(b, i, tmp);
159 size_t size = VARSIZE(a) - VARHDRSZ;
168 SET_VARSIZE(a, VARHDRSZ);
175 int i, dims_union, dims_new;
192 dims_union = GIDX_NDIMS(*b_union);
193 dims_new = GIDX_NDIMS(b_new);
195 POSTGIS_DEBUGF(4,
"merging gidx (%s) into gidx (%s)", gidx_to_string(b_new), gidx_to_string(*b_union));
197 if ( dims_new < dims_union )
199 POSTGIS_DEBUGF(5,
"reallocating b_union from %d dims to %d dims", dims_union, dims_new);
200 *b_union = (GIDX*)repalloc(*b_union, GIDX_SIZE(dims_new));
201 SET_VARSIZE(*b_union, VARSIZE(b_new));
202 dims_union = dims_new;
205 for ( i = 0; i < dims_union; i++ )
208 GIDX_SET_MIN(*b_union, i, Min(GIDX_GET_MIN(*b_union,i),GIDX_GET_MIN(b_new,i)));
210 GIDX_SET_MAX(*b_union, i, Max(GIDX_GET_MAX(*b_union,i),GIDX_GET_MAX(b_new,i)));
213 POSTGIS_DEBUGF(5,
"merge complete (%s)", gidx_to_string(*b_union));
227 result = GIDX_GET_MAX(a,0) - GIDX_GET_MIN(a,0);
228 for ( i = 1; i < GIDX_NDIMS(a); i++ )
229 result *= (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
230 POSTGIS_DEBUGF(5,
"calculated volume of %s as %.8g", gidx_to_string(a), result);
243 result = GIDX_GET_MAX(a,0) - GIDX_GET_MIN(a,0);
244 for ( i = 1; i < GIDX_NDIMS(a); i++ )
245 result += (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
246 POSTGIS_DEBUGF(5,
"calculated edge of %s as %.8g", gidx_to_string(a), result);
253 if ( GIDX_NDIMS(*a) < GIDX_NDIMS(*b) )
266 int ndims_a, ndims_b;
268 POSTGIS_DEBUG(5,
"entered function");
270 if ( a == NULL && b == NULL )
272 elog(ERROR,
"gidx_union_volume received two null arguments");
290 ndims_a = GIDX_NDIMS(a);
291 ndims_b = GIDX_NDIMS(b);
294 result = Max(GIDX_GET_MAX(a,0),GIDX_GET_MAX(b,0)) - Min(GIDX_GET_MIN(a,0),GIDX_GET_MIN(b,0));
297 for ( i = 1; i < ndims_b; i++ )
299 result *= (Max(GIDX_GET_MAX(a,i),GIDX_GET_MAX(b,i)) - Min(GIDX_GET_MIN(a,i),GIDX_GET_MIN(b,i)));
303 for ( i = ndims_b; i < ndims_a; i++ )
305 result *= (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
308 POSTGIS_DEBUGF(5,
"volume( %s union %s ) = %.12g", gidx_to_string(a), gidx_to_string(b), result);
318 int ndims_a, ndims_b;
320 POSTGIS_DEBUG(5,
"entered function");
322 if ( a == NULL && b == NULL )
324 elog(ERROR,
"gidx_union_edge received two null arguments");
342 ndims_a = GIDX_NDIMS(a);
343 ndims_b = GIDX_NDIMS(b);
346 result = Max(GIDX_GET_MAX(a,0),GIDX_GET_MAX(b,0)) - Min(GIDX_GET_MIN(a,0),GIDX_GET_MIN(b,0));
349 for ( i = 1; i < ndims_b; i++ )
351 result += (Max(GIDX_GET_MAX(a,i),GIDX_GET_MAX(b,i)) - Min(GIDX_GET_MIN(a,i),GIDX_GET_MIN(b,i)));
355 for ( i = ndims_b; i < ndims_a; i++ )
357 result += (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
360 POSTGIS_DEBUGF(5,
"edge( %s union %s ) = %.12g", gidx_to_string(a), gidx_to_string(b), result);
371 POSTGIS_DEBUG(5,
"entered function");
373 if ( a == NULL || b == NULL )
375 elog(ERROR,
"gidx_inter_volume received a null argument");
388 result = Min(GIDX_GET_MAX(a,0),GIDX_GET_MAX(b,0)) - Max(GIDX_GET_MIN(a,0),GIDX_GET_MIN(b,0));
391 if ( result < 0.0 )
return 0.0;
394 for ( i = 1; i < GIDX_NDIMS(b); i++ )
396 float width = Min(GIDX_GET_MAX(a,i),GIDX_GET_MAX(b,i)) - Max(GIDX_GET_MIN(a,i),GIDX_GET_MIN(b,i));
397 if ( width < 0.0 )
return 0.0;
401 POSTGIS_DEBUGF(5,
"volume( %s intersection %s ) = %.12g", gidx_to_string(a), gidx_to_string(b), result);
422 POSTGIS_DEBUG(5,
"entered function");
424 if ( (a == NULL) || (b == NULL) )
return false;
432 ndims_b = GIDX_NDIMS(b);
435 for ( i = 0; i < ndims_b; i++ )
437 if ( GIDX_GET_MIN(a,i) > GIDX_GET_MAX(b,i) )
439 if ( GIDX_GET_MIN(b,i) > GIDX_GET_MAX(a,i) )
453 int i, dims_a, dims_b;
455 POSTGIS_DEBUG(5,
"entered function");
457 if ( (a == NULL) || (b == NULL) )
return false;
462 dims_a = GIDX_NDIMS(a);
463 dims_b = GIDX_NDIMS(b);
465 if ( dims_a < dims_b )
471 for (i = dims_a; i < dims_b; i++)
473 if ( GIDX_GET_MIN(b,i) != 0 )
475 if ( GIDX_GET_MAX(b,i) != 0 )
481 for (i = 0; i < Min(dims_a, dims_b); i++)
483 if ( GIDX_GET_MIN(a,i) > GIDX_GET_MIN(b,i) )
485 if ( GIDX_GET_MAX(a,i) < GIDX_GET_MAX(b,i) )
501 POSTGIS_DEBUG(5,
"entered function");
503 if ( (a == NULL) && (b == NULL) )
return true;
504 if ( (a == NULL) || (b == NULL) )
return false;
516 for (i = 0; i < GIDX_NDIMS(b); i++)
518 if ( GIDX_GET_MIN(a,i) != GIDX_GET_MIN(b,i) )
520 if ( GIDX_GET_MAX(a,i) != GIDX_GET_MAX(b,i) )
524 for (i = GIDX_NDIMS(b); i < GIDX_NDIMS(a); i++)
526 if ( GIDX_GET_MIN(a,i) != 0.0 )
528 if ( GIDX_GET_MAX(a,i) != 0.0 )
542 char boxmem1[GIDX_MAX_SIZE];
543 char boxmem2[GIDX_MAX_SIZE];
544 GIDX *gidx1 = (GIDX*)boxmem1;
545 GIDX *gidx2 = (GIDX*)boxmem2;
547 POSTGIS_DEBUG(3,
"entered function");
551 if ( (gserialized_datum_get_gidx_p(gs1, gidx1) ==
LW_SUCCESS) &&
552 (gserialized_datum_get_gidx_p(gs2, gidx2) ==
LW_SUCCESS) &&
553 predicate(gidx1, gidx2) )
555 POSTGIS_DEBUGF(3,
"got boxes %s and %s", gidx_to_string(gidx1), gidx_to_string(gidx2));
561 #if POSTGIS_PGSQL_VERSION > 94
566 char boxmem2[GIDX_MAX_SIZE];
567 GIDX *gidx2 = (GIDX*)boxmem2;
569 POSTGIS_DEBUG(3,
"entered function");
573 if ( (gserialized_datum_get_gidx_p(gs2, gidx2) ==
LW_SUCCESS) &&
574 predicate(gidx1, gidx2) )
576 POSTGIS_DEBUGF(3,
"got boxes %s and %s", gidx_to_string(gidx1), gidx_to_string(gidx2));
586 char boxmem2[GIDX_MAX_SIZE];
587 GIDX *gidx1 = (GIDX*)boxmem2;
589 POSTGIS_DEBUG(3,
"entered function");
593 if ( (gserialized_datum_get_gidx_p(gs1, gidx1) ==
LW_SUCCESS) &&
594 predicate(gidx1, gidx2) )
596 POSTGIS_DEBUGF(3,
"got boxes %s and %s", gidx_to_string(gidx1), gidx_to_string(gidx2));
607 #if POSTGIS_PGSQL_VERSION < 95
608 static double gidx_distance_leaf_centroid(
const GIDX *a,
const GIDX *b)
614 ndims = Min(GIDX_NDIMS(b), GIDX_NDIMS(a));
615 for ( i = 0; i < ndims; ++i )
618 double amin = GIDX_GET_MIN(a,i);
619 double amax = GIDX_GET_MAX(a,i);
620 double bmin = GIDX_GET_MIN(b,i);
621 double bmax = GIDX_GET_MAX(b,i);
622 ca = amin + ( ( amax - amin ) / 2.0 );
623 cb = bmin + ( ( bmax - bmin ) / 2.0 );
654 ndims = Min(GIDX_NDIMS(b), GIDX_NDIMS(a));
655 for ( i = 0; i < ndims; ++i )
658 double amin = GIDX_GET_MIN(a,i);
659 double amax = GIDX_GET_MAX(a,i);
660 double bmin = GIDX_GET_MIN(b,i);
661 double bmax = GIDX_GET_MAX(b,i);
662 POSTGIS_DEBUGF(3,
"A %g - %g", amin, amax);
663 POSTGIS_DEBUGF(3,
"B %g - %g", bmin, bmax);
665 if ( ( amin <= bmax && amax >= bmin ) )
670 else if ( i == 4 && m_is_time )
674 else if ( bmax < amin )
682 assert( bmin > amax );
691 POSTGIS_DEBUGF(3,
"dist %g, squared %g, grows sum to %g", d, d*d, sum);
696 #if POSTGIS_PGSQL_VERSION < 95
697 static double gidx_distance_node_centroid(
const GIDX *node,
const GIDX *query)
703 int ndims = Min(GIDX_NDIMS(node), GIDX_NDIMS(query));
705 for ( i = 0; i < ndims; ++i )
708 double amin = GIDX_GET_MIN(query,i);
709 double amax = GIDX_GET_MAX(query,i);
710 double bmin = GIDX_GET_MIN(node,i);
711 double bmax = GIDX_GET_MAX(node,i);
712 double ca = amin + ( ( amax - amin ) / 2.0 );
714 if ( ( ca <= bmax && ca >= bmin ) )
719 else if ( bmax < ca )
736 POSTGIS_DEBUGF(3,
"dist %g, squared %g, grows sum to %g", d, d*d, sum);
744 double d, amin, amax, bmin, bmax;
747 mdim_a = GIDX_NDIMS(a) - 1;
748 mdim_b = GIDX_NDIMS(b) - 1;
750 amin = GIDX_GET_MIN(a,mdim_a);
751 amax = GIDX_GET_MAX(a,mdim_a);
752 bmin = GIDX_GET_MIN(b,mdim_b);
753 bmax = GIDX_GET_MAX(b,mdim_b);
755 if ( ( amin <= bmax && amax >= bmin ) )
760 else if ( bmax < amin )
768 assert( bmin > amax );
782 char boxmem[GIDX_MAX_SIZE];
783 GIDX *gidx = (GIDX*)boxmem;
788 if ( gserialized_get_gidx_p(g, gidx) ==
LW_FAILURE )
793 gidx_expand(gidx, fdistance);
795 return gserialized_set_gidx(g, gidx);
810 char b1mem[GIDX_MAX_SIZE];
811 GIDX *b1 = (GIDX*)b1mem;
812 char b2mem[GIDX_MAX_SIZE];
813 GIDX *b2 = (GIDX*)b2mem;
815 #if POSTGIS_PGSQL_VERSION < 95
818 Datum gs1 = PG_GETARG_DATUM(0);
819 Datum gs2 = PG_GETARG_DATUM(1);
820 double box_distance = FLT_MAX;
823 if ( (gserialized_datum_get_gidx_p(gs1, b1) ==
LW_SUCCESS) &&
824 (gserialized_datum_get_gidx_p(gs2, b2) ==
LW_SUCCESS) )
826 box_distance = gidx_distance_leaf_centroid(b1, b2);
827 POSTGIS_DEBUGF(3,
"got boxes %s and %s", gidx_to_string(b1), gidx_to_string(b2));
829 PG_RETURN_FLOAT8(box_distance);
860 double m1 = 0, m2 = 0;
900 gserialized_get_gidx_p(geom1, b1);
901 gserialized_get_gidx_p(geom2, b2);
913 PG_FREE_IF_COPY(geom1, 0);
914 PG_FREE_IF_COPY(geom2, 1);
928 PG_RETURN_BOOL(
true);
931 PG_RETURN_BOOL(
false);
934 #if POSTGIS_PGSQL_VERSION > 94
942 GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0);
945 PG_RETURN_BOOL(
true);
947 PG_RETURN_BOOL(
false);
957 if (
gidx_contains((GIDX *)PG_GETARG_POINTER(1), (GIDX *)PG_GETARG_POINTER(0)))
958 PG_RETURN_BOOL(
true);
960 PG_RETURN_BOOL(
false);
973 PG_RETURN_BOOL(
true);
976 PG_RETURN_BOOL(
false);
979 #if POSTGIS_PGSQL_VERSION > 94
987 GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0);
990 PG_RETURN_BOOL(
true);
992 PG_RETURN_BOOL(
false);
1002 if (
gidx_contains((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1)))
1003 PG_RETURN_BOOL(
true);
1005 PG_RETURN_BOOL(
false);
1011 GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0);
1014 PG_RETURN_BOOL(
true);
1016 PG_RETURN_BOOL(
false);
1022 if (
gidx_equals((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1)) )
1023 PG_RETURN_BOOL(
true);
1025 PG_RETURN_BOOL(
false);
1038 PG_RETURN_BOOL(
true);
1041 PG_RETURN_BOOL(
false);
1044 #if POSTGIS_PGSQL_VERSION > 94
1051 GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0);
1054 PG_RETURN_BOOL(
true);
1056 PG_RETURN_BOOL(
false);
1062 GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0);
1065 PG_RETURN_BOOL(
true);
1067 PG_RETURN_BOOL(
false);
1073 if (
gidx_overlaps((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1)) )
1074 PG_RETURN_BOOL(
true);
1076 PG_RETURN_BOOL(
false);
1093 GISTENTRY *entry_in = (GISTENTRY*)PG_GETARG_POINTER(0);
1094 GISTENTRY *entry_out = NULL;
1095 char gidxmem[GIDX_MAX_SIZE];
1096 GIDX *bbox_out = (GIDX*)gidxmem;
1100 POSTGIS_DEBUG(4,
"[GIST] 'compress' function called");
1106 if ( ! entry_in->leafkey )
1108 POSTGIS_DEBUG(4,
"[GIST] non-leafkey entry, returning input unaltered");
1109 PG_RETURN_POINTER(entry_in);
1112 POSTGIS_DEBUG(4,
"[GIST] processing leafkey input");
1113 entry_out = palloc(
sizeof(GISTENTRY));
1119 if ( DatumGetPointer(entry_in->key) == NULL )
1121 POSTGIS_DEBUG(4,
"[GIST] leafkey is null");
1122 gistentryinit(*entry_out, (Datum) 0, entry_in->rel,
1123 entry_in->page, entry_in->offset,
false);
1124 POSTGIS_DEBUG(4,
"[GIST] returning copy of input");
1125 PG_RETURN_POINTER(entry_out);
1129 result = gserialized_datum_get_gidx_p(entry_in->key, bbox_out);
1135 POSTGIS_DEBUG(4,
"[GIST] empty geometry!");
1137 gistentryinit(*entry_out, PointerGetDatum(
gidx_copy(bbox_out)),
1138 entry_in->rel, entry_in->page,
1139 entry_in->offset,
false);
1140 PG_RETURN_POINTER(entry_out);
1143 POSTGIS_DEBUGF(4,
"[GIST] got entry_in->key: %s", gidx_to_string(bbox_out));
1147 for ( i = 0; i < GIDX_NDIMS(bbox_out); i++ )
1149 if ( ! isfinite(GIDX_GET_MAX(bbox_out, i))
1150 || ! isfinite(GIDX_GET_MIN(bbox_out, i)) )
1153 gistentryinit(*entry_out,
1155 entry_in->rel, entry_in->page,
1156 entry_in->offset,
false);
1157 PG_RETURN_POINTER(entry_out);
1165 gistentryinit(*entry_out, PointerGetDatum(
gidx_copy(bbox_out)),
1166 entry_in->rel, entry_in->page, entry_in->offset,
false);
1169 POSTGIS_DEBUG(4,
"[GIST] 'compress' function complete");
1170 PG_RETURN_POINTER(entry_out);
1180 POSTGIS_DEBUG(5,
"[GIST] 'decompress' function called");
1182 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
1192 POSTGIS_DEBUGF(4,
"[GIST] leaf consistent, strategy [%d], count[%i]",
1193 strategy, geog_counter_leaf++);
1197 case RTOverlapStrategyNumber:
1200 case RTSameStrategyNumber:
1203 case RTContainsStrategyNumber:
1204 case RTOldContainsStrategyNumber:
1207 case RTContainedByStrategyNumber:
1208 case RTOldContainedByStrategyNumber:
1225 POSTGIS_DEBUGF(4,
"[GIST] internal consistent, strategy [%d], count[%i], query[%s], key[%s]",
1226 strategy, geog_counter_internal++, gidx_to_string(query), gidx_to_string(key) );
1230 case RTOverlapStrategyNumber:
1233 case RTSameStrategyNumber:
1234 case RTContainsStrategyNumber:
1235 case RTOldContainsStrategyNumber:
1238 case RTContainedByStrategyNumber:
1239 case RTOldContainedByStrategyNumber:
1256 GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
1257 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
1259 char gidxmem[GIDX_MAX_SIZE];
1260 GIDX *query_gbox_index = (GIDX*)gidxmem;
1264 bool *recheck = (
bool *) PG_GETARG_POINTER(4);
1271 POSTGIS_DEBUG(4,
"[GIST] 'consistent' function called");
1274 if ( DatumGetPointer(PG_GETARG_DATUM(1)) == NULL )
1276 POSTGIS_DEBUG(4,
"[GIST] null query pointer (!?!), returning false");
1277 PG_RETURN_BOOL(
false);
1281 if ( DatumGetPointer(entry->key) == NULL )
1283 POSTGIS_DEBUG(4,
"[GIST] null index entry, returning false");
1284 PG_RETURN_BOOL(
false);
1288 if ( gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), query_gbox_index) ==
LW_FAILURE )
1290 POSTGIS_DEBUG(4,
"[GIST] null query_gbox_index!");
1291 PG_RETURN_BOOL(
false);
1295 if (GIST_LEAF(entry))
1298 (GIDX*)DatumGetPointer(entry->key),
1299 query_gbox_index, strategy);
1304 (GIDX*)DatumGetPointer(entry->key),
1305 query_gbox_index, strategy);
1308 PG_RETURN_BOOL(result);
1328 struct {
unsigned value:31, sign:1; } vbits;
1329 struct {
unsigned value:29, realm:2, sign:1; } rbits;
1333 a.rbits.value = a.vbits.value >> 2;
1334 a.rbits.realm = realm;
1346 GISTENTRY *origentry = (GISTENTRY*) PG_GETARG_POINTER(0);
1347 GISTENTRY *newentry = (GISTENTRY*) PG_GETARG_POINTER(1);
1348 float *result = (
float*) PG_GETARG_POINTER(2);
1349 GIDX *gbox_index_orig, *gbox_index_new;
1350 float size_union, size_orig, edge_union, edge_orig;
1352 POSTGIS_DEBUG(4,
"[GIST] 'penalty' function called");
1354 gbox_index_orig = (GIDX*)DatumGetPointer(origentry->key);
1355 gbox_index_new = (GIDX*)DatumGetPointer(newentry->key);
1358 if ( (gbox_index_orig == NULL) && (gbox_index_new == NULL) )
1360 POSTGIS_DEBUG(4,
"[GIST] both inputs NULL! returning penalty of zero");
1362 PG_RETURN_FLOAT8(*result);
1368 *result = size_union - size_orig;
1385 *result = edge_union - edge_orig;
1401 POSTGIS_DEBUGF(4,
"[GIST] union size (%.12f), original size (%.12f), penalty (%.12f)", size_union, size_orig, *result);
1403 PG_RETURN_POINTER(result);
1412 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
1413 int *sizep = (
int *) PG_GETARG_POINTER(1);
1415 GIDX *box_cur, *box_union;
1417 POSTGIS_DEBUG(4,
"[GIST] 'union' function called");
1419 numranges = entryvec->n;
1421 box_cur = (GIDX*) DatumGetPointer(entryvec->vector[0].key);
1425 for ( i = 1; i < numranges; i++ )
1427 box_cur = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
1431 *sizep = VARSIZE(box_union);
1433 POSTGIS_DEBUGF(4,
"[GIST] union called, numranges(%i), pageunion %s", numranges, gidx_to_string(box_union));
1435 PG_RETURN_POINTER(box_union);
1445 GIDX *b1 = (GIDX*)PG_GETARG_POINTER(0);
1446 GIDX *b2 = (GIDX*)PG_GETARG_POINTER(1);
1447 bool *result = (
bool*)PG_GETARG_POINTER(2);
1449 POSTGIS_DEBUG(4,
"[GIST] 'same' function called");
1453 PG_RETURN_POINTER(result);
1462 GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
1463 Datum query_datum = PG_GETARG_DATUM(1);
1464 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
1465 #if POSTGIS_PGSQL_VERSION >= 95
1466 bool *recheck = (
bool *) PG_GETARG_POINTER(4);
1468 char query_box_mem[GIDX_MAX_SIZE];
1469 GIDX *query_box = (GIDX*)query_box_mem;
1473 POSTGIS_DEBUGF(3,
"[GIST] '%s' function called", __func__);
1476 if ( strategy != 13 )
1478 elog(ERROR,
"unrecognized strategy number: %d", strategy);
1479 PG_RETURN_FLOAT8(FLT_MAX);
1483 if ( gserialized_datum_get_gidx_p(query_datum, query_box) ==
LW_FAILURE )
1485 POSTGIS_DEBUG(2,
"[GIST] null query_gbox_index!");
1486 PG_RETURN_FLOAT8(FLT_MAX);
1489 #if POSTGIS_PGSQL_VERSION >= 95
1491 if (GIST_LEAF(entry))
1498 entry_box = (GIDX*)DatumGetPointer(entry->key);
1506 POSTGIS_DEBUGF(2,
"[GIST] '%s' got distance %g", __func__,
distance);
1531 GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
1532 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
1533 char query_box_mem[GIDX_MAX_SIZE];
1534 GIDX *query_box = (GIDX*)query_box_mem;
1536 #if POSTGIS_PGSQL_VERSION >= 95
1537 bool *recheck = (
bool *) PG_GETARG_POINTER(4);
1542 POSTGIS_DEBUG(4,
"[GIST] 'distance' function called");
1546 if ( strategy != 13 && strategy != 20 ) {
1547 elog(ERROR,
"unrecognized strategy number: %d", strategy);
1548 PG_RETURN_FLOAT8(FLT_MAX);
1552 if ( gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), query_box) ==
LW_FAILURE )
1554 POSTGIS_DEBUG(4,
"[GIST] null query_gbox_index!");
1555 PG_RETURN_FLOAT8(FLT_MAX);
1559 entry_box = (GIDX*)DatumGetPointer(entry->key);
1561 #if POSTGIS_PGSQL_VERSION >= 95
1567 if (GIST_LEAF(entry))
1571 if ( strategy == 20 )
1573 elog(ERROR,
"You need PostgreSQL 9.5.0 or higher in order to use |=| with index");
1574 PG_RETURN_FLOAT8(FLT_MAX);
1578 if (GIST_LEAF(entry))
1581 distance = (double)gidx_distance_leaf_centroid(entry_box, query_box);
1586 distance = (double)gidx_distance_node_centroid(entry_box, query_box);
1616 POSTGIS_DEBUGF(4,
"[GIST] checking split ratio (%d, %d)",
x,
y);
1627 for ( i = 0; i < dims; i++ )
1642 OffsetNumber i, maxoff;
1643 GIDX *unionL = NULL;
1644 GIDX *unionR = NULL;
1647 POSTGIS_DEBUG(4,
"[GIST] in fallback picksplit function");
1649 maxoff = entryvec->n - 1;
1651 nbytes = (maxoff + 2) *
sizeof(OffsetNumber);
1652 v->spl_left = (OffsetNumber*) palloc(nbytes);
1653 v->spl_right = (OffsetNumber*) palloc(nbytes);
1654 v->spl_nleft = v->spl_nright = 0;
1656 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
1658 GIDX *
cur = (GIDX*)DatumGetPointer(entryvec->vector[i].key);
1660 if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
1662 v->spl_left[v->spl_nleft] = i;
1675 v->spl_right[v->spl_nright] = i;
1688 if (v->spl_ldatum_exists)
1689 gidx_merge(&unionL, (GIDX*)DatumGetPointer(v->spl_ldatum));
1691 v->spl_ldatum = PointerGetDatum(unionL);
1693 if (v->spl_rdatum_exists)
1694 gidx_merge(&unionR, (GIDX*)DatumGetPointer(v->spl_rdatum));
1696 v->spl_rdatum = PointerGetDatum(unionR);
1697 v->spl_ldatum_exists = v->spl_rdatum_exists =
false;
1704 bool firstToLeft =
true;
1706 POSTGIS_DEBUG(4,
"[GIST] picksplit in constructsplit function");
1708 if (v->spl_ldatum_exists || v->spl_rdatum_exists)
1710 if (v->spl_ldatum_exists && v->spl_rdatum_exists)
1716 double sizeLR, sizeRL;
1718 gidx_merge(&LRl, (GIDX*)DatumGetPointer(v->spl_ldatum));
1719 gidx_merge(&LRr, (GIDX*)DatumGetPointer(v->spl_rdatum));
1720 gidx_merge(&RLl, (GIDX*)DatumGetPointer(v->spl_ldatum));
1721 gidx_merge(&RLr, (GIDX*)DatumGetPointer(v->spl_rdatum));
1726 POSTGIS_DEBUGF(4,
"[GIST] sizeLR / sizeRL == %.12g / %.12g", sizeLR, sizeRL);
1728 if (sizeLR > sizeRL)
1729 firstToLeft =
false;
1735 GISTENTRY oldUnion, addon;
1737 gistentryinit(oldUnion, (v->spl_ldatum_exists) ? v->spl_ldatum : v->spl_rdatum,
1738 NULL, NULL, InvalidOffsetNumber,
false);
1740 gistentryinit(addon, PointerGetDatum(*union1), NULL, NULL, InvalidOffsetNumber,
false);
1741 DirectFunctionCall3(
gserialized_gist_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&addon), PointerGetDatum(&p1));
1742 gistentryinit(addon, PointerGetDatum(*union2), NULL, NULL, InvalidOffsetNumber,
false);
1743 DirectFunctionCall3(
gserialized_gist_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&addon), PointerGetDatum(&p2));
1745 POSTGIS_DEBUGF(4,
"[GIST] p1 / p2 == %.12g / %.12g", p1, p2);
1747 if ((v->spl_ldatum_exists && p1 > p2) || (v->spl_rdatum_exists && p1 < p2))
1748 firstToLeft =
false;
1752 POSTGIS_DEBUGF(4,
"[GIST] firstToLeft == %d", firstToLeft);
1756 v->spl_left = list1;
1757 v->spl_right = list2;
1758 v->spl_nleft = nlist1;
1759 v->spl_nright = nlist2;
1760 if (v->spl_ldatum_exists)
1761 gidx_merge(union1, (GIDX*)DatumGetPointer(v->spl_ldatum));
1762 v->spl_ldatum = PointerGetDatum(*union1);
1763 if (v->spl_rdatum_exists)
1764 gidx_merge(union2, (GIDX*)DatumGetPointer(v->spl_rdatum));
1765 v->spl_rdatum = PointerGetDatum(*union2);
1769 v->spl_left = list2;
1770 v->spl_right = list1;
1771 v->spl_nleft = nlist2;
1772 v->spl_nright = nlist1;
1773 if (v->spl_ldatum_exists)
1774 gidx_merge(union2, (GIDX*)DatumGetPointer(v->spl_ldatum));
1775 v->spl_ldatum = PointerGetDatum(*union2);
1776 if (v->spl_rdatum_exists)
1777 gidx_merge(union1, (GIDX*)DatumGetPointer(v->spl_rdatum));
1778 v->spl_rdatum = PointerGetDatum(*union1);
1781 v->spl_ldatum_exists = v->spl_rdatum_exists =
false;
1785 #define BELOW(d) (2*(d))
1786 #define ABOVE(d) ((2*(d))+1)
1799 GistEntryVector *entryvec = (GistEntryVector*) PG_GETARG_POINTER(0);
1801 GIST_SPLITVEC *v = (GIST_SPLITVEC*) PG_GETARG_POINTER(1);
1806 OffsetNumber **list;
1809 GIDX *box_pageunion;
1812 bool all_entries_equal =
true;
1813 OffsetNumber max_offset;
1814 int nbytes, ndims_pageunion, d;
1815 int posmin = entryvec->n;
1817 POSTGIS_DEBUG(4,
"[GIST] 'picksplit' function called");
1823 max_offset = entryvec->n - 1;
1824 box_current = (GIDX*) DatumGetPointer(entryvec->vector[FirstOffsetNumber].key);
1828 for ( i = OffsetNumberNext(FirstOffsetNumber); i <= max_offset; i = OffsetNumberNext(i) )
1830 box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
1832 if ( all_entries_equal ==
true && !
gidx_equals (box_pageunion, box_current) )
1833 all_entries_equal =
false;
1838 POSTGIS_DEBUGF(3,
"[GIST] box_pageunion: %s", gidx_to_string(box_pageunion));
1841 if ( all_entries_equal )
1843 POSTGIS_DEBUG(4,
"[GIST] picksplit finds all entries equal!");
1845 PG_RETURN_POINTER(v);
1849 nbytes = (max_offset + 2) *
sizeof(OffsetNumber);
1850 ndims_pageunion = GIDX_NDIMS(box_pageunion);
1851 POSTGIS_DEBUGF(4,
"[GIST] ndims_pageunion == %d", ndims_pageunion);
1852 pos = palloc(2*ndims_pageunion *
sizeof(
int));
1853 list = palloc(2*ndims_pageunion *
sizeof(OffsetNumber*));
1854 box_union = palloc(2*ndims_pageunion *
sizeof(GIDX*));
1855 for ( d = 0; d < ndims_pageunion; d++ )
1857 list[
BELOW(d)] = (OffsetNumber*) palloc(nbytes);
1858 list[
ABOVE(d)] = (OffsetNumber*) palloc(nbytes);
1859 box_union[
BELOW(d)] = gidx_new(ndims_pageunion);
1860 box_union[
ABOVE(d)] = gidx_new(ndims_pageunion);
1870 POSTGIS_DEBUG(4,
"[GIST] 'picksplit' calculating best split axis");
1871 for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) )
1873 box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
1875 for ( d = 0; d < ndims_pageunion; d++ )
1877 if ( GIDX_GET_MIN(box_current,d)-GIDX_GET_MIN(box_pageunion,d) < GIDX_GET_MAX(box_pageunion,d)-GIDX_GET_MAX(box_current,d) )
1903 double *avgCenter = palloc(ndims_pageunion *
sizeof(
double));
1905 for ( d = 0; d < ndims_pageunion; d++ )
1910 POSTGIS_DEBUG(4,
"[GIST] picksplit can't find good split axis, trying center point method");
1912 for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) )
1914 box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
1915 for ( d = 0; d < ndims_pageunion; d++ )
1917 avgCenter[d] += (GIDX_GET_MAX(box_current,d) + GIDX_GET_MIN(box_current,d)) / 2.0;
1920 for ( d = 0; d < ndims_pageunion; d++ )
1922 avgCenter[d] /= max_offset;
1924 POSTGIS_DEBUGF(4,
"[GIST] picksplit average center point[%d] = %.12g", d, avgCenter[d]);
1928 for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) )
1931 box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
1933 for ( d = 0; d < ndims_pageunion; d++ )
1935 center = (GIDX_GET_MIN(box_current,d)+GIDX_GET_MAX(box_current,d))/2.0;
1936 if ( center < avgCenter[d] )
1938 else if ( FPeq(center, avgCenter[d]) )
1952 POSTGIS_DEBUG(4,
"[GIST] picksplit still cannot find a good split! just cutting the node in half");
1954 PG_RETURN_POINTER(v);
1966 for ( d = 0; d < ndims_pageunion; d++ )
1969 if ( posd < posmin )
1975 if ( direction == -1 || posmin == entryvec->n )
1978 elog(ERROR,
"Error in building split, unable to determine split direction.");
1981 POSTGIS_DEBUGF(3,
"[GIST] 'picksplit' splitting on axis %d", direction);
1984 pos[
BELOW(direction)],
1985 &(box_union[
BELOW(direction)]),
1986 list[
ABOVE(direction)],
1987 pos[
ABOVE(direction)],
1988 &(box_union[
ABOVE(direction)]) );
1990 POSTGIS_DEBUGF(4,
"[GIST] spl_ldatum: %s", gidx_to_string((GIDX*)v->spl_ldatum));
1991 POSTGIS_DEBUGF(4,
"[GIST] spl_rdatum: %s", gidx_to_string((GIDX*)v->spl_rdatum));
1993 POSTGIS_DEBUGF(4,
"[GIST] axis %d: parent range (%.12g, %.12g) left range (%.12g, %.12g), right range (%.12g, %.12g)",
1995 GIDX_GET_MIN(box_pageunion, direction), GIDX_GET_MAX(box_pageunion, direction),
1996 GIDX_GET_MIN((GIDX*)v->spl_ldatum, direction), GIDX_GET_MAX((GIDX*)v->spl_ldatum, direction),
1997 GIDX_GET_MIN((GIDX*)v->spl_rdatum, direction), GIDX_GET_MAX((GIDX*)v->spl_rdatum, direction) );
1999 PG_RETURN_POINTER(v);
2010 ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2011 errmsg(
"function gidx_in not implemented")));
2012 PG_RETURN_POINTER(NULL);
2018 GIDX *box = (GIDX *) PG_GETARG_POINTER(0);
2019 char *result = gidx_to_string(box);
2020 PG_RETURN_CSTRING(result);
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
static void gidx_set_unknown(GIDX *a)
static float gidx_union_volume(GIDX *a, GIDX *b)
static bool gserialized_gist_consistent_internal(GIDX *key, GIDX *query, StrategyNumber strategy)
Datum gserialized_distance_nd(PG_FUNCTION_ARGS)
bool(* gidx_predicate)(GIDX *a, GIDX *b)
static void gserialized_gist_picksplit_constructsplit(GIST_SPLITVEC *v, OffsetNumber *list1, int nlist1, GIDX **union1, OffsetNumber *list2, int nlist2, GIDX **union2)
Datum gserialized_gidx_gidx_overlaps(PG_FUNCTION_ARGS)
Datum gserialized_gist_union(PG_FUNCTION_ARGS)
static bool gserialized_gist_picksplit_badratios(int *pos, int dims)
bool gidx_is_unknown(const GIDX *a)
static float pack_float(const float value, const int realm)
Datum gserialized_within(PG_FUNCTION_ARGS)
Datum gserialized_gist_same(PG_FUNCTION_ARGS)
static float gidx_inter_volume(GIDX *a, GIDX *b)
Datum gserialized_contains(PG_FUNCTION_ARGS)
static float gidx_union_edge(GIDX *a, GIDX *b)
static void gserialized_gist_picksplit_addlist(OffsetNumber *list, GIDX **box_union, GIDX *box_current, int *pos, int num)
Datum gserialized_gidx_geom_overlaps(PG_FUNCTION_ARGS)
Datum gserialized_gidx_gidx_within(PG_FUNCTION_ARGS)
static float gidx_volume(GIDX *a)
GIDX * gidx_copy(GIDX *b)
Datum gserialized_gist_consistent(PG_FUNCTION_ARGS)
Datum gserialized_gidx_geom_contains(PG_FUNCTION_ARGS)
static void gidx_dimensionality_check(GIDX **a, GIDX **b)
bool gidx_contains(GIDX *a, GIDX *b)
Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS)
static int gserialized_datum_predicate_gidx_geom(GIDX *gidx1, Datum gs2, gidx_predicate predicate)
static int gserialized_datum_predicate(Datum gs1, Datum gs2, gidx_predicate predicate)
Support function.
Datum gserialized_gidx_geog_overlaps(PG_FUNCTION_ARGS)
static int gserialized_gist_picksplit_badratio(int x, int y)
static bool gserialized_gist_consistent_leaf(GIDX *key, GIDX *query, StrategyNumber strategy)
static double gidx_distance_m(const GIDX *a, const GIDX *b)
static float gidx_edge(GIDX *a)
PG_FUNCTION_INFO_V1(gserialized_distance_nd)
Datum gserialized_gist_compress(PG_FUNCTION_ARGS)
Datum gserialized_gidx_gidx_same(PG_FUNCTION_ARGS)
static int gserialized_datum_predicate_geom_gidx(Datum gs1, GIDX *gidx2, gidx_predicate predicate)
Datum gserialized_overlaps(PG_FUNCTION_ARGS)
Datum gserialized_gidx_gidx_contains(PG_FUNCTION_ARGS)
Datum gserialized_gidx_geom_within(PG_FUNCTION_ARGS)
Datum gidx_out(PG_FUNCTION_ARGS)
Datum gserialized_gist_penalty(PG_FUNCTION_ARGS)
Datum gserialized_gist_distance(PG_FUNCTION_ARGS)
Datum gserialized_gist_decompress(PG_FUNCTION_ARGS)
Datum gserialized_gidx_geom_same(PG_FUNCTION_ARGS)
Datum gidx_in(PG_FUNCTION_ARGS)
Datum gserialized_gist_geog_distance(PG_FUNCTION_ARGS)
static double gidx_distance(const GIDX *a, const GIDX *b, int m_is_time)
Calculate the centroid->centroid distance between the boxes.
static bool gidx_equals(GIDX *a, GIDX *b)
static void gserialized_gist_picksplit_fallback(GistEntryVector *entryvec, GIST_SPLITVEC *v)
static bool gidx_overlaps(GIDX *a, GIDX *b)
void gidx_validate(GIDX *b)
void gidx_merge(GIDX **b_union, GIDX *b_new)
GSERIALIZED * gserialized_expand(GSERIALIZED *g, double distance)
Return a GSERIALIZED with an expanded bounding box.
int lwpoint_getPoint4d_p(const LWPOINT *point, POINT4D *out)
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
void lwpoint_free(LWPOINT *pt)
void lwgeom_free(LWGEOM *geom)
double lwgeom_interpolate_point(const LWGEOM *lwin, const LWPOINT *lwpt)
Find the measure value at the location on the line closest to the point.
uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
double lwgeom_length(const LWGEOM *geom)
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
LWGEOM * lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2)
double lwgeom_length_2d(const LWGEOM *geom)
#define LW_TRUE
Return types for functions with status returns.
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
LWGEOM * lwgeom_closest_line_3d(const LWGEOM *lw1, const LWGEOM *lw2)
LWPOINT * lwline_get_lwpoint(const LWLINE *line, uint32_t where)
Returns freshly allocated LWPOINT that corresponds to the index where.
This library is the generic geometry handling section of PostGIS.
Datum distance(PG_FUNCTION_ARGS)