Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * geo_spgist.c
4 : * SP-GiST implementation of 4-dimensional quad tree over boxes
5 : *
6 : * This module provides SP-GiST implementation for boxes using quad tree
7 : * analogy in 4-dimensional space. SP-GiST doesn't allow indexing of
8 : * overlapping objects. We are making 2D objects never-overlapping in
9 : * 4D space. This technique has some benefits compared to traditional
10 : * R-Tree which is implemented as GiST. The performance tests reveal
11 : * that this technique especially beneficial with too much overlapping
12 : * objects, so called "spaghetti data".
13 : *
14 : * Unlike the original quad tree, we are splitting the tree into 16
15 : * quadrants in 4D space. It is easier to imagine it as splitting space
16 : * two times into 4:
17 : *
18 : * | |
19 : * | |
20 : * | -----+-----
21 : * | |
22 : * | |
23 : * -------------+-------------
24 : * |
25 : * |
26 : * |
27 : * |
28 : * |
29 : *
30 : * We are using box datatype as the prefix, but we are treating them
31 : * as points in 4-dimensional space, because 2D boxes are not enough
32 : * to represent the quadrant boundaries in 4D space. They however are
33 : * sufficient to point out the additional boundaries of the next
34 : * quadrant.
35 : *
36 : * We are using traversal values provided by SP-GiST to calculate and
37 : * to store the bounds of the quadrants, while traversing into the tree.
38 : * Traversal value has all the boundaries in the 4D space, and is is
39 : * capable of transferring the required boundaries to the following
40 : * traversal values. In conclusion, three things are necessary
41 : * to calculate the next traversal value:
42 : *
43 : * (1) the traversal value of the parent
44 : * (2) the quadrant of the current node
45 : * (3) the prefix of the current node
46 : *
47 : * If we visualize them on our simplified drawing (see the drawing above);
48 : * transferred boundaries of (1) would be the outer axis, relevant part
49 : * of (2) would be the up right part of the other axis, and (3) would be
50 : * the inner axis.
51 : *
52 : * For example, consider the case of overlapping. When recursion
53 : * descends deeper and deeper down the tree, all quadrants in
54 : * the current node will be checked for overlapping. The boundaries
55 : * will be re-calculated for all quadrants. Overlap check answers
56 : * the question: can any box from this quadrant overlap with the given
57 : * box? If yes, then this quadrant will be walked. If no, then this
58 : * quadrant will be skipped.
59 : *
60 : * This method provides restrictions for minimum and maximum values of
61 : * every dimension of every corner of the box on every level of the tree
62 : * except the root. For the root node, we are setting the boundaries
63 : * that we don't yet have as infinity.
64 : *
65 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
66 : * Portions Copyright (c) 1994, Regents of the University of California
67 : *
68 : * IDENTIFICATION
69 : * src/backend/utils/adt/geo_spgist.c
70 : *
71 : *-------------------------------------------------------------------------
72 : */
73 :
74 : #include "postgres.h"
75 :
76 : #include "access/spgist.h"
77 : #include "access/stratnum.h"
78 : #include "catalog/pg_type.h"
79 : #include "utils/builtins.h"
80 : #include "utils/geo_decls.h"
81 :
82 : /*
83 : * Comparator for qsort
84 : *
85 : * We don't need to use the floating point macros in here, because this
86 : * is going only going to be used in a place to effect the performance
87 : * of the index, not the correctness.
88 : */
89 : static int
90 128167 : compareDoubles(const void *a, const void *b)
91 : {
92 128167 : double x = *(double *) a;
93 128167 : double y = *(double *) b;
94 :
95 128167 : if (x == y)
96 43510 : return 0;
97 84657 : return (x > y) ? 1 : -1;
98 : }
99 :
100 : typedef struct
101 : {
102 : double low;
103 : double high;
104 : } Range;
105 :
106 : typedef struct
107 : {
108 : Range left;
109 : Range right;
110 : } RangeBox;
111 :
112 : typedef struct
113 : {
114 : RangeBox range_box_x;
115 : RangeBox range_box_y;
116 : } RectBox;
117 :
118 : /*
119 : * Calculate the quadrant
120 : *
121 : * The quadrant is 8 bit unsigned integer with 4 least bits in use.
122 : * This function accepts BOXes as input. They are not casted to
123 : * RangeBoxes, yet. All 4 bits are set by comparing a corner of the box.
124 : * This makes 16 quadrants in total.
125 : */
126 : static uint8
127 66985 : getQuadrant(BOX *centroid, BOX *inBox)
128 : {
129 66985 : uint8 quadrant = 0;
130 :
131 66985 : if (inBox->low.x > centroid->low.x)
132 58948 : quadrant |= 0x8;
133 :
134 66985 : if (inBox->high.x > centroid->high.x)
135 58950 : quadrant |= 0x4;
136 :
137 66985 : if (inBox->low.y > centroid->low.y)
138 32602 : quadrant |= 0x2;
139 :
140 66985 : if (inBox->high.y > centroid->high.y)
141 32605 : quadrant |= 0x1;
142 :
143 66985 : return quadrant;
144 : }
145 :
146 : /*
147 : * Get RangeBox using BOX
148 : *
149 : * We are turning the BOX to our structures to emphasize their function
150 : * of representing points in 4D space. It also is more convenient to
151 : * access the values with this structure.
152 : */
153 : static RangeBox *
154 1268 : getRangeBox(BOX *box)
155 : {
156 1268 : RangeBox *range_box = (RangeBox *) palloc(sizeof(RangeBox));
157 :
158 1268 : range_box->left.low = box->low.x;
159 1268 : range_box->left.high = box->high.x;
160 :
161 1268 : range_box->right.low = box->low.y;
162 1268 : range_box->right.high = box->high.y;
163 :
164 1268 : return range_box;
165 : }
166 :
167 : /*
168 : * Initialize the traversal value
169 : *
170 : * In the beginning, we don't have any restrictions. We have to
171 : * initialize the struct to cover the whole 4D space.
172 : */
173 : static RectBox *
174 13 : initRectBox(void)
175 : {
176 13 : RectBox *rect_box = (RectBox *) palloc(sizeof(RectBox));
177 13 : double infinity = get_float8_infinity();
178 :
179 13 : rect_box->range_box_x.left.low = -infinity;
180 13 : rect_box->range_box_x.left.high = infinity;
181 :
182 13 : rect_box->range_box_x.right.low = -infinity;
183 13 : rect_box->range_box_x.right.high = infinity;
184 :
185 13 : rect_box->range_box_y.left.low = -infinity;
186 13 : rect_box->range_box_y.left.high = infinity;
187 :
188 13 : rect_box->range_box_y.right.low = -infinity;
189 13 : rect_box->range_box_y.right.high = infinity;
190 :
191 13 : return rect_box;
192 : }
193 :
194 : /*
195 : * Calculate the next traversal value
196 : *
197 : * All centroids are bounded by RectBox, but SP-GiST only keeps
198 : * boxes. When we are traversing the tree, we must calculate RectBox,
199 : * using centroid and quadrant.
200 : */
201 : static RectBox *
202 10144 : nextRectBox(RectBox *rect_box, RangeBox *centroid, uint8 quadrant)
203 : {
204 10144 : RectBox *next_rect_box = (RectBox *) palloc(sizeof(RectBox));
205 :
206 10144 : memcpy(next_rect_box, rect_box, sizeof(RectBox));
207 :
208 10144 : if (quadrant & 0x8)
209 5072 : next_rect_box->range_box_x.left.low = centroid->left.low;
210 : else
211 5072 : next_rect_box->range_box_x.left.high = centroid->left.low;
212 :
213 10144 : if (quadrant & 0x4)
214 5072 : next_rect_box->range_box_x.right.low = centroid->left.high;
215 : else
216 5072 : next_rect_box->range_box_x.right.high = centroid->left.high;
217 :
218 10144 : if (quadrant & 0x2)
219 5072 : next_rect_box->range_box_y.left.low = centroid->right.low;
220 : else
221 5072 : next_rect_box->range_box_y.left.high = centroid->right.low;
222 :
223 10144 : if (quadrant & 0x1)
224 5072 : next_rect_box->range_box_y.right.low = centroid->right.high;
225 : else
226 5072 : next_rect_box->range_box_y.right.high = centroid->right.high;
227 :
228 10144 : return next_rect_box;
229 : }
230 :
231 : /* Can any range from range_box overlap with this argument? */
232 : static bool
233 808 : overlap2D(RangeBox *range_box, Range *query)
234 : {
235 1560 : return FPge(range_box->right.high, query->low) &&
236 752 : FPle(range_box->left.low, query->high);
237 : }
238 :
239 : /* Can any rectangle from rect_box overlap with this argument? */
240 : static bool
241 480 : overlap4D(RectBox *rect_box, RangeBox *query)
242 : {
243 808 : return overlap2D(&rect_box->range_box_x, &query->left) &&
244 328 : overlap2D(&rect_box->range_box_y, &query->right);
245 : }
246 :
247 : /* Can any range from range_box contain this argument? */
248 : static bool
249 152 : contain2D(RangeBox *range_box, Range *query)
250 : {
251 260 : return FPge(range_box->right.high, query->high) &&
252 108 : FPle(range_box->left.low, query->low);
253 : }
254 :
255 : /* Can any rectangle from rect_box contain this argument? */
256 : static bool
257 96 : contain4D(RectBox *rect_box, RangeBox *query)
258 : {
259 152 : return contain2D(&rect_box->range_box_x, &query->left) &&
260 56 : contain2D(&rect_box->range_box_y, &query->right);
261 : }
262 :
263 : /* Can any range from range_box be contained by this argument? */
264 : static bool
265 756 : contained2D(RangeBox *range_box, Range *query)
266 : {
267 2172 : return FPle(range_box->left.low, query->high) &&
268 1232 : FPge(range_box->left.high, query->low) &&
269 1824 : FPle(range_box->right.low, query->high) &&
270 496 : FPge(range_box->right.high, query->low);
271 : }
272 :
273 : /* Can any rectangle from rect_box be contained by this argument? */
274 : static bool
275 512 : contained4D(RectBox *rect_box, RangeBox *query)
276 : {
277 756 : return contained2D(&rect_box->range_box_x, &query->left) &&
278 244 : contained2D(&rect_box->range_box_y, &query->right);
279 : }
280 :
281 : /* Can any range from range_box to be lower than this argument? */
282 : static bool
283 704 : lower2D(RangeBox *range_box, Range *query)
284 : {
285 1280 : return FPlt(range_box->left.low, query->low) &&
286 576 : FPlt(range_box->right.low, query->low);
287 : }
288 :
289 : /* Can any range from range_box not extend to the right side of the query? */
290 : static bool
291 1888 : overLower2D(RangeBox *range_box, Range *query)
292 : {
293 3496 : return FPle(range_box->left.low, query->high) &&
294 1608 : FPle(range_box->right.low, query->high);
295 : }
296 :
297 : /* Can any range from range_box to be higher than this argument? */
298 : static bool
299 3744 : higher2D(RangeBox *range_box, Range *query)
300 : {
301 6880 : return FPgt(range_box->left.high, query->high) &&
302 3136 : FPgt(range_box->right.high, query->high);
303 : }
304 :
305 : /* Can any range from range_box not extend to the left side of the query? */
306 : static bool
307 2720 : overHigher2D(RangeBox *range_box, Range *query)
308 : {
309 5344 : return FPge(range_box->left.high, query->low) &&
310 2624 : FPge(range_box->right.high, query->low);
311 : }
312 :
313 : /* Can any rectangle from rect_box be left of this argument? */
314 : static bool
315 336 : left4D(RectBox *rect_box, RangeBox *query)
316 : {
317 336 : return lower2D(&rect_box->range_box_x, &query->left);
318 : }
319 :
320 : /* Can any rectangle from rect_box does not extend the right of this argument? */
321 : static bool
322 1136 : overLeft4D(RectBox *rect_box, RangeBox *query)
323 : {
324 1136 : return overLower2D(&rect_box->range_box_x, &query->left);
325 : }
326 :
327 : /* Can any rectangle from rect_box be right of this argument? */
328 : static bool
329 2944 : right4D(RectBox *rect_box, RangeBox *query)
330 : {
331 2944 : return higher2D(&rect_box->range_box_x, &query->left);
332 : }
333 :
334 : /* Can any rectangle from rect_box does not extend the left of this argument? */
335 : static bool
336 1488 : overRight4D(RectBox *rect_box, RangeBox *query)
337 : {
338 1488 : return overHigher2D(&rect_box->range_box_x, &query->left);
339 : }
340 :
341 : /* Can any rectangle from rect_box be below of this argument? */
342 : static bool
343 368 : below4D(RectBox *rect_box, RangeBox *query)
344 : {
345 368 : return lower2D(&rect_box->range_box_y, &query->right);
346 : }
347 :
348 : /* Can any rectangle from rect_box does not extend above this argument? */
349 : static bool
350 752 : overBelow4D(RectBox *rect_box, RangeBox *query)
351 : {
352 752 : return overLower2D(&rect_box->range_box_y, &query->right);
353 : }
354 :
355 : /* Can any rectangle from rect_box be above of this argument? */
356 : static bool
357 800 : above4D(RectBox *rect_box, RangeBox *query)
358 : {
359 800 : return higher2D(&rect_box->range_box_y, &query->right);
360 : }
361 :
362 : /* Can any rectangle from rect_box does not extend below of this argument? */
363 : static bool
364 1232 : overAbove4D(RectBox *rect_box, RangeBox *query)
365 : {
366 1232 : return overHigher2D(&rect_box->range_box_y, &query->right);
367 : }
368 :
369 : /*
370 : * SP-GiST config function
371 : */
372 : Datum
373 5 : spg_box_quad_config(PG_FUNCTION_ARGS)
374 : {
375 5 : spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1);
376 :
377 5 : cfg->prefixType = BOXOID;
378 5 : cfg->labelType = VOIDOID; /* We don't need node labels. */
379 5 : cfg->canReturnData = true;
380 5 : cfg->longValuesOK = false;
381 :
382 5 : PG_RETURN_VOID();
383 : }
384 :
385 : /*
386 : * SP-GiST choose function
387 : */
388 : Datum
389 57345 : spg_box_quad_choose(PG_FUNCTION_ARGS)
390 : {
391 57345 : spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
392 57345 : spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
393 57345 : BOX *centroid = DatumGetBoxP(in->prefixDatum),
394 57345 : *box = DatumGetBoxP(in->datum);
395 :
396 57345 : out->resultType = spgMatchNode;
397 57345 : out->result.matchNode.restDatum = BoxPGetDatum(box);
398 :
399 : /* nodeN will be set by core, when allTheSame. */
400 57345 : if (!in->allTheSame)
401 56309 : out->result.matchNode.nodeN = getQuadrant(centroid, box);
402 :
403 57345 : PG_RETURN_VOID();
404 : }
405 :
406 : /*
407 : * SP-GiST pick-split function
408 : *
409 : * It splits a list of boxes into quadrants by choosing a central 4D
410 : * point as the median of the coordinates of the boxes.
411 : */
412 : Datum
413 101 : spg_box_quad_picksplit(PG_FUNCTION_ARGS)
414 : {
415 101 : spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
416 101 : spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
417 : BOX *centroid;
418 : int median,
419 : i;
420 101 : double *lowXs = palloc(sizeof(double) * in->nTuples);
421 101 : double *highXs = palloc(sizeof(double) * in->nTuples);
422 101 : double *lowYs = palloc(sizeof(double) * in->nTuples);
423 101 : double *highYs = palloc(sizeof(double) * in->nTuples);
424 :
425 : /* Calculate median of all 4D coordinates */
426 10777 : for (i = 0; i < in->nTuples; i++)
427 : {
428 10676 : BOX *box = DatumGetBoxP(in->datums[i]);
429 :
430 10676 : lowXs[i] = box->low.x;
431 10676 : highXs[i] = box->high.x;
432 10676 : lowYs[i] = box->low.y;
433 10676 : highYs[i] = box->high.y;
434 : }
435 :
436 101 : qsort(lowXs, in->nTuples, sizeof(double), compareDoubles);
437 101 : qsort(highXs, in->nTuples, sizeof(double), compareDoubles);
438 101 : qsort(lowYs, in->nTuples, sizeof(double), compareDoubles);
439 101 : qsort(highYs, in->nTuples, sizeof(double), compareDoubles);
440 :
441 101 : median = in->nTuples / 2;
442 :
443 101 : centroid = palloc(sizeof(BOX));
444 :
445 101 : centroid->low.x = lowXs[median];
446 101 : centroid->high.x = highXs[median];
447 101 : centroid->low.y = lowYs[median];
448 101 : centroid->high.y = highYs[median];
449 :
450 : /* Fill the output */
451 101 : out->hasPrefix = true;
452 101 : out->prefixDatum = BoxPGetDatum(centroid);
453 :
454 101 : out->nNodes = 16;
455 101 : out->nodeLabels = NULL; /* We don't need node labels. */
456 :
457 101 : out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
458 101 : out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);
459 :
460 : /*
461 : * Assign ranges to corresponding nodes according to quadrants relative to
462 : * the "centroid" range
463 : */
464 10777 : for (i = 0; i < in->nTuples; i++)
465 : {
466 10676 : BOX *box = DatumGetBoxP(in->datums[i]);
467 10676 : uint8 quadrant = getQuadrant(centroid, box);
468 :
469 10676 : out->leafTupleDatums[i] = BoxPGetDatum(box);
470 10676 : out->mapTuplesToNodes[i] = quadrant;
471 : }
472 :
473 101 : PG_RETURN_VOID();
474 : }
475 :
476 : /*
477 : * SP-GiST inner consistent function
478 : */
479 : Datum
480 698 : spg_box_quad_inner_consistent(PG_FUNCTION_ARGS)
481 : {
482 698 : spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
483 698 : spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
484 : int i;
485 : MemoryContext old_ctx;
486 : RectBox *rect_box;
487 : uint8 quadrant;
488 : RangeBox *centroid,
489 : **queries;
490 :
491 698 : if (in->allTheSame)
492 : {
493 : /* Report that all nodes should be visited */
494 64 : out->nNodes = in->nNodes;
495 64 : out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
496 576 : for (i = 0; i < in->nNodes; i++)
497 512 : out->nodeNumbers[i] = i;
498 :
499 64 : PG_RETURN_VOID();
500 : }
501 :
502 : /*
503 : * We are saving the traversal value or initialize it an unbounded one, if
504 : * we have just begun to walk the tree.
505 : */
506 634 : if (in->traversalValue)
507 621 : rect_box = in->traversalValue;
508 : else
509 13 : rect_box = initRectBox();
510 :
511 : /*
512 : * We are casting the prefix and queries to RangeBoxes for ease of the
513 : * following operations.
514 : */
515 634 : centroid = getRangeBox(DatumGetBoxP(in->prefixDatum));
516 634 : queries = (RangeBox **) palloc(in->nkeys * sizeof(RangeBox *));
517 1268 : for (i = 0; i < in->nkeys; i++)
518 634 : queries[i] = getRangeBox(DatumGetBoxP(in->scankeys[i].sk_argument));
519 :
520 : /* Allocate enough memory for nodes */
521 634 : out->nNodes = 0;
522 634 : out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
523 634 : out->traversalValues = (void **) palloc(sizeof(void *) * in->nNodes);
524 :
525 : /*
526 : * We switch memory context, because we want to allocate memory for new
527 : * traversal values (next_rect_box) and pass these pieces of memory to
528 : * further call of this function.
529 : */
530 634 : old_ctx = MemoryContextSwitchTo(in->traversalMemoryContext);
531 :
532 10778 : for (quadrant = 0; quadrant < in->nNodes; quadrant++)
533 : {
534 10144 : RectBox *next_rect_box = nextRectBox(rect_box, centroid, quadrant);
535 10144 : bool flag = true;
536 :
537 18072 : for (i = 0; i < in->nkeys; i++)
538 : {
539 10144 : StrategyNumber strategy = in->scankeys[i].sk_strategy;
540 :
541 10144 : switch (strategy)
542 : {
543 : case RTOverlapStrategyNumber:
544 480 : flag = overlap4D(next_rect_box, queries[i]);
545 480 : break;
546 :
547 : case RTContainsStrategyNumber:
548 96 : flag = contain4D(next_rect_box, queries[i]);
549 96 : break;
550 :
551 : case RTSameStrategyNumber:
552 : case RTContainedByStrategyNumber:
553 512 : flag = contained4D(next_rect_box, queries[i]);
554 512 : break;
555 :
556 : case RTLeftStrategyNumber:
557 336 : flag = left4D(next_rect_box, queries[i]);
558 336 : break;
559 :
560 : case RTOverLeftStrategyNumber:
561 1136 : flag = overLeft4D(next_rect_box, queries[i]);
562 1136 : break;
563 :
564 : case RTRightStrategyNumber:
565 2944 : flag = right4D(next_rect_box, queries[i]);
566 2944 : break;
567 :
568 : case RTOverRightStrategyNumber:
569 1488 : flag = overRight4D(next_rect_box, queries[i]);
570 1488 : break;
571 :
572 : case RTAboveStrategyNumber:
573 800 : flag = above4D(next_rect_box, queries[i]);
574 800 : break;
575 :
576 : case RTOverAboveStrategyNumber:
577 1232 : flag = overAbove4D(next_rect_box, queries[i]);
578 1232 : break;
579 :
580 : case RTBelowStrategyNumber:
581 368 : flag = below4D(next_rect_box, queries[i]);
582 368 : break;
583 :
584 : case RTOverBelowStrategyNumber:
585 752 : flag = overBelow4D(next_rect_box, queries[i]);
586 752 : break;
587 :
588 : default:
589 0 : elog(ERROR, "unrecognized strategy: %d", strategy);
590 : }
591 :
592 : /* If any check is failed, we have found our answer. */
593 10144 : if (!flag)
594 2216 : break;
595 : }
596 :
597 10144 : if (flag)
598 : {
599 7928 : out->traversalValues[out->nNodes] = next_rect_box;
600 7928 : out->nodeNumbers[out->nNodes] = quadrant;
601 7928 : out->nNodes++;
602 : }
603 : else
604 : {
605 : /*
606 : * If this node is not selected, we don't need to keep the next
607 : * traversal value in the memory context.
608 : */
609 2216 : pfree(next_rect_box);
610 : }
611 : }
612 :
613 : /* Switch back */
614 634 : MemoryContextSwitchTo(old_ctx);
615 :
616 634 : PG_RETURN_VOID();
617 : }
618 :
619 : /*
620 : * SP-GiST inner consistent function
621 : */
622 : Datum
623 61893 : spg_box_quad_leaf_consistent(PG_FUNCTION_ARGS)
624 : {
625 61893 : spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0);
626 61893 : spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1);
627 61893 : Datum leaf = in->leafDatum;
628 61893 : bool flag = true;
629 : int i;
630 :
631 : /* All tests are exact. */
632 61893 : out->recheck = false;
633 :
634 : /* leafDatum is what it is... */
635 61893 : out->leafValue = in->leafDatum;
636 :
637 : /* Perform the required comparison(s) */
638 117031 : for (i = 0; i < in->nkeys; i++)
639 : {
640 61893 : StrategyNumber strategy = in->scankeys[i].sk_strategy;
641 61893 : Datum query = in->scankeys[i].sk_argument;
642 :
643 61893 : switch (strategy)
644 : {
645 : case RTOverlapStrategyNumber:
646 2332 : flag = DatumGetBool(DirectFunctionCall2(box_overlap, leaf,
647 : query));
648 2332 : break;
649 :
650 : case RTContainsStrategyNumber:
651 1090 : flag = DatumGetBool(DirectFunctionCall2(box_contain, leaf,
652 : query));
653 1090 : break;
654 :
655 : case RTContainedByStrategyNumber:
656 2155 : flag = DatumGetBool(DirectFunctionCall2(box_contained, leaf,
657 : query));
658 2155 : break;
659 :
660 : case RTSameStrategyNumber:
661 1075 : flag = DatumGetBool(DirectFunctionCall2(box_same, leaf,
662 : query));
663 1075 : break;
664 :
665 : case RTLeftStrategyNumber:
666 1446 : flag = DatumGetBool(DirectFunctionCall2(box_left, leaf,
667 : query));
668 1446 : break;
669 :
670 : case RTOverLeftStrategyNumber:
671 5242 : flag = DatumGetBool(DirectFunctionCall2(box_overleft, leaf,
672 : query));
673 5242 : break;
674 :
675 : case RTRightStrategyNumber:
676 15545 : flag = DatumGetBool(DirectFunctionCall2(box_right, leaf,
677 : query));
678 15545 : break;
679 :
680 : case RTOverRightStrategyNumber:
681 10389 : flag = DatumGetBool(DirectFunctionCall2(box_overright, leaf,
682 : query));
683 10389 : break;
684 :
685 : case RTAboveStrategyNumber:
686 5090 : flag = DatumGetBool(DirectFunctionCall2(box_above, leaf,
687 : query));
688 5090 : break;
689 :
690 : case RTOverAboveStrategyNumber:
691 9206 : flag = DatumGetBool(DirectFunctionCall2(box_overabove, leaf,
692 : query));
693 9206 : break;
694 :
695 : case RTBelowStrategyNumber:
696 2167 : flag = DatumGetBool(DirectFunctionCall2(box_below, leaf,
697 : query));
698 2167 : break;
699 :
700 : case RTOverBelowStrategyNumber:
701 6156 : flag = DatumGetBool(DirectFunctionCall2(box_overbelow, leaf,
702 : query));
703 6156 : break;
704 :
705 : default:
706 0 : elog(ERROR, "unrecognized strategy: %d", strategy);
707 : }
708 :
709 : /* If any check is failed, we have found our answer. */
710 61893 : if (!flag)
711 6755 : break;
712 : }
713 :
714 61893 : PG_RETURN_BOOL(flag);
715 : }
|