74 #include "lwgeom_pg.h"
75 #include "gserialized_gist.h"
78 #define GIDX_MAX_NODES 256
109 float x = *(
float *)a;
110 float y = *(
float *)b;
114 return (
x >
y) ? 1 : -1;
127 uint16_t octant = 0, dim = 0x01;
130 ndims = Min(GIDX_NDIMS(
centroid), GIDX_NDIMS(inBox));
132 for (i = 0; i < ndims; i++)
135 if (GIDX_GET_MAX(
centroid, i) != FLT_MAX && GIDX_GET_MAX(inBox, i) != FLT_MAX)
137 if (GIDX_GET_MAX(inBox, i) > GIDX_GET_MAX(
centroid, i))
140 if (GIDX_GET_MIN(inBox, i) > GIDX_GET_MIN(
centroid, i))
159 GIDX *left = (GIDX *)palloc(GIDX_SIZE(ndims));
160 GIDX *right = (GIDX *)palloc(GIDX_SIZE(ndims));
163 SET_VARSIZE(left, GIDX_SIZE(ndims));
164 SET_VARSIZE(right, GIDX_SIZE(ndims));
165 cube_box->
left = left;
166 cube_box->
right = right;
168 for (i = 0; i < ndims; i++)
170 GIDX_SET_MIN(cube_box->
left, i, -1 * FLT_MAX);
171 GIDX_SET_MAX(cube_box->
left, i, FLT_MAX);
172 GIDX_SET_MIN(cube_box->
right, i, -1 * FLT_MAX);
173 GIDX_SET_MAX(cube_box->
right, i, FLT_MAX);
189 int ndims = GIDX_NDIMS(
centroid), i;
191 GIDX *left = (GIDX *)palloc(GIDX_SIZE(ndims));
192 GIDX *right = (GIDX *)palloc(GIDX_SIZE(ndims));
195 memcpy(left, cube_box->
left, VARSIZE(cube_box->
left));
196 memcpy(right, cube_box->
right, VARSIZE(cube_box->
right));
197 next_cube_box->
left = left;
198 next_cube_box->
right = right;
200 for (i = 0; i < ndims; i++)
202 if (GIDX_GET_MAX(cube_box->
left, i) != FLT_MAX && GIDX_GET_MAX(
centroid, i) != FLT_MAX)
205 GIDX_GET_MIN(next_cube_box->
right, i) = GIDX_GET_MAX(
centroid, i);
207 GIDX_GET_MAX(next_cube_box->
right, i) = GIDX_GET_MAX(
centroid, i);
212 GIDX_GET_MIN(next_cube_box->
left, i) = GIDX_GET_MIN(
centroid, i);
214 GIDX_GET_MAX(next_cube_box->
left, i) = GIDX_GET_MIN(
centroid, i);
220 return next_cube_box;
230 ndims = Min(GIDX_NDIMS(cube_box->
left), GIDX_NDIMS(query));
232 for (i = 0; i < ndims; i++)
235 if (GIDX_GET_MAX(cube_box->
left, i) != FLT_MAX && GIDX_GET_MAX(query, i) != FLT_MAX)
236 result &= (GIDX_GET_MIN(cube_box->
left, i) <= GIDX_GET_MAX(query, i)) &&
237 (GIDX_GET_MAX(cube_box->
right, i) >= GIDX_GET_MIN(query, i));
249 ndims = Min(GIDX_NDIMS(cube_box->
left), GIDX_NDIMS(query));
251 for (i = 0; i < ndims; i++)
254 if (GIDX_GET_MAX(cube_box->
left, i) != FLT_MAX && GIDX_GET_MAX(query, i) != FLT_MAX)
255 result &= (GIDX_GET_MAX(cube_box->
right, i) >= GIDX_GET_MAX(query, i)) &&
256 (GIDX_GET_MIN(cube_box->
left, i) <= GIDX_GET_MIN(query, i));
269 spgConfigOut *
cfg = (spgConfigOut *)PG_GETARG_POINTER(1);
270 Oid boxoid = InvalidOid;
271 postgis_initialize_cache(fcinfo);
272 boxoid = postgis_oid(GIDXOID);
274 cfg->prefixType = boxoid;
275 cfg->labelType = VOIDOID;
276 cfg->leafType = boxoid;
277 cfg->canReturnData =
false;
278 cfg->longValuesOK =
false;
291 spgChooseIn *in = (spgChooseIn *)PG_GETARG_POINTER(0);
292 spgChooseOut *out = (spgChooseOut *)PG_GETARG_POINTER(1);
293 GIDX *
centroid = (GIDX *)DatumGetPointer(in->prefixDatum), *box = (GIDX *)DatumGetPointer(in->leafDatum);
295 out->resultType = spgMatchNode;
296 out->result.matchNode.restDatum = PointerGetDatum(box);
315 spgPickSplitIn *in = (spgPickSplitIn *)PG_GETARG_POINTER(0);
316 spgPickSplitOut *out = (spgPickSplitOut *)PG_GETARG_POINTER(1);
318 float *lowXs, *highXs;
319 int ndims, maxdims = -1,
count[GIDX_MAX_DIM], median, dim, tuple;
321 for (dim = 0; dim < GIDX_MAX_DIM; dim++)
324 lowXs = palloc(
sizeof(
float) * in->nTuples * GIDX_MAX_DIM),
325 highXs = palloc(
sizeof(
float) * in->nTuples * GIDX_MAX_DIM);
328 for (tuple = 0; tuple < in->nTuples; tuple++)
330 box = (GIDX *)DatumGetPointer(in->datums[tuple]);
331 ndims = GIDX_NDIMS(box);
334 for (dim = 0; dim < ndims; dim++)
337 if (GIDX_GET_MAX(box, dim) != FLT_MAX)
339 lowXs[dim * in->nTuples +
count[dim]] = GIDX_GET_MIN(box, dim);
340 highXs[dim * in->nTuples +
count[dim]] = GIDX_GET_MAX(box, dim);
346 for (dim = 0; dim < maxdims; dim++)
352 centroid = (GIDX *)palloc(GIDX_SIZE(maxdims));
353 SET_VARSIZE(
centroid, GIDX_SIZE(maxdims));
355 for (dim = 0; dim < maxdims; dim++)
357 median =
count[dim] / 2;
358 GIDX_SET_MIN(
centroid, dim, lowXs[dim * in->nTuples + median]);
359 GIDX_SET_MAX(
centroid, dim, highXs[dim * in->nTuples + median]);
363 out->hasPrefix =
true;
366 out->nNodes = 0x01 << (2 * maxdims);
367 out->nodeLabels = NULL;
369 out->mapTuplesToNodes = palloc(
sizeof(
int) * in->nTuples);
370 out->leafTupleDatums = palloc(
sizeof(Datum) * in->nTuples);
376 for (tuple = 0; tuple < in->nTuples; tuple++)
378 GIDX *box = (GIDX *)DatumGetPointer(in->datums[tuple]);
381 out->leafTupleDatums[tuple] = PointerGetDatum(box);
382 out->mapTuplesToNodes[tuple] = octant;
398 spgInnerConsistentIn *in = (spgInnerConsistentIn *)PG_GETARG_POINTER(0);
399 spgInnerConsistentOut *out = (spgInnerConsistentOut *)PG_GETARG_POINTER(1);
400 MemoryContext old_ctx;
402 int *nodeNumbers, i, j;
403 void **traversalValues;
404 char gidxmem[GIDX_MAX_SIZE];
405 GIDX *
centroid, *query_gbox_index = (GIDX *)gidxmem;
407 POSTGIS_DEBUG(4,
"[SPGIST] 'inner consistent' function called");
412 out->nNodes = in->nNodes;
413 out->nodeNumbers = (
int *)palloc(
sizeof(
int) * in->nNodes);
414 for (i = 0; i < in->nNodes; i++)
415 out->nodeNumbers[i] = i;
425 old_ctx = MemoryContextSwitchTo(in->traversalMemoryContext);
427 centroid = (GIDX *)DatumGetPointer(in->prefixDatum);
433 if (in->traversalValue)
434 cube_box = in->traversalValue;
440 nodeNumbers = (
int *)palloc(
sizeof(
int) * in->nNodes);
441 traversalValues = (
void **)palloc(
sizeof(
void *) * in->nNodes);
443 for (i = 0; i < in->nNodes; i++)
448 for (j = 0; j < in->nkeys; j++)
450 StrategyNumber strategy = in->scankeys[j].sk_strategy;
451 Datum query = in->scankeys[j].sk_argument;
454 if (DatumGetPointer(query) == NULL)
456 POSTGIS_DEBUG(4,
"[SPGIST] null query pointer (!?!)");
462 if (gserialized_datum_get_gidx_p(query, query_gbox_index) ==
LW_FAILURE)
464 POSTGIS_DEBUG(4,
"[SPGIST] null query_gbox_index!");
473 flag =
overlapND(next_cube_box, query_gbox_index);
478 flag =
containND(next_cube_box, query_gbox_index);
482 elog(ERROR,
"unrecognized strategy: %d", strategy);
492 traversalValues[out->nNodes] = next_cube_box;
493 nodeNumbers[out->nNodes] = i;
502 pfree(next_cube_box);
507 out->nodeNumbers = (
int *)palloc(
sizeof(
int) * out->nNodes);
508 out->traversalValues = (
void **)palloc(
sizeof(
void *) * out->nNodes);
509 for (i = 0; i < out->nNodes; i++)
511 out->nodeNumbers[i] = nodeNumbers[i];
512 out->traversalValues[i] = traversalValues[i];
515 pfree(traversalValues);
518 MemoryContextSwitchTo(old_ctx);
530 spgLeafConsistentIn *in = (spgLeafConsistentIn *)PG_GETARG_POINTER(0);
531 spgLeafConsistentOut *out = (spgLeafConsistentOut *)PG_GETARG_POINTER(1);
534 char gidxmem[GIDX_MAX_SIZE];
535 GIDX *leaf = (GIDX *)DatumGetPointer(in->leafDatum), *query_gbox_index = (GIDX *)gidxmem;
537 POSTGIS_DEBUG(4,
"[SPGIST] 'leaf consistent' function called");
540 out->recheck =
false;
543 out->leafValue = in->leafDatum;
546 for (i = 0; i < in->nkeys; i++)
548 StrategyNumber strategy = in->scankeys[i].sk_strategy;
549 Datum query = in->scankeys[i].sk_argument;
552 if (DatumGetPointer(query) == NULL)
554 POSTGIS_DEBUG(4,
"[SPGIST] null query pointer (!?!)");
559 if (gserialized_datum_get_gidx_p(query, query_gbox_index) ==
LW_FAILURE)
561 POSTGIS_DEBUG(4,
"[SPGIST] null query_gbox_index!");
584 elog(ERROR,
"unrecognized strategy: %d", strategy);
592 PG_RETURN_BOOL(flag);
599 char gidxmem[GIDX_MAX_SIZE];
600 GIDX *result = (GIDX *)gidxmem;
603 POSTGIS_DEBUG(4,
"[SPGIST] 'compress' function called");
608 POSTGIS_DEBUG(4,
"[SPGIST] null entry (!?!)");
614 if (gserialized_datum_get_gidx_p(PG_GETARG_DATUM(0), result) ==
LW_FAILURE)
616 POSTGIS_DEBUG(4,
"[SPGIST] empty geometry!");
620 POSTGIS_DEBUGF(4,
"[SPGIST] got GIDX: %s", gidx_to_string(result));
624 for (i = 0; i < GIDX_NDIMS(result); i++)
626 if (!isfinite(GIDX_GET_MAX(result, i)) || !isfinite(GIDX_GET_MIN(result, i)))
629 PG_RETURN_POINTER(result);
void gidx_set_unknown(GIDX *a)
GIDX * gidx_copy(GIDX *b)
bool gidx_contains(GIDX *a, GIDX *b)
bool gidx_equals(GIDX *a, GIDX *b)
void gidx_validate(GIDX *b)
bool gidx_overlaps(GIDX *a, GIDX *b)
#define SPGOverlapStrategyNumber
#define SPGSameStrategyNumber
#define SPGContainedByStrategyNumber
#define SPGContainsStrategyNumber
static bool overlapND(CubeGIDX *cube_box, GIDX *query)
Datum gserialized_spgist_compress_nd(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(gserialized_spgist_config_nd)
static CubeGIDX * nextCubeBox(CubeGIDX *cube_box, GIDX *centroid, uint16_t octant)
Datum gserialized_spgist_inner_consistent_nd(PG_FUNCTION_ARGS)
static uint16_t getOctant(GIDX *centroid, GIDX *inBox)
Datum gserialized_spgist_config_nd(PG_FUNCTION_ARGS)
Datum gserialized_spgist_choose_nd(PG_FUNCTION_ARGS)
static CubeGIDX * initCubeBox(int ndims)
Datum gserialized_spgist_picksplit_nd(PG_FUNCTION_ARGS)
static bool containND(CubeGIDX *cube_box, GIDX *query)
static int compareFloats(const void *a, const void *b)
Datum gserialized_spgist_leaf_consistent_nd(PG_FUNCTION_ARGS)
Datum centroid(PG_FUNCTION_ARGS)