PostgreSQL Source Code git master
Loading...
Searching...
No Matches
spgquadtreeproc.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * spgquadtreeproc.c
4 * implementation of quad tree over points for SP-GiST
5 *
6 *
7 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 * IDENTIFICATION
11 * src/backend/access/spgist/spgquadtreeproc.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16#include "postgres.h"
17
18#include "access/spgist.h"
20#include "access/stratnum.h"
21#include "catalog/pg_type.h"
22#include "utils/float.h"
23#include "utils/fmgrprotos.h"
24#include "utils/geo_decls.h"
25
28{
29#ifdef NOT_USED
31#endif
33
34 cfg->prefixType = POINTOID;
35 cfg->labelType = VOIDOID; /* we don't need node labels */
36 cfg->canReturnData = true;
37 cfg->longValuesOK = false;
39}
40
41#define SPTEST(f, x, y) \
42 DatumGetBool(DirectFunctionCall2(f, PointPGetDatum(x), PointPGetDatum(y)))
43
44/*
45 * Determine which quadrant a point falls into, relative to the centroid.
46 *
47 * Quadrants are identified like this:
48 *
49 * 4 | 1
50 * ----+-----
51 * 3 | 2
52 *
53 * Points on one of the axes are taken to lie in the lowest-numbered
54 * adjacent quadrant.
55 */
56static int16
58{
63 return 1;
64
68 return 2;
69
73 return 3;
74
77 return 4;
78
79 elog(ERROR, "getQuadrant: impossible case");
80 return 0;
81}
82
83/* Returns bounding box of a given quadrant inside given bounding box */
84static BOX *
86{
87 BOX *result = palloc_object(BOX);
88
89 switch (quadrant)
90 {
91 case 1:
92 result->high = bbox->high;
93 result->low = *centroid;
94 break;
95 case 2:
96 result->high.x = bbox->high.x;
97 result->high.y = centroid->y;
98 result->low.x = centroid->x;
99 result->low.y = bbox->low.y;
100 break;
101 case 3:
102 result->high = *centroid;
103 result->low = bbox->low;
104 break;
105 case 4:
106 result->high.x = centroid->x;
107 result->high.y = bbox->high.y;
108 result->low.x = bbox->low.x;
109 result->low.y = centroid->y;
110 break;
111 }
112
113 return result;
114}
115
116Datum
118{
122 *centroid;
123
124 if (in->allTheSame)
125 {
127 /* nodeN will be set by core */
128 out->result.matchNode.levelAdd = 0;
131 }
132
133 Assert(in->hasPrefix);
135
136 Assert(in->nNodes == 4);
137
140 out->result.matchNode.levelAdd = 0;
142
144}
145
146#ifdef USE_MEDIAN
147static int
148x_cmp(const void *a, const void *b, void *arg)
149{
150 Point *pa = *(Point *const *) a;
151 Point *pb = *(Point *const *) b;
152
153 if (pa->x == pb->x)
154 return 0;
155 return (pa->x > pb->x) ? 1 : -1;
156}
157
158static int
159y_cmp(const void *a, const void *b, void *arg)
160{
161 Point *pa = *(Point *const *) a;
162 Point *pb = *(Point *const *) b;
163
164 if (pa->y == pb->y)
165 return 0;
166 return (pa->y > pb->y) ? 1 : -1;
167}
168#endif
169
170Datum
172{
175 int i;
177
178#ifdef USE_MEDIAN
179 /* Use the median values of x and y as the centroid point */
180 Point **sorted;
181
182 sorted = palloc_array(Point *, in->nTuples);
183 for (i = 0; i < in->nTuples; i++)
184 sorted[i] = DatumGetPointP(in->datums[i]);
185
187
188 qsort(sorted, in->nTuples, sizeof(*sorted), x_cmp);
189 centroid->x = sorted[in->nTuples >> 1]->x;
190 qsort(sorted, in->nTuples, sizeof(*sorted), y_cmp);
191 centroid->y = sorted[in->nTuples >> 1]->y;
192#else
193 /* Use the average values of x and y as the centroid point */
195
196 for (i = 0; i < in->nTuples; i++)
197 {
198 centroid->x += DatumGetPointP(in->datums[i])->x;
199 centroid->y += DatumGetPointP(in->datums[i])->y;
200 }
201
202 centroid->x /= in->nTuples;
203 centroid->y /= in->nTuples;
204#endif
205
206 out->hasPrefix = true;
208
209 out->nNodes = 4;
210 out->nodeLabels = NULL; /* we don't need node labels */
211
212 out->mapTuplesToNodes = palloc_array(int, in->nTuples);
214
215 for (i = 0; i < in->nTuples; i++)
216 {
217 Point *p = DatumGetPointP(in->datums[i]);
218 int quadrant = getQuadrant(centroid, p) - 1;
219
222 }
223
225}
226
227
228Datum
230{
234 BOX infbbox;
235 BOX *bbox = NULL;
236 int which;
237 int i;
238
239 Assert(in->hasPrefix);
241
242 /*
243 * When ordering scan keys are specified, we've to calculate distance for
244 * them. In order to do that, we need calculate bounding boxes for all
245 * children nodes. Calculation of those bounding boxes on non-zero level
246 * require knowledge of bounding box of upper node. So, we save bounding
247 * boxes to traversalValues.
248 */
249 if (in->norderbys > 0)
250 {
251 out->distances = palloc_array(double *, in->nNodes);
252 out->traversalValues = palloc_array(void *, in->nNodes);
253
254 if (in->level == 0)
255 {
256 double inf = get_float8_infinity();
257
258 infbbox.high.x = inf;
259 infbbox.high.y = inf;
260 infbbox.low.x = -inf;
261 infbbox.low.y = -inf;
262 bbox = &infbbox;
263 }
264 else
265 {
266 bbox = in->traversalValue;
267 Assert(bbox);
268 }
269 }
270
271 if (in->allTheSame)
272 {
273 /* Report that all nodes should be visited */
274 out->nNodes = in->nNodes;
275 out->nodeNumbers = palloc_array(int, in->nNodes);
276 for (i = 0; i < in->nNodes; i++)
277 {
278 out->nodeNumbers[i] = i;
279
280 if (in->norderbys > 0)
281 {
283
284 /* Use parent quadrant box as traversalValue */
286
288
289 out->traversalValues[i] = quadrant;
291 in->orderbys, in->norderbys);
292 }
293 }
295 }
296
297 Assert(in->nNodes == 4);
298
299 /* "which" is a bitmask of quadrants that satisfy all constraints */
300 which = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
301
302 for (i = 0; i < in->nkeys; i++)
303 {
305 BOX *boxQuery;
306
307 switch (in->scankeys[i].sk_strategy)
308 {
310 if (SPTEST(point_right, centroid, query))
311 which &= (1 << 3) | (1 << 4);
312 break;
314 if (SPTEST(point_left, centroid, query))
315 which &= (1 << 1) | (1 << 2);
316 break;
318 which &= (1 << getQuadrant(centroid, query));
319 break;
322 if (SPTEST(point_above, centroid, query))
323 which &= (1 << 2) | (1 << 3);
324 break;
327 if (SPTEST(point_below, centroid, query))
328 which &= (1 << 1) | (1 << 4);
329 break;
331
332 /*
333 * For this operator, the query is a box not a point. We
334 * cheat to the extent of assuming that DatumGetPointP won't
335 * do anything that would be bad for a pointer-to-box.
336 */
338
342 {
343 /* centroid is in box, so all quadrants are OK */
344 }
345 else
346 {
347 /* identify quadrant(s) containing all corners of box */
348 Point p;
349 int r = 0;
350
351 p = boxQuery->low;
352 r |= 1 << getQuadrant(centroid, &p);
353 p.y = boxQuery->high.y;
354 r |= 1 << getQuadrant(centroid, &p);
355 p = boxQuery->high;
356 r |= 1 << getQuadrant(centroid, &p);
357 p.x = boxQuery->low.x;
358 r |= 1 << getQuadrant(centroid, &p);
359
360 which &= r;
361 }
362 break;
363 default:
364 elog(ERROR, "unrecognized strategy number: %d",
365 in->scankeys[i].sk_strategy);
366 break;
367 }
368
369 if (which == 0)
370 break; /* no need to consider remaining conditions */
371 }
372
373 out->levelAdds = palloc_array(int, 4);
374 for (i = 0; i < 4; ++i)
375 out->levelAdds[i] = 1;
376
377 /* We must descend into the quadrant(s) identified by which */
378 out->nodeNumbers = palloc_array(int, 4);
379 out->nNodes = 0;
380
381 for (i = 1; i <= 4; i++)
382 {
383 if (which & (1 << i))
384 {
385 out->nodeNumbers[out->nNodes] = i - 1;
386
387 if (in->norderbys > 0)
388 {
391
393
394 out->traversalValues[out->nNodes] = quadrant;
395
397 in->orderbys, in->norderbys);
398 }
399
400 out->nNodes++;
401 }
402 }
403
405}
406
407
408Datum
410{
413 Point *datum = DatumGetPointP(in->leafDatum);
414 bool res;
415 int i;
416
417 /* all tests are exact */
418 out->recheck = false;
419
420 /* leafDatum is what it is... */
421 out->leafValue = in->leafDatum;
422
423 /* Perform the required comparison(s) */
424 res = true;
425 for (i = 0; i < in->nkeys; i++)
426 {
428
429 switch (in->scankeys[i].sk_strategy)
430 {
432 res = SPTEST(point_left, datum, query);
433 break;
435 res = SPTEST(point_right, datum, query);
436 break;
438 res = SPTEST(point_eq, datum, query);
439 break;
442 res = SPTEST(point_below, datum, query);
443 break;
446 res = SPTEST(point_above, datum, query);
447 break;
449
450 /*
451 * For this operator, the query is a box not a point. We
452 * cheat to the extent of assuming that DatumGetPointP won't
453 * do anything that would be bad for a pointer-to-box.
454 */
455 res = SPTEST(box_contain_pt, query, datum);
456 break;
457 default:
458 elog(ERROR, "unrecognized strategy number: %d",
459 in->scankeys[i].sk_strategy);
460 break;
461 }
462
463 if (!res)
464 break;
465 }
466
467 if (res && in->norderbys > 0)
468 /* ok, it passes -> let's compute the distances */
470 in->orderbys, in->norderbys);
471
472 PG_RETURN_BOOL(res);
473}
#define Assert(condition)
Definition c.h:873
int16_t int16
Definition c.h:541
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define palloc_object(type)
Definition fe_memutils.h:74
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_object(type)
Definition fe_memutils.h:75
static float8 get_float8_infinity(void)
Definition float.h:65
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define DirectFunctionCall2(func, arg1, arg2)
Definition fmgr.h:686
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
static Point * DatumGetPointP(Datum X)
Definition geo_decls.h:175
static Datum PointPGetDatum(const Point *X)
Definition geo_decls.h:180
static BOX * DatumGetBoxP(Datum X)
Definition geo_decls.h:233
static Datum BoxPGetDatum(const BOX *X)
Definition geo_decls.h:238
Datum point_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:1955
Datum point_above(PG_FUNCTION_ARGS)
Definition geo_ops.c:1919
Datum box_contain_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:3146
Datum point_below(PG_FUNCTION_ARGS)
Definition geo_ops.c:1928
Datum point_horiz(PG_FUNCTION_ARGS)
Definition geo_ops.c:1946
Datum point_left(PG_FUNCTION_ARGS)
Definition geo_ops.c:1901
Datum point_right(PG_FUNCTION_ARGS)
Definition geo_ops.c:1910
Datum point_vert(PG_FUNCTION_ARGS)
Definition geo_ops.c:1937
int b
Definition isn.c:74
int a
Definition isn.c:73
int i
Definition isn.c:77
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
void * arg
#define qsort(a, b, c, d)
Definition port.h:495
static bool DatumGetBool(Datum X)
Definition postgres.h:100
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
@ spgMatchNode
Definition spgist.h:69
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)
Definition spgproc.c:82
double * spg_key_orderbys_distances(Datum key, bool isLeaf, ScanKey orderbys, int norderbys)
Definition spgproc.c:63
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 SPTEST(f, x, y)
#define RTLeftStrategyNumber
Definition stratnum.h:51
#define RTRightStrategyNumber
Definition stratnum.h:55
#define RTSameStrategyNumber
Definition stratnum.h:56
#define RTOldBelowStrategyNumber
Definition stratnum.h:79
#define RTBelowStrategyNumber
Definition stratnum.h:60
#define RTOldAboveStrategyNumber
Definition stratnum.h:80
#define RTAboveStrategyNumber
Definition stratnum.h:61
#define RTContainedByStrategyNumber
Definition stratnum.h:58
Point low
Definition geo_decls.h:142
Point high
Definition geo_decls.h:141
float8 y
Definition geo_decls.h:98
float8 x
Definition geo_decls.h:97
Datum sk_argument
Definition skey.h:72
StrategyNumber sk_strategy
Definition skey.h:68
bool hasPrefix
Definition spgist.h:61
Datum prefixDatum
Definition spgist.h:62
int nNodes
Definition spgist.h:63
Datum datum
Definition spgist.h:55
bool allTheSame
Definition spgist.h:60
spgChooseResultType resultType
Definition spgist.h:76
int levelAdd
Definition spgist.h:82
Datum restDatum
Definition spgist.h:83
int nodeN
Definition spgist.h:81
union spgChooseOut::@54 result
struct spgChooseOut::@54::@55 matchNode
bool longValuesOK
Definition spgist.h:47
bool canReturnData
Definition spgist.h:46
Oid labelType
Definition spgist.h:44
Oid prefixType
Definition spgist.h:43
void * traversalValue
Definition spgist.h:141
MemoryContext traversalMemoryContext
Definition spgist.h:142
void ** traversalValues
Definition spgist.h:160
double ** distances
Definition spgist.h:161
double * distances
Definition spgist.h:188
Datum * datums
Definition spgist.h:113
int * mapTuplesToNodes
Definition spgist.h:125
Datum * nodeLabels
Definition spgist.h:123
Datum * leafTupleDatums
Definition spgist.h:126
Datum prefixDatum
Definition spgist.h:120