Force a checkpoint in CREATE DATABASE before starting to copy the files,
[PostgreSQL.git] / src / backend / access / gist / gistproc.c
blob8dd482bafd15362201e2a480fea7fb1f1f419f7d
1 /*-------------------------------------------------------------------------
3 * gistproc.c
4 * Support procedures for GiSTs over 2-D objects (boxes, polygons, circles).
6 * This gives R-tree behavior, with Guttman's poly-time split algorithm.
9 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
12 * IDENTIFICATION
13 * $PostgreSQL$
15 *-------------------------------------------------------------------------
17 #include "postgres.h"
19 #include "access/gist.h"
20 #include "access/skey.h"
21 #include "utils/geo_decls.h"
24 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
25 StrategyNumber strategy);
26 static double size_box(Datum dbox);
27 static bool rtree_internal_consistent(BOX *key, BOX *query,
28 StrategyNumber strategy);
31 /**************************************************
32 * Box ops
33 **************************************************/
35 static Datum
36 rt_box_union(PG_FUNCTION_ARGS)
38 BOX *a = PG_GETARG_BOX_P(0);
39 BOX *b = PG_GETARG_BOX_P(1);
40 BOX *n;
42 n = (BOX *) palloc(sizeof(BOX));
44 n->high.x = Max(a->high.x, b->high.x);
45 n->high.y = Max(a->high.y, b->high.y);
46 n->low.x = Min(a->low.x, b->low.x);
47 n->low.y = Min(a->low.y, b->low.y);
49 PG_RETURN_BOX_P(n);
52 static Datum
53 rt_box_inter(PG_FUNCTION_ARGS)
55 BOX *a = PG_GETARG_BOX_P(0);
56 BOX *b = PG_GETARG_BOX_P(1);
57 BOX *n;
59 n = (BOX *) palloc(sizeof(BOX));
61 n->high.x = Min(a->high.x, b->high.x);
62 n->high.y = Min(a->high.y, b->high.y);
63 n->low.x = Max(a->low.x, b->low.x);
64 n->low.y = Max(a->low.y, b->low.y);
66 if (n->high.x < n->low.x || n->high.y < n->low.y)
68 pfree(n);
69 /* Indicate "no intersection" by returning NULL pointer */
70 n = NULL;
73 PG_RETURN_BOX_P(n);
77 * The GiST Consistent method for boxes
79 * Should return false if for all data items x below entry,
80 * the predicate x op query must be FALSE, where op is the oper
81 * corresponding to strategy in the pg_amop table.
83 Datum
84 gist_box_consistent(PG_FUNCTION_ARGS)
86 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
87 BOX *query = PG_GETARG_BOX_P(1);
88 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
89 /* Oid subtype = PG_GETARG_OID(3); */
90 bool *recheck = (bool *) PG_GETARG_POINTER(4);
92 /* All cases served by this function are exact */
93 *recheck = false;
95 if (DatumGetBoxP(entry->key) == NULL || query == NULL)
96 PG_RETURN_BOOL(FALSE);
99 * if entry is not leaf, use rtree_internal_consistent, else use
100 * gist_box_leaf_consistent
102 if (GIST_LEAF(entry))
103 PG_RETURN_BOOL(gist_box_leaf_consistent(DatumGetBoxP(entry->key),
104 query,
105 strategy));
106 else
107 PG_RETURN_BOOL(rtree_internal_consistent(DatumGetBoxP(entry->key),
108 query,
109 strategy));
112 static void
113 adjustBox(BOX *b, BOX *addon)
115 if (b->high.x < addon->high.x)
116 b->high.x = addon->high.x;
117 if (b->low.x > addon->low.x)
118 b->low.x = addon->low.x;
119 if (b->high.y < addon->high.y)
120 b->high.y = addon->high.y;
121 if (b->low.y > addon->low.y)
122 b->low.y = addon->low.y;
126 * The GiST Union method for boxes
128 * returns the minimal bounding box that encloses all the entries in entryvec
130 Datum
131 gist_box_union(PG_FUNCTION_ARGS)
133 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
134 int *sizep = (int *) PG_GETARG_POINTER(1);
135 int numranges,
137 BOX *cur,
138 *pageunion;
140 numranges = entryvec->n;
141 pageunion = (BOX *) palloc(sizeof(BOX));
142 cur = DatumGetBoxP(entryvec->vector[0].key);
143 memcpy((void *) pageunion, (void *) cur, sizeof(BOX));
145 for (i = 1; i < numranges; i++)
147 cur = DatumGetBoxP(entryvec->vector[i].key);
148 adjustBox(pageunion, cur);
150 *sizep = sizeof(BOX);
152 PG_RETURN_POINTER(pageunion);
156 * GiST Compress methods for boxes
158 * do not do anything.
160 Datum
161 gist_box_compress(PG_FUNCTION_ARGS)
163 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
167 * GiST DeCompress method for boxes (also used for polygons and circles)
169 * do not do anything --- we just use the stored box as is.
171 Datum
172 gist_box_decompress(PG_FUNCTION_ARGS)
174 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
178 * The GiST Penalty method for boxes
180 * As in the R-tree paper, we use change in area as our penalty metric
182 Datum
183 gist_box_penalty(PG_FUNCTION_ARGS)
185 GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
186 GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
187 float *result = (float *) PG_GETARG_POINTER(2);
188 Datum ud;
190 ud = DirectFunctionCall2(rt_box_union, origentry->key, newentry->key);
191 *result = (float) (size_box(ud) - size_box(origentry->key));
192 PG_RETURN_POINTER(result);
195 static void
196 chooseLR(GIST_SPLITVEC *v,
197 OffsetNumber *list1, int nlist1, BOX *union1,
198 OffsetNumber *list2, int nlist2, BOX *union2)
200 bool firstToLeft = true;
202 if (v->spl_ldatum_exists || v->spl_rdatum_exists)
204 if (v->spl_ldatum_exists && v->spl_rdatum_exists)
206 BOX LRl = *union1,
207 LRr = *union2;
208 BOX RLl = *union2,
209 RLr = *union1;
210 double sizeLR,
211 sizeRL;
213 adjustBox(&LRl, DatumGetBoxP(v->spl_ldatum));
214 adjustBox(&LRr, DatumGetBoxP(v->spl_rdatum));
215 adjustBox(&RLl, DatumGetBoxP(v->spl_ldatum));
216 adjustBox(&RLr, DatumGetBoxP(v->spl_rdatum));
218 sizeLR = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&LRl), BoxPGetDatum(&LRr)));
219 sizeRL = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&RLl), BoxPGetDatum(&RLr)));
221 if (sizeLR > sizeRL)
222 firstToLeft = false;
225 else
227 float p1,
229 GISTENTRY oldUnion,
230 addon;
232 gistentryinit(oldUnion, (v->spl_ldatum_exists) ? v->spl_ldatum : v->spl_rdatum,
233 NULL, NULL, InvalidOffsetNumber, FALSE);
235 gistentryinit(addon, BoxPGetDatum(union1), NULL, NULL, InvalidOffsetNumber, FALSE);
236 DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union1), PointerGetDatum(&p1));
237 gistentryinit(addon, BoxPGetDatum(union2), NULL, NULL, InvalidOffsetNumber, FALSE);
238 DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union2), PointerGetDatum(&p2));
240 if ((v->spl_ldatum_exists && p1 > p2) || (v->spl_rdatum_exists && p1 < p2))
241 firstToLeft = false;
245 if (firstToLeft)
247 v->spl_left = list1;
248 v->spl_right = list2;
249 v->spl_nleft = nlist1;
250 v->spl_nright = nlist2;
251 if (v->spl_ldatum_exists)
252 adjustBox(union1, DatumGetBoxP(v->spl_ldatum));
253 v->spl_ldatum = BoxPGetDatum(union1);
254 if (v->spl_rdatum_exists)
255 adjustBox(union2, DatumGetBoxP(v->spl_rdatum));
256 v->spl_rdatum = BoxPGetDatum(union2);
258 else
260 v->spl_left = list2;
261 v->spl_right = list1;
262 v->spl_nleft = nlist2;
263 v->spl_nright = nlist1;
264 if (v->spl_ldatum_exists)
265 adjustBox(union2, DatumGetBoxP(v->spl_ldatum));
266 v->spl_ldatum = BoxPGetDatum(union2);
267 if (v->spl_rdatum_exists)
268 adjustBox(union1, DatumGetBoxP(v->spl_rdatum));
269 v->spl_rdatum = BoxPGetDatum(union1);
272 v->spl_ldatum_exists = v->spl_rdatum_exists = false;
276 * The GiST PickSplit method
278 * New linear algorithm, see 'New Linear Node Splitting Algorithm for R-tree',
279 * C.H.Ang and T.C.Tan
281 Datum
282 gist_box_picksplit(PG_FUNCTION_ARGS)
284 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
285 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
286 OffsetNumber i;
287 OffsetNumber *listL,
288 *listR,
289 *listB,
290 *listT;
291 BOX *unionL,
292 *unionR,
293 *unionB,
294 *unionT;
295 int posL,
296 posR,
297 posB,
298 posT;
299 BOX pageunion;
300 BOX *cur;
301 char direction = ' ';
302 bool allisequal = true;
303 OffsetNumber maxoff;
304 int nbytes;
306 posL = posR = posB = posT = 0;
307 maxoff = entryvec->n - 1;
309 cur = DatumGetBoxP(entryvec->vector[FirstOffsetNumber].key);
310 memcpy((void *) &pageunion, (void *) cur, sizeof(BOX));
312 /* find MBR */
313 for (i = OffsetNumberNext(FirstOffsetNumber); i <= maxoff; i = OffsetNumberNext(i))
315 cur = DatumGetBoxP(entryvec->vector[i].key);
316 if (allisequal == true && (
317 pageunion.high.x != cur->high.x ||
318 pageunion.high.y != cur->high.y ||
319 pageunion.low.x != cur->low.x ||
320 pageunion.low.y != cur->low.y
322 allisequal = false;
324 adjustBox(&pageunion, cur);
327 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
328 listL = (OffsetNumber *) palloc(nbytes);
329 listR = (OffsetNumber *) palloc(nbytes);
330 unionL = (BOX *) palloc(sizeof(BOX));
331 unionR = (BOX *) palloc(sizeof(BOX));
332 if (allisequal)
334 cur = DatumGetBoxP(entryvec->vector[OffsetNumberNext(FirstOffsetNumber)].key);
335 if (memcmp((void *) cur, (void *) &pageunion, sizeof(BOX)) == 0)
337 v->spl_left = listL;
338 v->spl_right = listR;
339 v->spl_nleft = v->spl_nright = 0;
340 memcpy((void *) unionL, (void *) &pageunion, sizeof(BOX));
341 memcpy((void *) unionR, (void *) &pageunion, sizeof(BOX));
343 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
345 if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
347 v->spl_left[v->spl_nleft] = i;
348 v->spl_nleft++;
350 else
352 v->spl_right[v->spl_nright] = i;
353 v->spl_nright++;
357 if (v->spl_ldatum_exists)
358 adjustBox(unionL, DatumGetBoxP(v->spl_ldatum));
359 v->spl_ldatum = BoxPGetDatum(unionL);
361 if (v->spl_rdatum_exists)
362 adjustBox(unionR, DatumGetBoxP(v->spl_rdatum));
363 v->spl_rdatum = BoxPGetDatum(unionR);
365 v->spl_ldatum_exists = v->spl_rdatum_exists = false;
367 PG_RETURN_POINTER(v);
371 listB = (OffsetNumber *) palloc(nbytes);
372 listT = (OffsetNumber *) palloc(nbytes);
373 unionB = (BOX *) palloc(sizeof(BOX));
374 unionT = (BOX *) palloc(sizeof(BOX));
376 #define ADDLIST( list, unionD, pos, num ) do { \
377 if ( pos ) { \
378 if ( (unionD)->high.x < cur->high.x ) (unionD)->high.x = cur->high.x; \
379 if ( (unionD)->low.x > cur->low.x ) (unionD)->low.x = cur->low.x; \
380 if ( (unionD)->high.y < cur->high.y ) (unionD)->high.y = cur->high.y; \
381 if ( (unionD)->low.y > cur->low.y ) (unionD)->low.y = cur->low.y; \
382 } else { \
383 memcpy( (void*)(unionD), (void*) cur, sizeof( BOX ) ); \
385 (list)[pos] = num; \
386 (pos)++; \
387 } while(0)
389 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
391 cur = DatumGetBoxP(entryvec->vector[i].key);
392 if (cur->low.x - pageunion.low.x < pageunion.high.x - cur->high.x)
393 ADDLIST(listL, unionL, posL, i);
394 else
395 ADDLIST(listR, unionR, posR, i);
396 if (cur->low.y - pageunion.low.y < pageunion.high.y - cur->high.y)
397 ADDLIST(listB, unionB, posB, i);
398 else
399 ADDLIST(listT, unionT, posT, i);
402 #define LIMIT_RATIO 0.1
403 #define _IS_BADRATIO(x,y) ( (y) == 0 || (float)(x)/(float)(y) < LIMIT_RATIO )
404 #define IS_BADRATIO(x,y) ( _IS_BADRATIO((x),(y)) || _IS_BADRATIO((y),(x)) )
405 /* bad disposition, try to split by centers of boxes */
406 if (IS_BADRATIO(posR, posL) && IS_BADRATIO(posT, posB))
408 double avgCenterX = 0.0,
409 avgCenterY = 0.0;
410 double CenterX,
411 CenterY;
413 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
415 cur = DatumGetBoxP(entryvec->vector[i].key);
416 avgCenterX += ((double) cur->high.x + (double) cur->low.x) / 2.0;
417 avgCenterY += ((double) cur->high.y + (double) cur->low.y) / 2.0;
420 avgCenterX /= maxoff;
421 avgCenterY /= maxoff;
423 posL = posR = posB = posT = 0;
424 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
426 cur = DatumGetBoxP(entryvec->vector[i].key);
428 CenterX = ((double) cur->high.x + (double) cur->low.x) / 2.0;
429 CenterY = ((double) cur->high.y + (double) cur->low.y) / 2.0;
431 if (CenterX < avgCenterX)
432 ADDLIST(listL, unionL, posL, i);
433 else if (CenterX == avgCenterX)
435 if (posL > posR)
436 ADDLIST(listR, unionR, posR, i);
437 else
438 ADDLIST(listL, unionL, posL, i);
440 else
441 ADDLIST(listR, unionR, posR, i);
443 if (CenterY < avgCenterY)
444 ADDLIST(listB, unionB, posB, i);
445 else if (CenterY == avgCenterY)
447 if (posB > posT)
448 ADDLIST(listT, unionT, posT, i);
449 else
450 ADDLIST(listB, unionB, posB, i);
452 else
453 ADDLIST(listT, unionT, posT, i);
457 /* which split more optimal? */
458 if (Max(posL, posR) < Max(posB, posT))
459 direction = 'x';
460 else if (Max(posL, posR) > Max(posB, posT))
461 direction = 'y';
462 else
464 Datum interLR = DirectFunctionCall2(rt_box_inter,
465 BoxPGetDatum(unionL),
466 BoxPGetDatum(unionR));
467 Datum interBT = DirectFunctionCall2(rt_box_inter,
468 BoxPGetDatum(unionB),
469 BoxPGetDatum(unionT));
470 double sizeLR,
471 sizeBT;
473 sizeLR = size_box(interLR);
474 sizeBT = size_box(interBT);
476 if (sizeLR < sizeBT)
477 direction = 'x';
478 else
479 direction = 'y';
482 if (direction == 'x')
483 chooseLR(v,
484 listL, posL, unionL,
485 listR, posR, unionR);
486 else
487 chooseLR(v,
488 listB, posB, unionB,
489 listT, posT, unionT);
491 PG_RETURN_POINTER(v);
495 * Equality method
497 Datum
498 gist_box_same(PG_FUNCTION_ARGS)
500 BOX *b1 = PG_GETARG_BOX_P(0);
501 BOX *b2 = PG_GETARG_BOX_P(1);
502 bool *result = (bool *) PG_GETARG_POINTER(2);
504 if (b1 && b2)
505 *result = DatumGetBool(DirectFunctionCall2(box_same,
506 PointerGetDatum(b1),
507 PointerGetDatum(b2)));
508 else
509 *result = (b1 == NULL && b2 == NULL) ? TRUE : FALSE;
510 PG_RETURN_POINTER(result);
514 * Leaf-level consistency for boxes: just apply the query operator
516 static bool
517 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
519 bool retval;
521 switch (strategy)
523 case RTLeftStrategyNumber:
524 retval = DatumGetBool(DirectFunctionCall2(box_left,
525 PointerGetDatum(key),
526 PointerGetDatum(query)));
527 break;
528 case RTOverLeftStrategyNumber:
529 retval = DatumGetBool(DirectFunctionCall2(box_overleft,
530 PointerGetDatum(key),
531 PointerGetDatum(query)));
532 break;
533 case RTOverlapStrategyNumber:
534 retval = DatumGetBool(DirectFunctionCall2(box_overlap,
535 PointerGetDatum(key),
536 PointerGetDatum(query)));
537 break;
538 case RTOverRightStrategyNumber:
539 retval = DatumGetBool(DirectFunctionCall2(box_overright,
540 PointerGetDatum(key),
541 PointerGetDatum(query)));
542 break;
543 case RTRightStrategyNumber:
544 retval = DatumGetBool(DirectFunctionCall2(box_right,
545 PointerGetDatum(key),
546 PointerGetDatum(query)));
547 break;
548 case RTSameStrategyNumber:
549 retval = DatumGetBool(DirectFunctionCall2(box_same,
550 PointerGetDatum(key),
551 PointerGetDatum(query)));
552 break;
553 case RTContainsStrategyNumber:
554 case RTOldContainsStrategyNumber:
555 retval = DatumGetBool(DirectFunctionCall2(box_contain,
556 PointerGetDatum(key),
557 PointerGetDatum(query)));
558 break;
559 case RTContainedByStrategyNumber:
560 case RTOldContainedByStrategyNumber:
561 retval = DatumGetBool(DirectFunctionCall2(box_contained,
562 PointerGetDatum(key),
563 PointerGetDatum(query)));
564 break;
565 case RTOverBelowStrategyNumber:
566 retval = DatumGetBool(DirectFunctionCall2(box_overbelow,
567 PointerGetDatum(key),
568 PointerGetDatum(query)));
569 break;
570 case RTBelowStrategyNumber:
571 retval = DatumGetBool(DirectFunctionCall2(box_below,
572 PointerGetDatum(key),
573 PointerGetDatum(query)));
574 break;
575 case RTAboveStrategyNumber:
576 retval = DatumGetBool(DirectFunctionCall2(box_above,
577 PointerGetDatum(key),
578 PointerGetDatum(query)));
579 break;
580 case RTOverAboveStrategyNumber:
581 retval = DatumGetBool(DirectFunctionCall2(box_overabove,
582 PointerGetDatum(key),
583 PointerGetDatum(query)));
584 break;
585 default:
586 retval = FALSE;
588 return retval;
591 static double
592 size_box(Datum dbox)
594 BOX *box = DatumGetBoxP(dbox);
596 if (box == NULL || box->high.x <= box->low.x || box->high.y <= box->low.y)
597 return 0.0;
598 return (box->high.x - box->low.x) * (box->high.y - box->low.y);
601 /*****************************************
602 * Common rtree functions (for boxes, polygons, and circles)
603 *****************************************/
606 * Internal-page consistency for all these types
608 * We can use the same function since all types use bounding boxes as the
609 * internal-page representation.
611 static bool
612 rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy)
614 bool retval;
616 switch (strategy)
618 case RTLeftStrategyNumber:
619 retval = !DatumGetBool(DirectFunctionCall2(box_overright,
620 PointerGetDatum(key),
621 PointerGetDatum(query)));
622 break;
623 case RTOverLeftStrategyNumber:
624 retval = !DatumGetBool(DirectFunctionCall2(box_right,
625 PointerGetDatum(key),
626 PointerGetDatum(query)));
627 break;
628 case RTOverlapStrategyNumber:
629 retval = DatumGetBool(DirectFunctionCall2(box_overlap,
630 PointerGetDatum(key),
631 PointerGetDatum(query)));
632 break;
633 case RTOverRightStrategyNumber:
634 retval = !DatumGetBool(DirectFunctionCall2(box_left,
635 PointerGetDatum(key),
636 PointerGetDatum(query)));
637 break;
638 case RTRightStrategyNumber:
639 retval = !DatumGetBool(DirectFunctionCall2(box_overleft,
640 PointerGetDatum(key),
641 PointerGetDatum(query)));
642 break;
643 case RTSameStrategyNumber:
644 case RTContainsStrategyNumber:
645 case RTOldContainsStrategyNumber:
646 retval = DatumGetBool(DirectFunctionCall2(box_contain,
647 PointerGetDatum(key),
648 PointerGetDatum(query)));
649 break;
650 case RTContainedByStrategyNumber:
651 case RTOldContainedByStrategyNumber:
652 retval = DatumGetBool(DirectFunctionCall2(box_overlap,
653 PointerGetDatum(key),
654 PointerGetDatum(query)));
655 break;
656 case RTOverBelowStrategyNumber:
657 retval = !DatumGetBool(DirectFunctionCall2(box_above,
658 PointerGetDatum(key),
659 PointerGetDatum(query)));
660 break;
661 case RTBelowStrategyNumber:
662 retval = !DatumGetBool(DirectFunctionCall2(box_overabove,
663 PointerGetDatum(key),
664 PointerGetDatum(query)));
665 break;
666 case RTAboveStrategyNumber:
667 retval = !DatumGetBool(DirectFunctionCall2(box_overbelow,
668 PointerGetDatum(key),
669 PointerGetDatum(query)));
670 break;
671 case RTOverAboveStrategyNumber:
672 retval = !DatumGetBool(DirectFunctionCall2(box_below,
673 PointerGetDatum(key),
674 PointerGetDatum(query)));
675 break;
676 default:
677 retval = FALSE;
679 return retval;
682 /**************************************************
683 * Polygon ops
684 **************************************************/
687 * GiST compress for polygons: represent a polygon by its bounding box
689 Datum
690 gist_poly_compress(PG_FUNCTION_ARGS)
692 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
693 GISTENTRY *retval;
695 if (entry->leafkey)
697 retval = palloc(sizeof(GISTENTRY));
698 if (DatumGetPointer(entry->key) != NULL)
700 POLYGON *in = DatumGetPolygonP(entry->key);
701 BOX *r;
703 r = (BOX *) palloc(sizeof(BOX));
704 memcpy((void *) r, (void *) &(in->boundbox), sizeof(BOX));
705 gistentryinit(*retval, PointerGetDatum(r),
706 entry->rel, entry->page,
707 entry->offset, FALSE);
710 else
712 gistentryinit(*retval, (Datum) 0,
713 entry->rel, entry->page,
714 entry->offset, FALSE);
717 else
718 retval = entry;
719 PG_RETURN_POINTER(retval);
723 * The GiST Consistent method for polygons
725 Datum
726 gist_poly_consistent(PG_FUNCTION_ARGS)
728 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
729 POLYGON *query = PG_GETARG_POLYGON_P(1);
730 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
731 /* Oid subtype = PG_GETARG_OID(3); */
732 bool *recheck = (bool *) PG_GETARG_POINTER(4);
733 bool result;
735 /* All cases served by this function are inexact */
736 *recheck = true;
738 if (DatumGetBoxP(entry->key) == NULL || query == NULL)
739 PG_RETURN_BOOL(FALSE);
742 * Since the operators require recheck anyway, we can just use
743 * rtree_internal_consistent even at leaf nodes. (This works in part
744 * because the index entries are bounding boxes not polygons.)
746 result = rtree_internal_consistent(DatumGetBoxP(entry->key),
747 &(query->boundbox), strategy);
749 /* Avoid memory leak if supplied poly is toasted */
750 PG_FREE_IF_COPY(query, 1);
752 PG_RETURN_BOOL(result);
755 /**************************************************
756 * Circle ops
757 **************************************************/
760 * GiST compress for circles: represent a circle by its bounding box
762 Datum
763 gist_circle_compress(PG_FUNCTION_ARGS)
765 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
766 GISTENTRY *retval;
768 if (entry->leafkey)
770 retval = palloc(sizeof(GISTENTRY));
771 if (DatumGetCircleP(entry->key) != NULL)
773 CIRCLE *in = DatumGetCircleP(entry->key);
774 BOX *r;
776 r = (BOX *) palloc(sizeof(BOX));
777 r->high.x = in->center.x + in->radius;
778 r->low.x = in->center.x - in->radius;
779 r->high.y = in->center.y + in->radius;
780 r->low.y = in->center.y - in->radius;
781 gistentryinit(*retval, PointerGetDatum(r),
782 entry->rel, entry->page,
783 entry->offset, FALSE);
786 else
788 gistentryinit(*retval, (Datum) 0,
789 entry->rel, entry->page,
790 entry->offset, FALSE);
793 else
794 retval = entry;
795 PG_RETURN_POINTER(retval);
799 * The GiST Consistent method for circles
801 Datum
802 gist_circle_consistent(PG_FUNCTION_ARGS)
804 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
805 CIRCLE *query = PG_GETARG_CIRCLE_P(1);
806 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
807 /* Oid subtype = PG_GETARG_OID(3); */
808 bool *recheck = (bool *) PG_GETARG_POINTER(4);
809 BOX bbox;
810 bool result;
812 /* All cases served by this function are inexact */
813 *recheck = true;
815 if (DatumGetBoxP(entry->key) == NULL || query == NULL)
816 PG_RETURN_BOOL(FALSE);
819 * Since the operators require recheck anyway, we can just use
820 * rtree_internal_consistent even at leaf nodes. (This works in part
821 * because the index entries are bounding boxes not circles.)
823 bbox.high.x = query->center.x + query->radius;
824 bbox.low.x = query->center.x - query->radius;
825 bbox.high.y = query->center.y + query->radius;
826 bbox.low.y = query->center.y - query->radius;
828 result = rtree_internal_consistent(DatumGetBoxP(entry->key),
829 &bbox, strategy);
831 PG_RETURN_BOOL(result);