2011-12-17 22:41:16 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* spgquadtreeproc.c
|
|
|
|
* implementation of quad tree over points for SP-GiST
|
|
|
|
*
|
|
|
|
*
|
2019-01-02 18:44:25 +01:00
|
|
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
|
2011-12-17 22:41:16 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/backend/access/spgist/spgquadtreeproc.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "access/spgist.h"
|
2018-09-19 00:54:10 +02:00
|
|
|
#include "access/spgist_private.h"
|
2019-11-12 04:00:16 +01:00
|
|
|
#include "access/stratnum.h"
|
2011-12-17 22:41:16 +01:00
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "utils/builtins.h"
|
2018-09-19 00:54:10 +02:00
|
|
|
#include "utils/float.h"
|
2011-12-17 22:41:16 +01:00
|
|
|
#include "utils/geo_decls.h"
|
|
|
|
|
|
|
|
Datum
|
|
|
|
spg_quad_config(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* spgConfigIn *cfgin = (spgConfigIn *) PG_GETARG_POINTER(0); */
|
|
|
|
spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1);
|
|
|
|
|
|
|
|
cfg->prefixType = POINTOID;
|
|
|
|
cfg->labelType = VOIDOID; /* we don't need node labels */
|
2011-12-19 20:58:41 +01:00
|
|
|
cfg->canReturnData = true;
|
2011-12-17 22:41:16 +01:00
|
|
|
cfg->longValuesOK = false;
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SPTEST(f, x, y) \
|
|
|
|
DatumGetBool(DirectFunctionCall2(f, PointPGetDatum(x), PointPGetDatum(y)))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine which quadrant a point falls into, relative to the centroid.
|
|
|
|
*
|
|
|
|
* Quadrants are identified like this:
|
|
|
|
*
|
|
|
|
* 4 | 1
|
|
|
|
* ----+-----
|
|
|
|
* 3 | 2
|
|
|
|
*
|
|
|
|
* Points on one of the axes are taken to lie in the lowest-numbered
|
|
|
|
* adjacent quadrant.
|
|
|
|
*/
|
2012-06-25 00:51:46 +02:00
|
|
|
static int16
|
2011-12-17 22:41:16 +01:00
|
|
|
getQuadrant(Point *centroid, Point *tst)
|
|
|
|
{
|
|
|
|
if ((SPTEST(point_above, tst, centroid) ||
|
|
|
|
SPTEST(point_horiz, tst, centroid)) &&
|
|
|
|
(SPTEST(point_right, tst, centroid) ||
|
|
|
|
SPTEST(point_vert, tst, centroid)))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (SPTEST(point_below, tst, centroid) &&
|
|
|
|
(SPTEST(point_right, tst, centroid) ||
|
|
|
|
SPTEST(point_vert, tst, centroid)))
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
if ((SPTEST(point_below, tst, centroid) ||
|
|
|
|
SPTEST(point_horiz, tst, centroid)) &&
|
|
|
|
SPTEST(point_left, tst, centroid))
|
|
|
|
return 3;
|
|
|
|
|
|
|
|
if (SPTEST(point_above, tst, centroid) &&
|
|
|
|
SPTEST(point_left, tst, centroid))
|
|
|
|
return 4;
|
|
|
|
|
|
|
|
elog(ERROR, "getQuadrant: impossible case");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:54:10 +02:00
|
|
|
/* Returns bounding box of a given quadrant inside given bounding box */
|
|
|
|
static BOX *
|
|
|
|
getQuadrantArea(BOX *bbox, Point *centroid, int quadrant)
|
|
|
|
{
|
|
|
|
BOX *result = (BOX *) palloc(sizeof(BOX));
|
|
|
|
|
|
|
|
switch (quadrant)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
result->high = bbox->high;
|
|
|
|
result->low = *centroid;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
result->high.x = bbox->high.x;
|
|
|
|
result->high.y = centroid->y;
|
|
|
|
result->low.x = centroid->x;
|
|
|
|
result->low.y = bbox->low.y;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
result->high = *centroid;
|
|
|
|
result->low = bbox->low;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
result->high.x = centroid->x;
|
|
|
|
result->high.y = bbox->high.y;
|
|
|
|
result->low.x = bbox->low.x;
|
|
|
|
result->low.y = centroid->y;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2011-12-17 22:41:16 +01:00
|
|
|
|
|
|
|
Datum
|
|
|
|
spg_quad_choose(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
|
|
|
|
spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
|
|
|
|
Point *inPoint = DatumGetPointP(in->datum),
|
|
|
|
*centroid;
|
|
|
|
|
|
|
|
if (in->allTheSame)
|
|
|
|
{
|
|
|
|
out->resultType = spgMatchNode;
|
|
|
|
/* nodeN will be set by core */
|
|
|
|
out->result.matchNode.levelAdd = 0;
|
|
|
|
out->result.matchNode.restDatum = PointPGetDatum(inPoint);
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
Assert(in->hasPrefix);
|
|
|
|
centroid = DatumGetPointP(in->prefixDatum);
|
|
|
|
|
|
|
|
Assert(in->nNodes == 4);
|
|
|
|
|
|
|
|
out->resultType = spgMatchNode;
|
|
|
|
out->result.matchNode.nodeN = getQuadrant(centroid, inPoint) - 1;
|
|
|
|
out->result.matchNode.levelAdd = 0;
|
|
|
|
out->result.matchNode.restDatum = PointPGetDatum(inPoint);
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_MEDIAN
|
|
|
|
static int
|
|
|
|
x_cmp(const void *a, const void *b, void *arg)
|
|
|
|
{
|
|
|
|
Point *pa = *(Point **) a;
|
|
|
|
Point *pb = *(Point **) b;
|
|
|
|
|
|
|
|
if (pa->x == pb->x)
|
|
|
|
return 0;
|
|
|
|
return (pa->x > pb->x) ? 1 : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
y_cmp(const void *a, const void *b, void *arg)
|
|
|
|
{
|
|
|
|
Point *pa = *(Point **) a;
|
|
|
|
Point *pb = *(Point **) b;
|
|
|
|
|
|
|
|
if (pa->y == pb->y)
|
|
|
|
return 0;
|
|
|
|
return (pa->y > pb->y) ? 1 : -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Datum
|
|
|
|
spg_quad_picksplit(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
|
|
|
|
spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
|
|
|
|
int i;
|
|
|
|
Point *centroid;
|
|
|
|
|
|
|
|
#ifdef USE_MEDIAN
|
|
|
|
/* Use the median values of x and y as the centroid point */
|
|
|
|
Point **sorted;
|
|
|
|
|
|
|
|
sorted = palloc(sizeof(*sorted) * in->nTuples);
|
|
|
|
for (i = 0; i < in->nTuples; i++)
|
|
|
|
sorted[i] = DatumGetPointP(in->datums[i]);
|
|
|
|
|
|
|
|
centroid = palloc(sizeof(*centroid));
|
|
|
|
|
|
|
|
qsort(sorted, in->nTuples, sizeof(*sorted), x_cmp);
|
|
|
|
centroid->x = sorted[in->nTuples >> 1]->x;
|
|
|
|
qsort(sorted, in->nTuples, sizeof(*sorted), y_cmp);
|
|
|
|
centroid->y = sorted[in->nTuples >> 1]->y;
|
|
|
|
#else
|
|
|
|
/* Use the average values of x and y as the centroid point */
|
|
|
|
centroid = palloc0(sizeof(*centroid));
|
|
|
|
|
|
|
|
for (i = 0; i < in->nTuples; i++)
|
|
|
|
{
|
|
|
|
centroid->x += DatumGetPointP(in->datums[i])->x;
|
|
|
|
centroid->y += DatumGetPointP(in->datums[i])->y;
|
|
|
|
}
|
|
|
|
|
|
|
|
centroid->x /= in->nTuples;
|
|
|
|
centroid->y /= in->nTuples;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
out->hasPrefix = true;
|
|
|
|
out->prefixDatum = PointPGetDatum(centroid);
|
|
|
|
|
|
|
|
out->nNodes = 4;
|
|
|
|
out->nodeLabels = NULL; /* we don't need node labels */
|
|
|
|
|
|
|
|
out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
|
|
|
|
out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);
|
|
|
|
|
|
|
|
for (i = 0; i < in->nTuples; i++)
|
|
|
|
{
|
|
|
|
Point *p = DatumGetPointP(in->datums[i]);
|
|
|
|
int quadrant = getQuadrant(centroid, p) - 1;
|
|
|
|
|
|
|
|
out->leafTupleDatums[i] = PointPGetDatum(p);
|
|
|
|
out->mapTuplesToNodes[i] = quadrant;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
spg_quad_inner_consistent(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
|
|
|
|
spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
|
2012-03-11 00:36:49 +01:00
|
|
|
Point *centroid;
|
2018-09-19 00:54:10 +02:00
|
|
|
BOX infbbox;
|
|
|
|
BOX *bbox = NULL;
|
2012-03-11 00:36:49 +01:00
|
|
|
int which;
|
|
|
|
int i;
|
2011-12-17 22:41:16 +01:00
|
|
|
|
|
|
|
Assert(in->hasPrefix);
|
|
|
|
centroid = DatumGetPointP(in->prefixDatum);
|
|
|
|
|
2018-09-19 00:54:10 +02:00
|
|
|
/*
|
|
|
|
* When ordering scan keys are specified, we've to calculate distance for
|
|
|
|
* them. In order to do that, we need calculate bounding boxes for all
|
|
|
|
* children nodes. Calculation of those bounding boxes on non-zero level
|
|
|
|
* require knowledge of bounding box of upper node. So, we save bounding
|
|
|
|
* boxes to traversalValues.
|
|
|
|
*/
|
|
|
|
if (in->norderbys > 0)
|
|
|
|
{
|
|
|
|
out->distances = (double **) palloc(sizeof(double *) * in->nNodes);
|
|
|
|
out->traversalValues = (void **) palloc(sizeof(void *) * in->nNodes);
|
|
|
|
|
|
|
|
if (in->level == 0)
|
|
|
|
{
|
|
|
|
double inf = get_float8_infinity();
|
|
|
|
|
|
|
|
infbbox.high.x = inf;
|
|
|
|
infbbox.high.y = inf;
|
|
|
|
infbbox.low.x = -inf;
|
|
|
|
infbbox.low.y = -inf;
|
|
|
|
bbox = &infbbox;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bbox = in->traversalValue;
|
|
|
|
Assert(bbox);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-17 22:41:16 +01:00
|
|
|
if (in->allTheSame)
|
|
|
|
{
|
|
|
|
/* Report that all nodes should be visited */
|
|
|
|
out->nNodes = in->nNodes;
|
|
|
|
out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
|
|
|
|
for (i = 0; i < in->nNodes; i++)
|
2018-09-19 00:54:10 +02:00
|
|
|
{
|
2011-12-17 22:41:16 +01:00
|
|
|
out->nodeNumbers[i] = i;
|
2018-09-19 00:54:10 +02:00
|
|
|
|
|
|
|
if (in->norderbys > 0)
|
|
|
|
{
|
2018-09-27 22:29:50 +02:00
|
|
|
MemoryContext oldCtx = MemoryContextSwitchTo(in->traversalMemoryContext);
|
2018-09-19 00:54:10 +02:00
|
|
|
|
|
|
|
/* Use parent quadrant box as traversalValue */
|
|
|
|
BOX *quadrant = box_copy(bbox);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldCtx);
|
|
|
|
|
|
|
|
out->traversalValues[i] = quadrant;
|
2018-09-27 22:29:50 +02:00
|
|
|
out->distances[i] = spg_key_orderbys_distances(BoxPGetDatum(quadrant), false,
|
2018-09-19 00:54:10 +02:00
|
|
|
in->orderbys, in->norderbys);
|
|
|
|
}
|
|
|
|
}
|
2011-12-17 22:41:16 +01:00
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
Assert(in->nNodes == 4);
|
|
|
|
|
2012-03-11 00:36:49 +01:00
|
|
|
/* "which" is a bitmask of quadrants that satisfy all constraints */
|
|
|
|
which = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
|
|
|
|
|
|
|
|
for (i = 0; i < in->nkeys; i++)
|
2011-12-17 22:41:16 +01:00
|
|
|
{
|
2012-03-11 00:36:49 +01:00
|
|
|
Point *query = DatumGetPointP(in->scankeys[i].sk_argument);
|
|
|
|
BOX *boxQuery;
|
|
|
|
|
|
|
|
switch (in->scankeys[i].sk_strategy)
|
|
|
|
{
|
|
|
|
case RTLeftStrategyNumber:
|
|
|
|
if (SPTEST(point_right, centroid, query))
|
|
|
|
which &= (1 << 3) | (1 << 4);
|
|
|
|
break;
|
|
|
|
case RTRightStrategyNumber:
|
|
|
|
if (SPTEST(point_left, centroid, query))
|
|
|
|
which &= (1 << 1) | (1 << 2);
|
|
|
|
break;
|
|
|
|
case RTSameStrategyNumber:
|
|
|
|
which &= (1 << getQuadrant(centroid, query));
|
|
|
|
break;
|
|
|
|
case RTBelowStrategyNumber:
|
|
|
|
if (SPTEST(point_above, centroid, query))
|
|
|
|
which &= (1 << 2) | (1 << 3);
|
|
|
|
break;
|
|
|
|
case RTAboveStrategyNumber:
|
|
|
|
if (SPTEST(point_below, centroid, query))
|
|
|
|
which &= (1 << 1) | (1 << 4);
|
|
|
|
break;
|
|
|
|
case RTContainedByStrategyNumber:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For this operator, the query is a box not a point. We
|
|
|
|
* cheat to the extent of assuming that DatumGetPointP won't
|
|
|
|
* do anything that would be bad for a pointer-to-box.
|
|
|
|
*/
|
|
|
|
boxQuery = DatumGetBoxP(in->scankeys[i].sk_argument);
|
|
|
|
|
|
|
|
if (DatumGetBool(DirectFunctionCall2(box_contain_pt,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
PointerGetDatum(boxQuery),
|
|
|
|
PointerGetDatum(centroid))))
|
2011-12-17 22:41:16 +01:00
|
|
|
{
|
2012-03-11 00:36:49 +01:00
|
|
|
/* centroid is in box, so all quadrants are OK */
|
2011-12-17 22:41:16 +01:00
|
|
|
}
|
2012-03-11 00:36:49 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* identify quadrant(s) containing all corners of box */
|
|
|
|
Point p;
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
p = boxQuery->low;
|
|
|
|
r |= 1 << getQuadrant(centroid, &p);
|
|
|
|
p.y = boxQuery->high.y;
|
|
|
|
r |= 1 << getQuadrant(centroid, &p);
|
|
|
|
p = boxQuery->high;
|
|
|
|
r |= 1 << getQuadrant(centroid, &p);
|
|
|
|
p.x = boxQuery->low.x;
|
|
|
|
r |= 1 << getQuadrant(centroid, &p);
|
|
|
|
|
|
|
|
which &= r;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized strategy number: %d",
|
|
|
|
in->scankeys[i].sk_strategy);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (which == 0)
|
|
|
|
break; /* no need to consider remaining conditions */
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:54:10 +02:00
|
|
|
out->levelAdds = palloc(sizeof(int) * 4);
|
|
|
|
for (i = 0; i < 4; ++i)
|
|
|
|
out->levelAdds[i] = 1;
|
|
|
|
|
2012-03-11 00:36:49 +01:00
|
|
|
/* We must descend into the quadrant(s) identified by which */
|
|
|
|
out->nodeNumbers = (int *) palloc(sizeof(int) * 4);
|
|
|
|
out->nNodes = 0;
|
2018-09-19 00:54:10 +02:00
|
|
|
|
2012-03-11 00:36:49 +01:00
|
|
|
for (i = 1; i <= 4; i++)
|
|
|
|
{
|
|
|
|
if (which & (1 << i))
|
2018-09-19 00:54:10 +02:00
|
|
|
{
|
|
|
|
out->nodeNumbers[out->nNodes] = i - 1;
|
|
|
|
|
|
|
|
if (in->norderbys > 0)
|
|
|
|
{
|
2018-09-27 22:29:50 +02:00
|
|
|
MemoryContext oldCtx = MemoryContextSwitchTo(in->traversalMemoryContext);
|
2018-09-19 00:54:10 +02:00
|
|
|
BOX *quadrant = getQuadrantArea(bbox, centroid, i);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldCtx);
|
|
|
|
|
|
|
|
out->traversalValues[out->nNodes] = quadrant;
|
|
|
|
|
2018-09-27 22:29:50 +02:00
|
|
|
out->distances[out->nNodes] = spg_key_orderbys_distances(BoxPGetDatum(quadrant), false,
|
2018-09-19 00:54:10 +02:00
|
|
|
in->orderbys, in->norderbys);
|
|
|
|
}
|
|
|
|
|
|
|
|
out->nNodes++;
|
|
|
|
}
|
2011-12-17 22:41:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
spg_quad_leaf_consistent(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0);
|
|
|
|
spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1);
|
|
|
|
Point *datum = DatumGetPointP(in->leafDatum);
|
|
|
|
bool res;
|
2012-03-11 00:36:49 +01:00
|
|
|
int i;
|
2011-12-17 22:41:16 +01:00
|
|
|
|
|
|
|
/* all tests are exact */
|
|
|
|
out->recheck = false;
|
|
|
|
|
2011-12-19 20:58:41 +01:00
|
|
|
/* leafDatum is what it is... */
|
|
|
|
out->leafValue = in->leafDatum;
|
|
|
|
|
2012-03-11 00:36:49 +01:00
|
|
|
/* Perform the required comparison(s) */
|
|
|
|
res = true;
|
|
|
|
for (i = 0; i < in->nkeys; i++)
|
2011-12-17 22:41:16 +01:00
|
|
|
{
|
2012-03-11 00:36:49 +01:00
|
|
|
Point *query = DatumGetPointP(in->scankeys[i].sk_argument);
|
|
|
|
|
|
|
|
switch (in->scankeys[i].sk_strategy)
|
|
|
|
{
|
|
|
|
case RTLeftStrategyNumber:
|
|
|
|
res = SPTEST(point_left, datum, query);
|
|
|
|
break;
|
|
|
|
case RTRightStrategyNumber:
|
|
|
|
res = SPTEST(point_right, datum, query);
|
|
|
|
break;
|
|
|
|
case RTSameStrategyNumber:
|
|
|
|
res = SPTEST(point_eq, datum, query);
|
|
|
|
break;
|
|
|
|
case RTBelowStrategyNumber:
|
|
|
|
res = SPTEST(point_below, datum, query);
|
|
|
|
break;
|
|
|
|
case RTAboveStrategyNumber:
|
|
|
|
res = SPTEST(point_above, datum, query);
|
|
|
|
break;
|
|
|
|
case RTContainedByStrategyNumber:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For this operator, the query is a box not a point. We
|
|
|
|
* cheat to the extent of assuming that DatumGetPointP won't
|
|
|
|
* do anything that would be bad for a pointer-to-box.
|
|
|
|
*/
|
|
|
|
res = SPTEST(box_contain_pt, query, datum);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized strategy number: %d",
|
|
|
|
in->scankeys[i].sk_strategy);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!res)
|
2011-12-17 22:41:16 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:54:10 +02:00
|
|
|
if (res && in->norderbys > 0)
|
|
|
|
/* ok, it passes -> let's compute the distances */
|
2018-09-27 22:25:22 +02:00
|
|
|
out->distances = spg_key_orderbys_distances(in->leafDatum, true,
|
2018-09-19 00:54:10 +02:00
|
|
|
in->orderbys, in->norderbys);
|
|
|
|
|
2011-12-17 22:41:16 +01:00
|
|
|
PG_RETURN_BOOL(res);
|
|
|
|
}
|