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));
140 POSTGIS_DEBUGF(5,
"validating gidx (%s)", gidx_to_string(b));
141 for ( i = 0; i < GIDX_NDIMS(b); i++ )
143 if ( GIDX_GET_MIN(b,i) > GIDX_GET_MAX(b,i) )
146 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;
191 dims_union = GIDX_NDIMS(*b_union);
192 dims_new = GIDX_NDIMS(b_new);
194 POSTGIS_DEBUGF(4,
"merging gidx (%s) into gidx (%s)", gidx_to_string(b_new), gidx_to_string(*b_union));
196 if ( dims_new < dims_union )
198 POSTGIS_DEBUGF(5,
"reallocating b_union from %d dims to %d dims", dims_union, dims_new);
199 *b_union = (GIDX*)repalloc(*b_union, GIDX_SIZE(dims_new));
200 SET_VARSIZE(*b_union, VARSIZE(b_new));
201 dims_union = dims_new;
204 for ( i = 0; i < dims_union; i++ )
207 GIDX_SET_MIN(*b_union, i, Min(GIDX_GET_MIN(*b_union,i),GIDX_GET_MIN(b_new,i)));
209 GIDX_SET_MAX(*b_union, i, Max(GIDX_GET_MAX(*b_union,i),GIDX_GET_MAX(b_new,i)));
212 POSTGIS_DEBUGF(5,
"merge complete (%s)", gidx_to_string(*b_union));
226 result = GIDX_GET_MAX(a,0) - GIDX_GET_MIN(a,0);
227 for ( i = 1; i < GIDX_NDIMS(a); i++ )
228 result *= (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
229 POSTGIS_DEBUGF(5,
"calculated volume of %s as %.8g", gidx_to_string(a), result);
242 result = GIDX_GET_MAX(a,0) - GIDX_GET_MIN(a,0);
243 for ( i = 1; i < GIDX_NDIMS(a); i++ )
244 result += (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
245 POSTGIS_DEBUGF(5,
"calculated edge of %s as %.8g", gidx_to_string(a), result);
252 if ( GIDX_NDIMS(*a) < GIDX_NDIMS(*b) )
265 int ndims_a, ndims_b;
267 POSTGIS_DEBUG(5,
"entered function");
269 if ( a == NULL && b == NULL )
271 elog(ERROR,
"gidx_union_volume received two null arguments");
289 ndims_a = GIDX_NDIMS(a);
290 ndims_b = GIDX_NDIMS(b);
293 result = Max(GIDX_GET_MAX(a,0),GIDX_GET_MAX(b,0)) - Min(GIDX_GET_MIN(a,0),GIDX_GET_MIN(b,0));
296 for ( i = 1; i < ndims_b; i++ )
298 result *= (Max(GIDX_GET_MAX(a,i),GIDX_GET_MAX(b,i)) - Min(GIDX_GET_MIN(a,i),GIDX_GET_MIN(b,i)));
302 for ( i = ndims_b; i < ndims_a; i++ )
304 result *= (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
307 POSTGIS_DEBUGF(5,
"volume( %s union %s ) = %.12g", gidx_to_string(a), gidx_to_string(b), result);
317 int ndims_a, ndims_b;
319 POSTGIS_DEBUG(5,
"entered function");
321 if ( a == NULL && b == NULL )
323 elog(ERROR,
"gidx_union_edge received two null arguments");
341 ndims_a = GIDX_NDIMS(a);
342 ndims_b = GIDX_NDIMS(b);
345 result = Max(GIDX_GET_MAX(a,0),GIDX_GET_MAX(b,0)) - Min(GIDX_GET_MIN(a,0),GIDX_GET_MIN(b,0));
348 for ( i = 1; i < ndims_b; i++ )
350 result += (Max(GIDX_GET_MAX(a,i),GIDX_GET_MAX(b,i)) - Min(GIDX_GET_MIN(a,i),GIDX_GET_MIN(b,i)));
354 for ( i = ndims_b; i < ndims_a; i++ )
356 result += (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
359 POSTGIS_DEBUGF(5,
"edge( %s union %s ) = %.12g", gidx_to_string(a), gidx_to_string(b), result);
370 POSTGIS_DEBUG(5,
"entered function");
372 if ( a == NULL || b == NULL )
374 elog(ERROR,
"gidx_inter_volume received a null argument");
387 result = Min(GIDX_GET_MAX(a,0),GIDX_GET_MAX(b,0)) - Max(GIDX_GET_MIN(a,0),GIDX_GET_MIN(b,0));
390 if ( result < 0.0 )
return 0.0;
393 for ( i = 1; i < GIDX_NDIMS(b); i++ )
395 float width = Min(GIDX_GET_MAX(a,i),GIDX_GET_MAX(b,i)) - Max(GIDX_GET_MIN(a,i),GIDX_GET_MIN(b,i));
396 if ( width < 0.0 )
return 0.0;
400 POSTGIS_DEBUGF(5,
"volume( %s intersection %s ) = %.12g", gidx_to_string(a), gidx_to_string(b), result);
421 POSTGIS_DEBUG(5,
"entered function");
423 if ( (a == NULL) || (b == NULL) )
return FALSE;
431 ndims_b = GIDX_NDIMS(b);
434 for ( i = 0; i < ndims_b; i++ )
436 if ( GIDX_GET_MIN(a,i) > GIDX_GET_MAX(b,i) )
438 if ( GIDX_GET_MIN(b,i) > GIDX_GET_MAX(a,i) )
452 int i, dims_a, dims_b;
454 POSTGIS_DEBUG(5,
"entered function");
456 if ( (a == NULL) || (b == NULL) )
return FALSE;
461 dims_a = GIDX_NDIMS(a);
462 dims_b = GIDX_NDIMS(b);
464 if ( dims_a < dims_b )
470 for (i = dims_a; i < dims_b; i++)
472 if ( GIDX_GET_MIN(b,i) != 0 )
474 if ( GIDX_GET_MAX(b,i) != 0 )
480 for (i = 0; i < Min(dims_a, dims_b); i++)
482 if ( GIDX_GET_MIN(a,i) > GIDX_GET_MIN(b,i) )
484 if ( GIDX_GET_MAX(a,i) < GIDX_GET_MAX(b,i) )
500 POSTGIS_DEBUG(5,
"entered function");
502 if ( (a == NULL) && (b == NULL) )
return TRUE;
503 if ( (a == NULL) || (b == NULL) )
return FALSE;
515 for (i = 0; i < GIDX_NDIMS(b); i++)
517 if ( GIDX_GET_MIN(a,i) != GIDX_GET_MIN(b,i) )
519 if ( GIDX_GET_MAX(a,i) != GIDX_GET_MAX(b,i) )
523 for (i = GIDX_NDIMS(b); i < GIDX_NDIMS(a); i++)
525 if ( GIDX_GET_MIN(a,i) != 0.0 )
527 if ( GIDX_GET_MAX(a,i) != 0.0 )
541 char boxmem1[GIDX_MAX_SIZE];
542 char boxmem2[GIDX_MAX_SIZE];
543 GIDX *gidx1 = (GIDX*)boxmem1;
544 GIDX *gidx2 = (GIDX*)boxmem2;
546 POSTGIS_DEBUG(3,
"entered function");
550 if ( (gserialized_datum_get_gidx_p(gs1, gidx1) ==
LW_SUCCESS) &&
551 (gserialized_datum_get_gidx_p(gs2, gidx2) ==
LW_SUCCESS) &&
552 predicate(gidx1, gidx2) )
554 POSTGIS_DEBUGF(3,
"got boxes %s and %s", gidx_to_string(gidx1), gidx_to_string(gidx2));
560 #if POSTGIS_PGSQL_VERSION > 94 565 char boxmem2[GIDX_MAX_SIZE];
566 GIDX *gidx2 = (GIDX*)boxmem2;
568 POSTGIS_DEBUG(3,
"entered function");
572 if ( (gserialized_datum_get_gidx_p(gs2, gidx2) ==
LW_SUCCESS) &&
573 predicate(gidx1, gidx2) )
575 POSTGIS_DEBUGF(3,
"got boxes %s and %s", gidx_to_string(gidx1), gidx_to_string(gidx2));
585 char boxmem2[GIDX_MAX_SIZE];
586 GIDX *gidx1 = (GIDX*)boxmem2;
588 POSTGIS_DEBUG(3,
"entered function");
592 if ( (gserialized_datum_get_gidx_p(gs1, gidx1) ==
LW_SUCCESS) &&
593 predicate(gidx1, gidx2) )
595 POSTGIS_DEBUGF(3,
"got boxes %s and %s", gidx_to_string(gidx1), gidx_to_string(gidx2));
606 #if POSTGIS_PGSQL_VERSION < 95 607 static double gidx_distance_leaf_centroid(
const GIDX *a,
const GIDX *b)
613 ndims = Min(GIDX_NDIMS(b), GIDX_NDIMS(a));
614 for ( i = 0; i < ndims; ++i )
617 double amin = GIDX_GET_MIN(a,i);
618 double amax = GIDX_GET_MAX(a,i);
619 double bmin = GIDX_GET_MIN(b,i);
620 double bmax = GIDX_GET_MAX(b,i);
621 ca = amin + ( ( amax - amin ) / 2.0 );
622 cb = bmin + ( ( bmax - bmin ) / 2.0 );
653 ndims = Min(GIDX_NDIMS(b), GIDX_NDIMS(a));
654 for ( i = 0; i < ndims; ++i )
657 double amin = GIDX_GET_MIN(a,i);
658 double amax = GIDX_GET_MAX(a,i);
659 double bmin = GIDX_GET_MIN(b,i);
660 double bmax = GIDX_GET_MAX(b,i);
661 POSTGIS_DEBUGF(3,
"A %g - %g", amin, amax);
662 POSTGIS_DEBUGF(3,
"B %g - %g", bmin, bmax);
664 if ( ( amin <= bmax && amax >= bmin ) )
669 else if ( i == 4 && m_is_time )
673 else if ( bmax < amin )
681 assert( bmin > amax );
690 POSTGIS_DEBUGF(3,
"dist %g, squared %g, grows sum to %g", d, d*d, sum);
695 #if POSTGIS_PGSQL_VERSION < 95 696 static double gidx_distance_node_centroid(
const GIDX *node,
const GIDX *query)
702 int ndims = Min(GIDX_NDIMS(node), GIDX_NDIMS(query));
704 for ( i = 0; i < ndims; ++i )
707 double amin = GIDX_GET_MIN(query,i);
708 double amax = GIDX_GET_MAX(query,i);
709 double bmin = GIDX_GET_MIN(node,i);
710 double bmax = GIDX_GET_MAX(node,i);
711 double ca = amin + ( ( amax - amin ) / 2.0 );
713 if ( ( ca <= bmax && ca >= bmin ) )
718 else if ( bmax < ca )
735 POSTGIS_DEBUGF(3,
"dist %g, squared %g, grows sum to %g", d, d*d, sum);
743 double d, amin, amax, bmin, bmax;
746 mdim_a = GIDX_NDIMS(a) - 1;
747 mdim_b = GIDX_NDIMS(b) - 1;
749 amin = GIDX_GET_MIN(a,mdim_a);
750 amax = GIDX_GET_MAX(a,mdim_a);
751 bmin = GIDX_GET_MIN(b,mdim_b);
752 bmax = GIDX_GET_MAX(b,mdim_b);
754 if ( ( amin <= bmax && amax >= bmin ) )
759 else if ( bmax < amin )
767 assert( bmin > amax );
781 char boxmem[GIDX_MAX_SIZE];
782 GIDX *gidx = (GIDX*)boxmem;
783 float fdistance = (float)distance;
787 if ( gserialized_get_gidx_p(g, gidx) ==
LW_FAILURE )
792 gidx_expand(gidx, fdistance);
794 return gserialized_set_gidx(g, gidx);
809 char b1mem[GIDX_MAX_SIZE];
810 GIDX *b1 = (GIDX*)b1mem;
811 char b2mem[GIDX_MAX_SIZE];
812 GIDX *b2 = (GIDX*)b2mem;
814 #if POSTGIS_PGSQL_VERSION < 95 817 Datum gs1 = PG_GETARG_DATUM(0);
818 Datum gs2 = PG_GETARG_DATUM(1);
819 double box_distance = FLT_MAX;
822 if ( (gserialized_datum_get_gidx_p(gs1, b1) ==
LW_SUCCESS) &&
823 (gserialized_datum_get_gidx_p(gs2, b2) ==
LW_SUCCESS) )
825 box_distance = gidx_distance_leaf_centroid(b1, b2);
826 POSTGIS_DEBUGF(3,
"got boxes %s and %s", gidx_to_string(b1), gidx_to_string(b2));
828 PG_RETURN_FLOAT8(box_distance);
899 gserialized_get_gidx_p(geom1, b1);
900 gserialized_get_gidx_p(geom2, b2);
906 distance += (m2-m1)*(m2-m1);
912 PG_FREE_IF_COPY(geom1, 0);
913 PG_FREE_IF_COPY(geom2, 1);
914 PG_RETURN_FLOAT8(sqrt(distance));
927 PG_RETURN_BOOL(
TRUE);
930 PG_RETURN_BOOL(
FALSE);
933 #if POSTGIS_PGSQL_VERSION > 94 941 GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0);
944 PG_RETURN_BOOL(
TRUE);
946 PG_RETURN_BOOL(
FALSE);
956 if (
gidx_contains((GIDX *)PG_GETARG_POINTER(1), (GIDX *)PG_GETARG_POINTER(0)))
957 PG_RETURN_BOOL(
TRUE);
959 PG_RETURN_BOOL(
FALSE);
972 PG_RETURN_BOOL(
TRUE);
975 PG_RETURN_BOOL(
FALSE);
978 #if POSTGIS_PGSQL_VERSION > 94 986 GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0);
989 PG_RETURN_BOOL(
TRUE);
991 PG_RETURN_BOOL(
FALSE);
1001 if (
gidx_contains((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1)))
1002 PG_RETURN_BOOL(
TRUE);
1004 PG_RETURN_BOOL(
FALSE);
1010 GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0);
1013 PG_RETURN_BOOL(
TRUE);
1015 PG_RETURN_BOOL(
FALSE);
1021 if (
gidx_equals((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1)) )
1022 PG_RETURN_BOOL(
TRUE);
1024 PG_RETURN_BOOL(
FALSE);
1037 PG_RETURN_BOOL(
TRUE);
1040 PG_RETURN_BOOL(
FALSE);
1043 #if POSTGIS_PGSQL_VERSION > 94 1050 GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0);
1053 PG_RETURN_BOOL(
TRUE);
1055 PG_RETURN_BOOL(
FALSE);
1061 GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0);
1064 PG_RETURN_BOOL(
TRUE);
1066 PG_RETURN_BOOL(
FALSE);
1072 if (
gidx_overlaps((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1)) )
1073 PG_RETURN_BOOL(
TRUE);
1075 PG_RETURN_BOOL(
FALSE);
1092 GISTENTRY *entry_in = (GISTENTRY*)PG_GETARG_POINTER(0);
1093 GISTENTRY *entry_out = NULL;
1094 char gidxmem[GIDX_MAX_SIZE];
1095 GIDX *bbox_out = (GIDX*)gidxmem;
1099 POSTGIS_DEBUG(4,
"[GIST] 'compress' function called");
1105 if ( ! entry_in->leafkey )
1107 POSTGIS_DEBUG(4,
"[GIST] non-leafkey entry, returning input unaltered");
1108 PG_RETURN_POINTER(entry_in);
1111 POSTGIS_DEBUG(4,
"[GIST] processing leafkey input");
1112 entry_out = palloc(
sizeof(GISTENTRY));
1118 if ( DatumGetPointer(entry_in->key) == NULL )
1120 POSTGIS_DEBUG(4,
"[GIST] leafkey is null");
1121 gistentryinit(*entry_out, (Datum) 0, entry_in->rel,
1122 entry_in->page, entry_in->offset,
FALSE);
1123 POSTGIS_DEBUG(4,
"[GIST] returning copy of input");
1124 PG_RETURN_POINTER(entry_out);
1128 result = gserialized_datum_get_gidx_p(entry_in->key, bbox_out);
1134 POSTGIS_DEBUG(4,
"[GIST] empty geometry!");
1136 gistentryinit(*entry_out, PointerGetDatum(
gidx_copy(bbox_out)),
1137 entry_in->rel, entry_in->page,
1138 entry_in->offset,
FALSE);
1139 PG_RETURN_POINTER(entry_out);
1142 POSTGIS_DEBUGF(4,
"[GIST] got entry_in->key: %s", gidx_to_string(bbox_out));
1146 for ( i = 0; i < GIDX_NDIMS(bbox_out); i++ )
1148 if ( ! isfinite(GIDX_GET_MAX(bbox_out, i))
1149 || ! isfinite(GIDX_GET_MIN(bbox_out, i)) )
1152 gistentryinit(*entry_out,
1154 entry_in->rel, entry_in->page,
1155 entry_in->offset,
FALSE);
1156 PG_RETURN_POINTER(entry_out);
1164 gistentryinit(*entry_out, PointerGetDatum(
gidx_copy(bbox_out)),
1165 entry_in->rel, entry_in->page, entry_in->offset,
FALSE);
1168 POSTGIS_DEBUG(4,
"[GIST] 'compress' function complete");
1169 PG_RETURN_POINTER(entry_out);
1179 POSTGIS_DEBUG(5,
"[GIST] 'decompress' function called");
1181 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
1191 POSTGIS_DEBUGF(4,
"[GIST] leaf consistent, strategy [%d], count[%i]",
1192 strategy, geog_counter_leaf++);
1196 case RTOverlapStrategyNumber:
1199 case RTSameStrategyNumber:
1202 case RTContainsStrategyNumber:
1203 case RTOldContainsStrategyNumber:
1206 case RTContainedByStrategyNumber:
1207 case RTOldContainedByStrategyNumber:
1224 POSTGIS_DEBUGF(4,
"[GIST] internal consistent, strategy [%d], count[%i], query[%s], key[%s]",
1225 strategy, geog_counter_internal++, gidx_to_string(query), gidx_to_string(key) );
1229 case RTOverlapStrategyNumber:
1232 case RTSameStrategyNumber:
1233 case RTContainsStrategyNumber:
1234 case RTOldContainsStrategyNumber:
1237 case RTContainedByStrategyNumber:
1238 case RTOldContainedByStrategyNumber:
1255 GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
1256 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
1258 char gidxmem[GIDX_MAX_SIZE];
1259 GIDX *query_gbox_index = (GIDX*)gidxmem;
1263 bool *recheck = (
bool *) PG_GETARG_POINTER(4);
1270 POSTGIS_DEBUG(4,
"[GIST] 'consistent' function called");
1273 if ( DatumGetPointer(PG_GETARG_DATUM(1)) == NULL )
1275 POSTGIS_DEBUG(4,
"[GIST] null query pointer (!?!), returning false");
1276 PG_RETURN_BOOL(
FALSE);
1280 if ( DatumGetPointer(entry->key) == NULL )
1282 POSTGIS_DEBUG(4,
"[GIST] null index entry, returning false");
1283 PG_RETURN_BOOL(
FALSE);
1287 if ( gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), query_gbox_index) ==
LW_FAILURE )
1289 POSTGIS_DEBUG(4,
"[GIST] null query_gbox_index!");
1290 PG_RETURN_BOOL(
FALSE);
1294 if (GIST_LEAF(entry))
1297 (GIDX*)DatumGetPointer(entry->key),
1298 query_gbox_index, strategy);
1303 (GIDX*)DatumGetPointer(entry->key),
1304 query_gbox_index, strategy);
1307 PG_RETURN_BOOL(result);
1327 struct {
unsigned value:31, sign:1; } vbits;
1328 struct {
unsigned value:29, realm:2, sign:1; } rbits;
1332 a.rbits.value = a.vbits.value >> 2;
1333 a.rbits.realm = realm;
1345 GISTENTRY *origentry = (GISTENTRY*) PG_GETARG_POINTER(0);
1346 GISTENTRY *newentry = (GISTENTRY*) PG_GETARG_POINTER(1);
1347 float *result = (
float*) PG_GETARG_POINTER(2);
1348 GIDX *gbox_index_orig, *gbox_index_new;
1349 float size_union, size_orig, edge_union, edge_orig;
1351 POSTGIS_DEBUG(4,
"[GIST] 'penalty' function called");
1353 gbox_index_orig = (GIDX*)DatumGetPointer(origentry->key);
1354 gbox_index_new = (GIDX*)DatumGetPointer(newentry->key);
1357 if ( (gbox_index_orig == NULL) && (gbox_index_new == NULL) )
1359 POSTGIS_DEBUG(4,
"[GIST] both inputs NULL! returning penalty of zero");
1361 PG_RETURN_FLOAT8(*result);
1367 *result = size_union - size_orig;
1384 *result = edge_union - edge_orig;
1400 POSTGIS_DEBUGF(4,
"[GIST] union size (%.12f), original size (%.12f), penalty (%.12f)", size_union, size_orig, *result);
1402 PG_RETURN_POINTER(result);
1411 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
1412 int *sizep = (
int *) PG_GETARG_POINTER(1);
1414 GIDX *box_cur, *box_union;
1416 POSTGIS_DEBUG(4,
"[GIST] 'union' function called");
1418 numranges = entryvec->n;
1420 box_cur = (GIDX*) DatumGetPointer(entryvec->vector[0].key);
1424 for ( i = 1; i < numranges; i++ )
1426 box_cur = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
1430 *sizep = VARSIZE(box_union);
1432 POSTGIS_DEBUGF(4,
"[GIST] union called, numranges(%i), pageunion %s", numranges, gidx_to_string(box_union));
1434 PG_RETURN_POINTER(box_union);
1444 GIDX *b1 = (GIDX*)PG_GETARG_POINTER(0);
1445 GIDX *b2 = (GIDX*)PG_GETARG_POINTER(1);
1446 bool *result = (
bool*)PG_GETARG_POINTER(2);
1448 POSTGIS_DEBUG(4,
"[GIST] 'same' function called");
1452 PG_RETURN_POINTER(result);
1461 GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
1462 Datum query_datum = PG_GETARG_DATUM(1);
1463 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
1464 #if POSTGIS_PGSQL_VERSION >= 95 1465 bool *recheck = (
bool *) PG_GETARG_POINTER(4);
1467 char query_box_mem[GIDX_MAX_SIZE];
1468 GIDX *query_box = (GIDX*)query_box_mem;
1472 POSTGIS_DEBUGF(3,
"[GIST] '%s' function called", __func__);
1475 if ( strategy != 13 )
1477 elog(ERROR,
"unrecognized strategy number: %d", strategy);
1478 PG_RETURN_FLOAT8(FLT_MAX);
1482 if ( gserialized_datum_get_gidx_p(query_datum, query_box) ==
LW_FAILURE )
1484 POSTGIS_DEBUG(2,
"[GIST] null query_gbox_index!");
1485 PG_RETURN_FLOAT8(FLT_MAX);
1488 #if POSTGIS_PGSQL_VERSION >= 95 1490 if (GIST_LEAF(entry))
1497 entry_box = (GIDX*)DatumGetPointer(entry->key);
1505 POSTGIS_DEBUGF(2,
"[GIST] '%s' got distance %g", __func__, distance);
1507 PG_RETURN_FLOAT8(distance);
1530 GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
1531 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
1532 char query_box_mem[GIDX_MAX_SIZE];
1533 GIDX *query_box = (GIDX*)query_box_mem;
1535 #if POSTGIS_PGSQL_VERSION >= 95 1536 bool *recheck = (
bool *) PG_GETARG_POINTER(4);
1541 POSTGIS_DEBUG(4,
"[GIST] 'distance' function called");
1545 if ( strategy != 13 && strategy != 20 ) {
1546 elog(ERROR,
"unrecognized strategy number: %d", strategy);
1547 PG_RETURN_FLOAT8(FLT_MAX);
1551 if ( gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), query_box) ==
LW_FAILURE )
1553 POSTGIS_DEBUG(4,
"[GIST] null query_gbox_index!");
1554 PG_RETURN_FLOAT8(FLT_MAX);
1558 entry_box = (GIDX*)DatumGetPointer(entry->key);
1560 #if POSTGIS_PGSQL_VERSION >= 95 1563 distance =
gidx_distance(entry_box, query_box, strategy == 20);
1566 if (GIST_LEAF(entry))
1570 if ( strategy == 20 )
1572 elog(ERROR,
"You need PostgreSQL 9.5.0 or higher in order to use |=| with index");
1573 PG_RETURN_FLOAT8(FLT_MAX);
1577 if (GIST_LEAF(entry))
1580 distance = (double)gidx_distance_leaf_centroid(entry_box, query_box);
1585 distance = (double)gidx_distance_node_centroid(entry_box, query_box);
1588 PG_RETURN_FLOAT8(distance);
1615 POSTGIS_DEBUGF(4,
"[GIST] checking split ratio (%d, %d)", x, y);
1616 if ( (y == 0) || (((
float)x / (
float)y) <
LIMIT_RATIO) ||
1617 (x == 0) || (((
float)y / (
float)x) <
LIMIT_RATIO) )
1626 for ( i = 0; i < dims; i++ )
1641 OffsetNumber i, maxoff;
1642 GIDX *unionL = NULL;
1643 GIDX *unionR = NULL;
1646 POSTGIS_DEBUG(4,
"[GIST] in fallback picksplit function");
1648 maxoff = entryvec->n - 1;
1650 nbytes = (maxoff + 2) *
sizeof(OffsetNumber);
1651 v->spl_left = (OffsetNumber*) palloc(nbytes);
1652 v->spl_right = (OffsetNumber*) palloc(nbytes);
1653 v->spl_nleft = v->spl_nright = 0;
1655 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
1657 GIDX *
cur = (GIDX*)DatumGetPointer(entryvec->vector[i].key);
1659 if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
1661 v->spl_left[v->spl_nleft] = i;
1674 v->spl_right[v->spl_nright] = i;
1687 if (v->spl_ldatum_exists)
1688 gidx_merge(&unionL, (GIDX*)DatumGetPointer(v->spl_ldatum));
1690 v->spl_ldatum = PointerGetDatum(unionL);
1692 if (v->spl_rdatum_exists)
1693 gidx_merge(&unionR, (GIDX*)DatumGetPointer(v->spl_rdatum));
1695 v->spl_rdatum = PointerGetDatum(unionR);
1696 v->spl_ldatum_exists = v->spl_rdatum_exists =
false;
1703 bool firstToLeft =
true;
1705 POSTGIS_DEBUG(4,
"[GIST] picksplit in constructsplit function");
1707 if (v->spl_ldatum_exists || v->spl_rdatum_exists)
1709 if (v->spl_ldatum_exists && v->spl_rdatum_exists)
1715 double sizeLR, sizeRL;
1717 gidx_merge(&LRl, (GIDX*)DatumGetPointer(v->spl_ldatum));
1718 gidx_merge(&LRr, (GIDX*)DatumGetPointer(v->spl_rdatum));
1719 gidx_merge(&RLl, (GIDX*)DatumGetPointer(v->spl_ldatum));
1720 gidx_merge(&RLr, (GIDX*)DatumGetPointer(v->spl_rdatum));
1725 POSTGIS_DEBUGF(4,
"[GIST] sizeLR / sizeRL == %.12g / %.12g", sizeLR, sizeRL);
1727 if (sizeLR > sizeRL)
1728 firstToLeft =
false;
1734 GISTENTRY oldUnion, addon;
1736 gistentryinit(oldUnion, (v->spl_ldatum_exists) ? v->spl_ldatum : v->spl_rdatum,
1737 NULL, NULL, InvalidOffsetNumber,
FALSE);
1739 gistentryinit(addon, PointerGetDatum(*union1), NULL, NULL, InvalidOffsetNumber,
FALSE);
1740 DirectFunctionCall3(
gserialized_gist_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&addon), PointerGetDatum(&p1));
1741 gistentryinit(addon, PointerGetDatum(*union2), NULL, NULL, InvalidOffsetNumber,
FALSE);
1742 DirectFunctionCall3(
gserialized_gist_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&addon), PointerGetDatum(&p2));
1744 POSTGIS_DEBUGF(4,
"[GIST] p1 / p2 == %.12g / %.12g", p1, p2);
1746 if ((v->spl_ldatum_exists && p1 > p2) || (v->spl_rdatum_exists && p1 < p2))
1747 firstToLeft =
false;
1751 POSTGIS_DEBUGF(4,
"[GIST] firstToLeft == %d", firstToLeft);
1755 v->spl_left = list1;
1756 v->spl_right = list2;
1757 v->spl_nleft = nlist1;
1758 v->spl_nright = nlist2;
1759 if (v->spl_ldatum_exists)
1760 gidx_merge(union1, (GIDX*)DatumGetPointer(v->spl_ldatum));
1761 v->spl_ldatum = PointerGetDatum(*union1);
1762 if (v->spl_rdatum_exists)
1763 gidx_merge(union2, (GIDX*)DatumGetPointer(v->spl_rdatum));
1764 v->spl_rdatum = PointerGetDatum(*union2);
1768 v->spl_left = list2;
1769 v->spl_right = list1;
1770 v->spl_nleft = nlist2;
1771 v->spl_nright = nlist1;
1772 if (v->spl_ldatum_exists)
1773 gidx_merge(union2, (GIDX*)DatumGetPointer(v->spl_ldatum));
1774 v->spl_ldatum = PointerGetDatum(*union2);
1775 if (v->spl_rdatum_exists)
1776 gidx_merge(union1, (GIDX*)DatumGetPointer(v->spl_rdatum));
1777 v->spl_rdatum = PointerGetDatum(*union1);
1780 v->spl_ldatum_exists = v->spl_rdatum_exists =
false;
1784 #define BELOW(d) (2*(d)) 1785 #define ABOVE(d) ((2*(d))+1) 1798 GistEntryVector *entryvec = (GistEntryVector*) PG_GETARG_POINTER(0);
1800 GIST_SPLITVEC *v = (GIST_SPLITVEC*) PG_GETARG_POINTER(1);
1805 OffsetNumber **list;
1808 GIDX *box_pageunion;
1811 bool all_entries_equal =
true;
1812 OffsetNumber max_offset;
1813 int nbytes, ndims_pageunion, d;
1814 int posmin = entryvec->n;
1816 POSTGIS_DEBUG(4,
"[GIST] 'picksplit' function called");
1822 max_offset = entryvec->n - 1;
1823 box_current = (GIDX*) DatumGetPointer(entryvec->vector[FirstOffsetNumber].key);
1827 for ( i = OffsetNumberNext(FirstOffsetNumber); i <= max_offset; i = OffsetNumberNext(i) )
1829 box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
1831 if ( all_entries_equal ==
true && !
gidx_equals (box_pageunion, box_current) )
1832 all_entries_equal =
false;
1837 POSTGIS_DEBUGF(3,
"[GIST] box_pageunion: %s", gidx_to_string(box_pageunion));
1840 if ( all_entries_equal )
1842 POSTGIS_DEBUG(4,
"[GIST] picksplit finds all entries equal!");
1844 PG_RETURN_POINTER(v);
1848 nbytes = (max_offset + 2) *
sizeof(OffsetNumber);
1849 ndims_pageunion = GIDX_NDIMS(box_pageunion);
1850 POSTGIS_DEBUGF(4,
"[GIST] ndims_pageunion == %d", ndims_pageunion);
1851 pos = palloc(2*ndims_pageunion *
sizeof(
int));
1852 list = palloc(2*ndims_pageunion *
sizeof(OffsetNumber*));
1853 box_union = palloc(2*ndims_pageunion *
sizeof(GIDX*));
1854 for ( d = 0; d < ndims_pageunion; d++ )
1856 list[
BELOW(d)] = (OffsetNumber*) palloc(nbytes);
1857 list[
ABOVE(d)] = (OffsetNumber*) palloc(nbytes);
1858 box_union[
BELOW(d)] = gidx_new(ndims_pageunion);
1859 box_union[
ABOVE(d)] = gidx_new(ndims_pageunion);
1869 POSTGIS_DEBUG(4,
"[GIST] 'picksplit' calculating best split axis");
1870 for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) )
1872 box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
1874 for ( d = 0; d < ndims_pageunion; d++ )
1876 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) )
1902 double *avgCenter = palloc(ndims_pageunion *
sizeof(
double));
1904 for ( d = 0; d < ndims_pageunion; d++ )
1909 POSTGIS_DEBUG(4,
"[GIST] picksplit can't find good split axis, trying center point method");
1911 for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) )
1913 box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
1914 for ( d = 0; d < ndims_pageunion; d++ )
1916 avgCenter[d] += (GIDX_GET_MAX(box_current,d) + GIDX_GET_MIN(box_current,d)) / 2.0;
1919 for ( d = 0; d < ndims_pageunion; d++ )
1921 avgCenter[d] /= max_offset;
1923 POSTGIS_DEBUGF(4,
"[GIST] picksplit average center point[%d] = %.12g", d, avgCenter[d]);
1927 for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) )
1930 box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
1932 for ( d = 0; d < ndims_pageunion; d++ )
1934 center = (GIDX_GET_MIN(box_current,d)+GIDX_GET_MAX(box_current,d))/2.0;
1935 if ( center < avgCenter[d] )
1937 else if (
FPeq(center, avgCenter[d]) )
1951 POSTGIS_DEBUG(4,
"[GIST] picksplit still cannot find a good split! just cutting the node in half");
1953 PG_RETURN_POINTER(v);
1965 for ( d = 0; d < ndims_pageunion; d++ )
1968 if ( posd < posmin )
1974 if ( direction == -1 || posmin == entryvec->n )
1977 elog(ERROR,
"Error in building split, unable to determine split direction.");
1980 POSTGIS_DEBUGF(3,
"[GIST] 'picksplit' splitting on axis %d", direction);
1983 pos[
BELOW(direction)],
1984 &(box_union[
BELOW(direction)]),
1985 list[
ABOVE(direction)],
1986 pos[
ABOVE(direction)],
1987 &(box_union[
ABOVE(direction)]) );
1989 POSTGIS_DEBUGF(4,
"[GIST] spl_ldatum: %s", gidx_to_string((GIDX*)v->spl_ldatum));
1990 POSTGIS_DEBUGF(4,
"[GIST] spl_rdatum: %s", gidx_to_string((GIDX*)v->spl_rdatum));
1992 POSTGIS_DEBUGF(4,
"[GIST] axis %d: parent range (%.12g, %.12g) left range (%.12g, %.12g), right range (%.12g, %.12g)",
1994 GIDX_GET_MIN(box_pageunion, direction), GIDX_GET_MAX(box_pageunion, direction),
1995 GIDX_GET_MIN((GIDX*)v->spl_ldatum, direction), GIDX_GET_MAX((GIDX*)v->spl_ldatum, direction),
1996 GIDX_GET_MIN((GIDX*)v->spl_rdatum, direction), GIDX_GET_MAX((GIDX*)v->spl_rdatum, direction) );
1998 PG_RETURN_POINTER(v);
2009 ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2010 errmsg(
"function gidx_in not implemented")));
2011 PG_RETURN_POINTER(NULL);
2017 GIDX *box = (GIDX *) PG_GETARG_POINTER(0);
2018 char *result = gidx_to_string(box);
2019 PG_RETURN_CSTRING(result);
static void gidx_merge(GIDX **b_union, GIDX *b_new)
static GIDX * gidx_copy(GIDX *b)
Datum gserialized_gidx_geom_contains(PG_FUNCTION_ARGS)
static float gidx_union_edge(GIDX *a, GIDX *b)
Datum gserialized_gidx_geom_overlaps(PG_FUNCTION_ARGS)
Datum gserialized_within(PG_FUNCTION_ARGS)
Datum gserialized_gist_decompress(PG_FUNCTION_ARGS)
static bool gidx_is_unknown(const GIDX *a)
Datum gserialized_gist_geog_distance(PG_FUNCTION_ARGS)
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
PG_FUNCTION_INFO_V1(gserialized_distance_nd)
uint32_t lwgeom_get_type(const LWGEOM *geom)
Return LWTYPE number.
static float gidx_volume(GIDX *a)
Datum gserialized_contains(PG_FUNCTION_ARGS)
void lwpoint_free(LWPOINT *pt)
void lwgeom_free(LWGEOM *geom)
static void gserialized_gist_picksplit_constructsplit(GIST_SPLITVEC *v, OffsetNumber *list1, int nlist1, GIDX **union1, OffsetNumber *list2, int nlist2, GIDX **union2)
Datum gserialized_gist_penalty(PG_FUNCTION_ARGS)
static void gidx_set_unknown(GIDX *a)
static float gidx_union_volume(GIDX *a, GIDX *b)
LWGEOM * lwgeom_closest_line_3d(const LWGEOM *lw1, const LWGEOM *lw2)
bool gidx_contains(GIDX *a, GIDX *b)
static int gserialized_datum_predicate(Datum gs1, Datum gs2, gidx_predicate predicate)
Support function.
double lwgeom_length_2d(const LWGEOM *geom)
Datum gserialized_gist_union(PG_FUNCTION_ARGS)
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
static bool gserialized_gist_consistent_leaf(GIDX *key, GIDX *query, StrategyNumber strategy)
double lwgeom_interpolate_point(const LWGEOM *lwin, const LWPOINT *lwpt)
Find the measure value at the location on the line closest to the point.
Datum gserialized_gidx_geog_overlaps(PG_FUNCTION_ARGS)
static void gidx_dimensionality_check(GIDX **a, GIDX **b)
static bool gidx_equals(GIDX *a, GIDX *b)
Datum gserialized_gidx_gidx_contains(PG_FUNCTION_ARGS)
GSERIALIZED * gserialized_expand(GSERIALIZED *g, double distance)
Return a GSERIALIZED with an expanded bounding box.
static void gidx_validate(GIDX *b)
static int gserialized_datum_predicate_gidx_geom(GIDX *gidx1, Datum gs2, gidx_predicate predicate)
Datum gserialized_gist_distance(PG_FUNCTION_ARGS)
Datum gserialized_gist_compress(PG_FUNCTION_ARGS)
static int gserialized_datum_predicate_geom_gidx(Datum gs1, GIDX *gidx2, gidx_predicate predicate)
Datum gserialized_distance_nd(PG_FUNCTION_ARGS)
Datum gserialized_gidx_geom_same(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.
Datum gidx_in(PG_FUNCTION_ARGS)
#define LW_TRUE
Return types for functions with status returns.
static bool gserialized_gist_picksplit_badratios(int *pos, int dims)
Datum gserialized_gist_same(PG_FUNCTION_ARGS)
static int gserialized_gist_picksplit_badratio(int x, int y)
static void gserialized_gist_picksplit_fallback(GistEntryVector *entryvec, GIST_SPLITVEC *v)
int lwpoint_getPoint4d_p(const LWPOINT *point, POINT4D *out)
Datum gserialized_gidx_geom_within(PG_FUNCTION_ARGS)
static float gidx_inter_volume(GIDX *a, GIDX *b)
Datum distance(PG_FUNCTION_ARGS)
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
static float pack_float(const float value, const int realm)
bool(* gidx_predicate)(GIDX *a, GIDX *b)
static void gserialized_gist_picksplit_addlist(OffsetNumber *list, GIDX **box_union, GIDX *box_current, int *pos, int num)
Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS)
static bool gidx_overlaps(GIDX *a, GIDX *b)
Datum gserialized_gidx_gidx_within(PG_FUNCTION_ARGS)
Datum gserialized_gidx_gidx_same(PG_FUNCTION_ARGS)
Datum gserialized_overlaps(PG_FUNCTION_ARGS)
double lwgeom_length(const LWGEOM *geom)
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Datum gserialized_gidx_gidx_overlaps(PG_FUNCTION_ARGS)
LWPOINT * lwline_get_lwpoint(const LWLINE *line, int where)
Returns freshly allocated LWPOINT that corresponds to the index where.
static float gidx_edge(GIDX *a)
LWGEOM * lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2)
Datum gserialized_gist_consistent(PG_FUNCTION_ARGS)
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
static double gidx_distance_m(const GIDX *a, const GIDX *b)
static bool gserialized_gist_consistent_internal(GIDX *key, GIDX *query, StrategyNumber strategy)
Datum gidx_out(PG_FUNCTION_ARGS)
This library is the generic geometry handling section of PostGIS.