1 /*-------------------------------------------------------------------------
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-2009, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
15 *-------------------------------------------------------------------------
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 /**************************************************
33 **************************************************/
36 rt_box_union(PG_FUNCTION_ARGS
)
38 BOX
*a
= PG_GETARG_BOX_P(0);
39 BOX
*b
= PG_GETARG_BOX_P(1);
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
);
53 rt_box_inter(PG_FUNCTION_ARGS
)
55 BOX
*a
= PG_GETARG_BOX_P(0);
56 BOX
*b
= PG_GETARG_BOX_P(1);
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
)
69 /* Indicate "no intersection" by returning NULL pointer */
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.
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);
90 /* Oid subtype = PG_GETARG_OID(3); */
91 bool *recheck
= (bool *) PG_GETARG_POINTER(4);
93 /* All cases served by this function are exact */
96 if (DatumGetBoxP(entry
->key
) == NULL
|| query
== NULL
)
97 PG_RETURN_BOOL(FALSE
);
100 * if entry is not leaf, use rtree_internal_consistent, else use
101 * gist_box_leaf_consistent
103 if (GIST_LEAF(entry
))
104 PG_RETURN_BOOL(gist_box_leaf_consistent(DatumGetBoxP(entry
->key
),
108 PG_RETURN_BOOL(rtree_internal_consistent(DatumGetBoxP(entry
->key
),
114 adjustBox(BOX
*b
, BOX
*addon
)
116 if (b
->high
.x
< addon
->high
.x
)
117 b
->high
.x
= addon
->high
.x
;
118 if (b
->low
.x
> addon
->low
.x
)
119 b
->low
.x
= addon
->low
.x
;
120 if (b
->high
.y
< addon
->high
.y
)
121 b
->high
.y
= addon
->high
.y
;
122 if (b
->low
.y
> addon
->low
.y
)
123 b
->low
.y
= addon
->low
.y
;
127 * The GiST Union method for boxes
129 * returns the minimal bounding box that encloses all the entries in entryvec
132 gist_box_union(PG_FUNCTION_ARGS
)
134 GistEntryVector
*entryvec
= (GistEntryVector
*) PG_GETARG_POINTER(0);
135 int *sizep
= (int *) PG_GETARG_POINTER(1);
141 numranges
= entryvec
->n
;
142 pageunion
= (BOX
*) palloc(sizeof(BOX
));
143 cur
= DatumGetBoxP(entryvec
->vector
[0].key
);
144 memcpy((void *) pageunion
, (void *) cur
, sizeof(BOX
));
146 for (i
= 1; i
< numranges
; i
++)
148 cur
= DatumGetBoxP(entryvec
->vector
[i
].key
);
149 adjustBox(pageunion
, cur
);
151 *sizep
= sizeof(BOX
);
153 PG_RETURN_POINTER(pageunion
);
157 * GiST Compress methods for boxes
159 * do not do anything.
162 gist_box_compress(PG_FUNCTION_ARGS
)
164 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
168 * GiST DeCompress method for boxes (also used for polygons and circles)
170 * do not do anything --- we just use the stored box as is.
173 gist_box_decompress(PG_FUNCTION_ARGS
)
175 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
179 * The GiST Penalty method for boxes
181 * As in the R-tree paper, we use change in area as our penalty metric
184 gist_box_penalty(PG_FUNCTION_ARGS
)
186 GISTENTRY
*origentry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
187 GISTENTRY
*newentry
= (GISTENTRY
*) PG_GETARG_POINTER(1);
188 float *result
= (float *) PG_GETARG_POINTER(2);
191 ud
= DirectFunctionCall2(rt_box_union
, origentry
->key
, newentry
->key
);
192 *result
= (float) (size_box(ud
) - size_box(origentry
->key
));
193 PG_RETURN_POINTER(result
);
197 chooseLR(GIST_SPLITVEC
*v
,
198 OffsetNumber
*list1
, int nlist1
, BOX
*union1
,
199 OffsetNumber
*list2
, int nlist2
, BOX
*union2
)
201 bool firstToLeft
= true;
203 if (v
->spl_ldatum_exists
|| v
->spl_rdatum_exists
)
205 if (v
->spl_ldatum_exists
&& v
->spl_rdatum_exists
)
214 adjustBox(&LRl
, DatumGetBoxP(v
->spl_ldatum
));
215 adjustBox(&LRr
, DatumGetBoxP(v
->spl_rdatum
));
216 adjustBox(&RLl
, DatumGetBoxP(v
->spl_ldatum
));
217 adjustBox(&RLr
, DatumGetBoxP(v
->spl_rdatum
));
219 sizeLR
= size_box(DirectFunctionCall2(rt_box_inter
, BoxPGetDatum(&LRl
), BoxPGetDatum(&LRr
)));
220 sizeRL
= size_box(DirectFunctionCall2(rt_box_inter
, BoxPGetDatum(&RLl
), BoxPGetDatum(&RLr
)));
233 gistentryinit(oldUnion
, (v
->spl_ldatum_exists
) ? v
->spl_ldatum
: v
->spl_rdatum
,
234 NULL
, NULL
, InvalidOffsetNumber
, FALSE
);
236 gistentryinit(addon
, BoxPGetDatum(union1
), NULL
, NULL
, InvalidOffsetNumber
, FALSE
);
237 DirectFunctionCall3(gist_box_penalty
, PointerGetDatum(&oldUnion
), PointerGetDatum(&union1
), PointerGetDatum(&p1
));
238 gistentryinit(addon
, BoxPGetDatum(union2
), NULL
, NULL
, InvalidOffsetNumber
, FALSE
);
239 DirectFunctionCall3(gist_box_penalty
, PointerGetDatum(&oldUnion
), PointerGetDatum(&union2
), PointerGetDatum(&p2
));
241 if ((v
->spl_ldatum_exists
&& p1
> p2
) || (v
->spl_rdatum_exists
&& p1
< p2
))
249 v
->spl_right
= list2
;
250 v
->spl_nleft
= nlist1
;
251 v
->spl_nright
= nlist2
;
252 if (v
->spl_ldatum_exists
)
253 adjustBox(union1
, DatumGetBoxP(v
->spl_ldatum
));
254 v
->spl_ldatum
= BoxPGetDatum(union1
);
255 if (v
->spl_rdatum_exists
)
256 adjustBox(union2
, DatumGetBoxP(v
->spl_rdatum
));
257 v
->spl_rdatum
= BoxPGetDatum(union2
);
262 v
->spl_right
= list1
;
263 v
->spl_nleft
= nlist2
;
264 v
->spl_nright
= nlist1
;
265 if (v
->spl_ldatum_exists
)
266 adjustBox(union2
, DatumGetBoxP(v
->spl_ldatum
));
267 v
->spl_ldatum
= BoxPGetDatum(union2
);
268 if (v
->spl_rdatum_exists
)
269 adjustBox(union1
, DatumGetBoxP(v
->spl_rdatum
));
270 v
->spl_rdatum
= BoxPGetDatum(union1
);
273 v
->spl_ldatum_exists
= v
->spl_rdatum_exists
= false;
277 * Trivial split: half of entries will be placed on one page
278 * and another half - to another
281 fallbackSplit(GistEntryVector
*entryvec
, GIST_SPLITVEC
*v
)
289 maxoff
= entryvec
->n
- 1;
291 nbytes
= (maxoff
+ 2) * sizeof(OffsetNumber
);
292 v
->spl_left
= (OffsetNumber
*) palloc(nbytes
);
293 v
->spl_right
= (OffsetNumber
*) palloc(nbytes
);
294 v
->spl_nleft
= v
->spl_nright
= 0;
296 for (i
= FirstOffsetNumber
; i
<= maxoff
; i
= OffsetNumberNext(i
))
298 BOX
*cur
= DatumGetBoxP(entryvec
->vector
[i
].key
);
300 if (i
<= (maxoff
- FirstOffsetNumber
+ 1) / 2)
302 v
->spl_left
[v
->spl_nleft
] = i
;
305 unionL
= (BOX
*) palloc(sizeof(BOX
));
309 adjustBox(unionL
, cur
);
315 v
->spl_right
[v
->spl_nright
] = i
;
318 unionR
= (BOX
*) palloc(sizeof(BOX
));
322 adjustBox(unionR
, cur
);
328 if (v
->spl_ldatum_exists
)
329 adjustBox(unionL
, DatumGetBoxP(v
->spl_ldatum
));
330 v
->spl_ldatum
= BoxPGetDatum(unionL
);
332 if (v
->spl_rdatum_exists
)
333 adjustBox(unionR
, DatumGetBoxP(v
->spl_rdatum
));
334 v
->spl_rdatum
= BoxPGetDatum(unionR
);
336 v
->spl_ldatum_exists
= v
->spl_rdatum_exists
= false;
340 * The GiST PickSplit method
342 * New linear algorithm, see 'New Linear Node Splitting Algorithm for R-tree',
343 * C.H.Ang and T.C.Tan
346 gist_box_picksplit(PG_FUNCTION_ARGS
)
348 GistEntryVector
*entryvec
= (GistEntryVector
*) PG_GETARG_POINTER(0);
349 GIST_SPLITVEC
*v
= (GIST_SPLITVEC
*) PG_GETARG_POINTER(1);
365 char direction
= ' ';
366 bool allisequal
= true;
370 posL
= posR
= posB
= posT
= 0;
371 maxoff
= entryvec
->n
- 1;
373 cur
= DatumGetBoxP(entryvec
->vector
[FirstOffsetNumber
].key
);
374 memcpy((void *) &pageunion
, (void *) cur
, sizeof(BOX
));
377 for (i
= OffsetNumberNext(FirstOffsetNumber
); i
<= maxoff
; i
= OffsetNumberNext(i
))
379 cur
= DatumGetBoxP(entryvec
->vector
[i
].key
);
380 if (allisequal
== true && (
381 pageunion
.high
.x
!= cur
->high
.x
||
382 pageunion
.high
.y
!= cur
->high
.y
||
383 pageunion
.low
.x
!= cur
->low
.x
||
384 pageunion
.low
.y
!= cur
->low
.y
388 adjustBox(&pageunion
, cur
);
394 * All entries are the same
396 fallbackSplit(entryvec
, v
);
397 PG_RETURN_POINTER(v
);
400 nbytes
= (maxoff
+ 2) * sizeof(OffsetNumber
);
401 listL
= (OffsetNumber
*) palloc(nbytes
);
402 listR
= (OffsetNumber
*) palloc(nbytes
);
403 listB
= (OffsetNumber
*) palloc(nbytes
);
404 listT
= (OffsetNumber
*) palloc(nbytes
);
405 unionL
= (BOX
*) palloc(sizeof(BOX
));
406 unionR
= (BOX
*) palloc(sizeof(BOX
));
407 unionB
= (BOX
*) palloc(sizeof(BOX
));
408 unionT
= (BOX
*) palloc(sizeof(BOX
));
410 #define ADDLIST( list, unionD, pos, num ) do { \
412 if ( (unionD)->high.x < cur->high.x ) (unionD)->high.x = cur->high.x; \
413 if ( (unionD)->low.x > cur->low.x ) (unionD)->low.x = cur->low.x; \
414 if ( (unionD)->high.y < cur->high.y ) (unionD)->high.y = cur->high.y; \
415 if ( (unionD)->low.y > cur->low.y ) (unionD)->low.y = cur->low.y; \
417 memcpy( (void*)(unionD), (void*) cur, sizeof( BOX ) ); \
423 for (i
= FirstOffsetNumber
; i
<= maxoff
; i
= OffsetNumberNext(i
))
425 cur
= DatumGetBoxP(entryvec
->vector
[i
].key
);
426 if (cur
->low
.x
- pageunion
.low
.x
< pageunion
.high
.x
- cur
->high
.x
)
427 ADDLIST(listL
, unionL
, posL
, i
);
429 ADDLIST(listR
, unionR
, posR
, i
);
430 if (cur
->low
.y
- pageunion
.low
.y
< pageunion
.high
.y
- cur
->high
.y
)
431 ADDLIST(listB
, unionB
, posB
, i
);
433 ADDLIST(listT
, unionT
, posT
, i
);
436 #define LIMIT_RATIO 0.1
437 #define _IS_BADRATIO(x,y) ( (y) == 0 || (float)(x)/(float)(y) < LIMIT_RATIO )
438 #define IS_BADRATIO(x,y) ( _IS_BADRATIO((x),(y)) || _IS_BADRATIO((y),(x)) )
439 /* bad disposition, try to split by centers of boxes */
440 if (IS_BADRATIO(posR
, posL
) && IS_BADRATIO(posT
, posB
))
442 double avgCenterX
= 0.0,
447 for (i
= FirstOffsetNumber
; i
<= maxoff
; i
= OffsetNumberNext(i
))
449 cur
= DatumGetBoxP(entryvec
->vector
[i
].key
);
450 avgCenterX
+= ((double) cur
->high
.x
+ (double) cur
->low
.x
) / 2.0;
451 avgCenterY
+= ((double) cur
->high
.y
+ (double) cur
->low
.y
) / 2.0;
454 avgCenterX
/= maxoff
;
455 avgCenterY
/= maxoff
;
457 posL
= posR
= posB
= posT
= 0;
458 for (i
= FirstOffsetNumber
; i
<= maxoff
; i
= OffsetNumberNext(i
))
460 cur
= DatumGetBoxP(entryvec
->vector
[i
].key
);
462 CenterX
= ((double) cur
->high
.x
+ (double) cur
->low
.x
) / 2.0;
463 CenterY
= ((double) cur
->high
.y
+ (double) cur
->low
.y
) / 2.0;
465 if (CenterX
< avgCenterX
)
466 ADDLIST(listL
, unionL
, posL
, i
);
467 else if (CenterX
== avgCenterX
)
470 ADDLIST(listR
, unionR
, posR
, i
);
472 ADDLIST(listL
, unionL
, posL
, i
);
475 ADDLIST(listR
, unionR
, posR
, i
);
477 if (CenterY
< avgCenterY
)
478 ADDLIST(listB
, unionB
, posB
, i
);
479 else if (CenterY
== avgCenterY
)
482 ADDLIST(listT
, unionT
, posT
, i
);
484 ADDLIST(listB
, unionB
, posB
, i
);
487 ADDLIST(listT
, unionT
, posT
, i
);
490 if (IS_BADRATIO(posR
, posL
) && IS_BADRATIO(posT
, posB
))
492 fallbackSplit(entryvec
, v
);
493 PG_RETURN_POINTER(v
);
497 /* which split more optimal? */
498 if (Max(posL
, posR
) < Max(posB
, posT
))
500 else if (Max(posL
, posR
) > Max(posB
, posT
))
504 Datum interLR
= DirectFunctionCall2(rt_box_inter
,
505 BoxPGetDatum(unionL
),
506 BoxPGetDatum(unionR
));
507 Datum interBT
= DirectFunctionCall2(rt_box_inter
,
508 BoxPGetDatum(unionB
),
509 BoxPGetDatum(unionT
));
513 sizeLR
= size_box(interLR
);
514 sizeBT
= size_box(interBT
);
522 if (direction
== 'x')
525 listR
, posR
, unionR
);
529 listT
, posT
, unionT
);
531 PG_RETURN_POINTER(v
);
538 gist_box_same(PG_FUNCTION_ARGS
)
540 BOX
*b1
= PG_GETARG_BOX_P(0);
541 BOX
*b2
= PG_GETARG_BOX_P(1);
542 bool *result
= (bool *) PG_GETARG_POINTER(2);
545 *result
= DatumGetBool(DirectFunctionCall2(box_same
,
547 PointerGetDatum(b2
)));
549 *result
= (b1
== NULL
&& b2
== NULL
) ? TRUE
: FALSE
;
550 PG_RETURN_POINTER(result
);
554 * Leaf-level consistency for boxes: just apply the query operator
557 gist_box_leaf_consistent(BOX
*key
, BOX
*query
, StrategyNumber strategy
)
563 case RTLeftStrategyNumber
:
564 retval
= DatumGetBool(DirectFunctionCall2(box_left
,
565 PointerGetDatum(key
),
566 PointerGetDatum(query
)));
568 case RTOverLeftStrategyNumber
:
569 retval
= DatumGetBool(DirectFunctionCall2(box_overleft
,
570 PointerGetDatum(key
),
571 PointerGetDatum(query
)));
573 case RTOverlapStrategyNumber
:
574 retval
= DatumGetBool(DirectFunctionCall2(box_overlap
,
575 PointerGetDatum(key
),
576 PointerGetDatum(query
)));
578 case RTOverRightStrategyNumber
:
579 retval
= DatumGetBool(DirectFunctionCall2(box_overright
,
580 PointerGetDatum(key
),
581 PointerGetDatum(query
)));
583 case RTRightStrategyNumber
:
584 retval
= DatumGetBool(DirectFunctionCall2(box_right
,
585 PointerGetDatum(key
),
586 PointerGetDatum(query
)));
588 case RTSameStrategyNumber
:
589 retval
= DatumGetBool(DirectFunctionCall2(box_same
,
590 PointerGetDatum(key
),
591 PointerGetDatum(query
)));
593 case RTContainsStrategyNumber
:
594 case RTOldContainsStrategyNumber
:
595 retval
= DatumGetBool(DirectFunctionCall2(box_contain
,
596 PointerGetDatum(key
),
597 PointerGetDatum(query
)));
599 case RTContainedByStrategyNumber
:
600 case RTOldContainedByStrategyNumber
:
601 retval
= DatumGetBool(DirectFunctionCall2(box_contained
,
602 PointerGetDatum(key
),
603 PointerGetDatum(query
)));
605 case RTOverBelowStrategyNumber
:
606 retval
= DatumGetBool(DirectFunctionCall2(box_overbelow
,
607 PointerGetDatum(key
),
608 PointerGetDatum(query
)));
610 case RTBelowStrategyNumber
:
611 retval
= DatumGetBool(DirectFunctionCall2(box_below
,
612 PointerGetDatum(key
),
613 PointerGetDatum(query
)));
615 case RTAboveStrategyNumber
:
616 retval
= DatumGetBool(DirectFunctionCall2(box_above
,
617 PointerGetDatum(key
),
618 PointerGetDatum(query
)));
620 case RTOverAboveStrategyNumber
:
621 retval
= DatumGetBool(DirectFunctionCall2(box_overabove
,
622 PointerGetDatum(key
),
623 PointerGetDatum(query
)));
634 BOX
*box
= DatumGetBoxP(dbox
);
636 if (box
== NULL
|| box
->high
.x
<= box
->low
.x
|| box
->high
.y
<= box
->low
.y
)
638 return (box
->high
.x
- box
->low
.x
) * (box
->high
.y
- box
->low
.y
);
641 /*****************************************
642 * Common rtree functions (for boxes, polygons, and circles)
643 *****************************************/
646 * Internal-page consistency for all these types
648 * We can use the same function since all types use bounding boxes as the
649 * internal-page representation.
652 rtree_internal_consistent(BOX
*key
, BOX
*query
, StrategyNumber strategy
)
658 case RTLeftStrategyNumber
:
659 retval
= !DatumGetBool(DirectFunctionCall2(box_overright
,
660 PointerGetDatum(key
),
661 PointerGetDatum(query
)));
663 case RTOverLeftStrategyNumber
:
664 retval
= !DatumGetBool(DirectFunctionCall2(box_right
,
665 PointerGetDatum(key
),
666 PointerGetDatum(query
)));
668 case RTOverlapStrategyNumber
:
669 retval
= DatumGetBool(DirectFunctionCall2(box_overlap
,
670 PointerGetDatum(key
),
671 PointerGetDatum(query
)));
673 case RTOverRightStrategyNumber
:
674 retval
= !DatumGetBool(DirectFunctionCall2(box_left
,
675 PointerGetDatum(key
),
676 PointerGetDatum(query
)));
678 case RTRightStrategyNumber
:
679 retval
= !DatumGetBool(DirectFunctionCall2(box_overleft
,
680 PointerGetDatum(key
),
681 PointerGetDatum(query
)));
683 case RTSameStrategyNumber
:
684 case RTContainsStrategyNumber
:
685 case RTOldContainsStrategyNumber
:
686 retval
= DatumGetBool(DirectFunctionCall2(box_contain
,
687 PointerGetDatum(key
),
688 PointerGetDatum(query
)));
690 case RTContainedByStrategyNumber
:
691 case RTOldContainedByStrategyNumber
:
692 retval
= DatumGetBool(DirectFunctionCall2(box_overlap
,
693 PointerGetDatum(key
),
694 PointerGetDatum(query
)));
696 case RTOverBelowStrategyNumber
:
697 retval
= !DatumGetBool(DirectFunctionCall2(box_above
,
698 PointerGetDatum(key
),
699 PointerGetDatum(query
)));
701 case RTBelowStrategyNumber
:
702 retval
= !DatumGetBool(DirectFunctionCall2(box_overabove
,
703 PointerGetDatum(key
),
704 PointerGetDatum(query
)));
706 case RTAboveStrategyNumber
:
707 retval
= !DatumGetBool(DirectFunctionCall2(box_overbelow
,
708 PointerGetDatum(key
),
709 PointerGetDatum(query
)));
711 case RTOverAboveStrategyNumber
:
712 retval
= !DatumGetBool(DirectFunctionCall2(box_below
,
713 PointerGetDatum(key
),
714 PointerGetDatum(query
)));
722 /**************************************************
724 **************************************************/
727 * GiST compress for polygons: represent a polygon by its bounding box
730 gist_poly_compress(PG_FUNCTION_ARGS
)
732 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
737 retval
= palloc(sizeof(GISTENTRY
));
738 if (DatumGetPointer(entry
->key
) != NULL
)
740 POLYGON
*in
= DatumGetPolygonP(entry
->key
);
743 r
= (BOX
*) palloc(sizeof(BOX
));
744 memcpy((void *) r
, (void *) &(in
->boundbox
), sizeof(BOX
));
745 gistentryinit(*retval
, PointerGetDatum(r
),
746 entry
->rel
, entry
->page
,
747 entry
->offset
, FALSE
);
752 gistentryinit(*retval
, (Datum
) 0,
753 entry
->rel
, entry
->page
,
754 entry
->offset
, FALSE
);
759 PG_RETURN_POINTER(retval
);
763 * The GiST Consistent method for polygons
766 gist_poly_consistent(PG_FUNCTION_ARGS
)
768 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
769 POLYGON
*query
= PG_GETARG_POLYGON_P(1);
770 StrategyNumber strategy
= (StrategyNumber
) PG_GETARG_UINT16(2);
772 /* Oid subtype = PG_GETARG_OID(3); */
773 bool *recheck
= (bool *) PG_GETARG_POINTER(4);
776 /* All cases served by this function are inexact */
779 if (DatumGetBoxP(entry
->key
) == NULL
|| query
== NULL
)
780 PG_RETURN_BOOL(FALSE
);
783 * Since the operators require recheck anyway, we can just use
784 * rtree_internal_consistent even at leaf nodes. (This works in part
785 * because the index entries are bounding boxes not polygons.)
787 result
= rtree_internal_consistent(DatumGetBoxP(entry
->key
),
788 &(query
->boundbox
), strategy
);
790 /* Avoid memory leak if supplied poly is toasted */
791 PG_FREE_IF_COPY(query
, 1);
793 PG_RETURN_BOOL(result
);
796 /**************************************************
798 **************************************************/
801 * GiST compress for circles: represent a circle by its bounding box
804 gist_circle_compress(PG_FUNCTION_ARGS
)
806 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
811 retval
= palloc(sizeof(GISTENTRY
));
812 if (DatumGetCircleP(entry
->key
) != NULL
)
814 CIRCLE
*in
= DatumGetCircleP(entry
->key
);
817 r
= (BOX
*) palloc(sizeof(BOX
));
818 r
->high
.x
= in
->center
.x
+ in
->radius
;
819 r
->low
.x
= in
->center
.x
- in
->radius
;
820 r
->high
.y
= in
->center
.y
+ in
->radius
;
821 r
->low
.y
= in
->center
.y
- in
->radius
;
822 gistentryinit(*retval
, PointerGetDatum(r
),
823 entry
->rel
, entry
->page
,
824 entry
->offset
, FALSE
);
829 gistentryinit(*retval
, (Datum
) 0,
830 entry
->rel
, entry
->page
,
831 entry
->offset
, FALSE
);
836 PG_RETURN_POINTER(retval
);
840 * The GiST Consistent method for circles
843 gist_circle_consistent(PG_FUNCTION_ARGS
)
845 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
846 CIRCLE
*query
= PG_GETARG_CIRCLE_P(1);
847 StrategyNumber strategy
= (StrategyNumber
) PG_GETARG_UINT16(2);
849 /* Oid subtype = PG_GETARG_OID(3); */
850 bool *recheck
= (bool *) PG_GETARG_POINTER(4);
854 /* All cases served by this function are inexact */
857 if (DatumGetBoxP(entry
->key
) == NULL
|| query
== NULL
)
858 PG_RETURN_BOOL(FALSE
);
861 * Since the operators require recheck anyway, we can just use
862 * rtree_internal_consistent even at leaf nodes. (This works in part
863 * because the index entries are bounding boxes not circles.)
865 bbox
.high
.x
= query
->center
.x
+ query
->radius
;
866 bbox
.low
.x
= query
->center
.x
- query
->radius
;
867 bbox
.high
.y
= query
->center
.y
+ query
->radius
;
868 bbox
.low
.y
= query
->center
.y
- query
->radius
;
870 result
= rtree_internal_consistent(DatumGetBoxP(entry
->key
),
873 PG_RETURN_BOOL(result
);