1/*-------------------------------------------------------------------------
4 * implementation of quad tree over points for SP-GiST
7 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/access/spgist/spgquadtreeproc.c
13 *-------------------------------------------------------------------------
23#include "utils/fmgrprotos.h"
29 /* spgConfigIn *cfgin = (spgConfigIn *) PG_GETARG_POINTER(0); */
33 cfg->
labelType = VOIDOID;
/* we don't need node labels */
39 #define SPTEST(f, x, y) \
40 DatumGetBool(DirectFunctionCall2(f, PointPGetDatum(x), PointPGetDatum(y)))
43 * Determine which quadrant a point falls into, relative to the centroid.
45 * Quadrants are identified like this:
51 * Points on one of the axes are taken to lie in the lowest-numbered
77 elog(
ERROR,
"getQuadrant: impossible case");
81/* Returns bounding box of a given quadrant inside given bounding box */
91 result->
low = *centroid;
95 result->
high.
y = centroid->
y;
96 result->
low.
x = centroid->
x;
100 result->
high = *centroid;
104 result->
high.
x = centroid->
x;
107 result->
low.
y = centroid->
y;
125 /* nodeN will be set by core */
153 return (pa->
x > pb->
x) ? 1 : -1;
164 return (pa->
y > pb->
y) ? 1 : -1;
177 /* Use the median values of x and y as the centroid point */
184 centroid =
palloc(
sizeof(*centroid));
187 centroid->
x = sorted[in->
nTuples >> 1]->
x;
189 centroid->
y = sorted[in->
nTuples >> 1]->
y;
191 /* Use the average values of x and y as the centroid point */
192 centroid =
palloc0(
sizeof(*centroid));
208 out->
nodeLabels = NULL;
/* we don't need node labels */
241 * When ordering scan keys are specified, we've to calculate distance for
242 * them. In order to do that, we need calculate bounding boxes for all
243 * children nodes. Calculation of those bounding boxes on non-zero level
244 * require knowledge of bounding box of upper node. So, we save bounding
245 * boxes to traversalValues.
256 infbbox.
high.
x = inf;
257 infbbox.
high.
y = inf;
258 infbbox.
low.
x = -inf;
259 infbbox.
low.
y = -inf;
271 /* Report that all nodes should be visited */
282 /* Use parent quadrant box as traversalValue */
297 /* "which" is a bitmask of quadrants that satisfy all constraints */
298 which = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
309 which &= (1 << 3) | (1 << 4);
313 which &= (1 << 1) | (1 << 2);
321 which &= (1 << 2) | (1 << 3);
326 which &= (1 << 1) | (1 << 4);
331 * For this operator, the query is a box not a point. We
332 * cheat to the extent of assuming that DatumGetPointP won't
333 * do anything that would be bad for a pointer-to-box.
341 /* centroid is in box, so all quadrants are OK */
345 /* identify quadrant(s) containing all corners of box */
355 p.
x = boxQuery->
low.
x;
362 elog(
ERROR,
"unrecognized strategy number: %d",
368 break;
/* no need to consider remaining conditions */
372 for (
i = 0;
i < 4; ++
i)
375 /* We must descend into the quadrant(s) identified by which */
379 for (
i = 1;
i <= 4;
i++)
381 if (which & (1 <<
i))
415 /* all tests are exact */
418 /* leafDatum is what it is... */
421 /* Perform the required comparison(s) */
449 * For this operator, the query is a box not a point. We
450 * cheat to the extent of assuming that DatumGetPointP won't
451 * do anything that would be bad for a pointer-to-box.
456 elog(
ERROR,
"unrecognized strategy number: %d",
466 /* ok, it passes -> let's compute the distances */
static float8 get_float8_infinity(void)
#define DirectFunctionCall2(func, arg1, arg2)
#define PG_GETARG_POINTER(n)
#define PG_RETURN_BOOL(x)
static Point * DatumGetPointP(Datum X)
static Datum PointPGetDatum(const Point *X)
static BOX * DatumGetBoxP(Datum X)
static Datum BoxPGetDatum(const BOX *X)
Datum point_eq(PG_FUNCTION_ARGS)
Datum point_above(PG_FUNCTION_ARGS)
Datum box_contain_pt(PG_FUNCTION_ARGS)
Datum point_below(PG_FUNCTION_ARGS)
Datum point_horiz(PG_FUNCTION_ARGS)
Datum point_left(PG_FUNCTION_ARGS)
Datum point_right(PG_FUNCTION_ARGS)
Datum point_vert(PG_FUNCTION_ARGS)
Assert(PointerIsAligned(start, uint64))
void * palloc0(Size size)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
#define qsort(a, b, c, d)
static bool DatumGetBool(Datum X)
static Datum PointerGetDatum(const void *X)
static int x_cmp(const void *a, const void *b)
static int y_cmp(const void *a, const void *b)
BOX * box_copy(BOX *orig)
double * spg_key_orderbys_distances(Datum key, bool isLeaf, ScanKey orderbys, int norderbys)
Datum spg_quad_picksplit(PG_FUNCTION_ARGS)
Datum spg_quad_choose(PG_FUNCTION_ARGS)
static int16 getQuadrant(Point *centroid, Point *tst)
Datum spg_quad_config(PG_FUNCTION_ARGS)
Datum spg_quad_leaf_consistent(PG_FUNCTION_ARGS)
Datum spg_quad_inner_consistent(PG_FUNCTION_ARGS)
static BOX * getQuadrantArea(BOX *bbox, Point *centroid, int quadrant)
#define RTLeftStrategyNumber
#define RTRightStrategyNumber
#define RTSameStrategyNumber
#define RTOldBelowStrategyNumber
#define RTBelowStrategyNumber
#define RTOldAboveStrategyNumber
#define RTAboveStrategyNumber
#define RTContainedByStrategyNumber
StrategyNumber sk_strategy
spgChooseResultType resultType
struct spgChooseOut::@53::@54 matchNode
union spgChooseOut::@53 result
MemoryContext traversalMemoryContext