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-2008, 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);
89 /* Oid subtype = PG_GETARG_OID(3); */
90 bool *recheck
= (bool *) PG_GETARG_POINTER(4);
92 /* All cases served by this function are exact */
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
),
107 PG_RETURN_BOOL(rtree_internal_consistent(DatumGetBoxP(entry
->key
),
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
131 gist_box_union(PG_FUNCTION_ARGS
)
133 GistEntryVector
*entryvec
= (GistEntryVector
*) PG_GETARG_POINTER(0);
134 int *sizep
= (int *) PG_GETARG_POINTER(1);
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.
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.
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
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);
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
);
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
)
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
)));
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
))
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
);
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
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);
301 char direction
= ' ';
302 bool allisequal
= true;
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
));
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
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
));
334 cur
= DatumGetBoxP(entryvec
->vector
[OffsetNumberNext(FirstOffsetNumber
)].key
);
335 if (memcmp((void *) cur
, (void *) &pageunion
, sizeof(BOX
)) == 0)
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
;
352 v
->spl_right
[v
->spl_nright
] = i
;
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 { \
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; \
383 memcpy( (void*)(unionD), (void*) cur, sizeof( BOX ) ); \
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
);
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
);
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,
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
)
436 ADDLIST(listR
, unionR
, posR
, i
);
438 ADDLIST(listL
, unionL
, posL
, i
);
441 ADDLIST(listR
, unionR
, posR
, i
);
443 if (CenterY
< avgCenterY
)
444 ADDLIST(listB
, unionB
, posB
, i
);
445 else if (CenterY
== avgCenterY
)
448 ADDLIST(listT
, unionT
, posT
, i
);
450 ADDLIST(listB
, unionB
, posB
, i
);
453 ADDLIST(listT
, unionT
, posT
, i
);
457 /* which split more optimal? */
458 if (Max(posL
, posR
) < Max(posB
, posT
))
460 else if (Max(posL
, posR
) > Max(posB
, posT
))
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
));
473 sizeLR
= size_box(interLR
);
474 sizeBT
= size_box(interBT
);
482 if (direction
== 'x')
485 listR
, posR
, unionR
);
489 listT
, posT
, unionT
);
491 PG_RETURN_POINTER(v
);
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);
505 *result
= DatumGetBool(DirectFunctionCall2(box_same
,
507 PointerGetDatum(b2
)));
509 *result
= (b1
== NULL
&& b2
== NULL
) ? TRUE
: FALSE
;
510 PG_RETURN_POINTER(result
);
514 * Leaf-level consistency for boxes: just apply the query operator
517 gist_box_leaf_consistent(BOX
*key
, BOX
*query
, StrategyNumber strategy
)
523 case RTLeftStrategyNumber
:
524 retval
= DatumGetBool(DirectFunctionCall2(box_left
,
525 PointerGetDatum(key
),
526 PointerGetDatum(query
)));
528 case RTOverLeftStrategyNumber
:
529 retval
= DatumGetBool(DirectFunctionCall2(box_overleft
,
530 PointerGetDatum(key
),
531 PointerGetDatum(query
)));
533 case RTOverlapStrategyNumber
:
534 retval
= DatumGetBool(DirectFunctionCall2(box_overlap
,
535 PointerGetDatum(key
),
536 PointerGetDatum(query
)));
538 case RTOverRightStrategyNumber
:
539 retval
= DatumGetBool(DirectFunctionCall2(box_overright
,
540 PointerGetDatum(key
),
541 PointerGetDatum(query
)));
543 case RTRightStrategyNumber
:
544 retval
= DatumGetBool(DirectFunctionCall2(box_right
,
545 PointerGetDatum(key
),
546 PointerGetDatum(query
)));
548 case RTSameStrategyNumber
:
549 retval
= DatumGetBool(DirectFunctionCall2(box_same
,
550 PointerGetDatum(key
),
551 PointerGetDatum(query
)));
553 case RTContainsStrategyNumber
:
554 case RTOldContainsStrategyNumber
:
555 retval
= DatumGetBool(DirectFunctionCall2(box_contain
,
556 PointerGetDatum(key
),
557 PointerGetDatum(query
)));
559 case RTContainedByStrategyNumber
:
560 case RTOldContainedByStrategyNumber
:
561 retval
= DatumGetBool(DirectFunctionCall2(box_contained
,
562 PointerGetDatum(key
),
563 PointerGetDatum(query
)));
565 case RTOverBelowStrategyNumber
:
566 retval
= DatumGetBool(DirectFunctionCall2(box_overbelow
,
567 PointerGetDatum(key
),
568 PointerGetDatum(query
)));
570 case RTBelowStrategyNumber
:
571 retval
= DatumGetBool(DirectFunctionCall2(box_below
,
572 PointerGetDatum(key
),
573 PointerGetDatum(query
)));
575 case RTAboveStrategyNumber
:
576 retval
= DatumGetBool(DirectFunctionCall2(box_above
,
577 PointerGetDatum(key
),
578 PointerGetDatum(query
)));
580 case RTOverAboveStrategyNumber
:
581 retval
= DatumGetBool(DirectFunctionCall2(box_overabove
,
582 PointerGetDatum(key
),
583 PointerGetDatum(query
)));
594 BOX
*box
= DatumGetBoxP(dbox
);
596 if (box
== NULL
|| box
->high
.x
<= box
->low
.x
|| box
->high
.y
<= box
->low
.y
)
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.
612 rtree_internal_consistent(BOX
*key
, BOX
*query
, StrategyNumber strategy
)
618 case RTLeftStrategyNumber
:
619 retval
= !DatumGetBool(DirectFunctionCall2(box_overright
,
620 PointerGetDatum(key
),
621 PointerGetDatum(query
)));
623 case RTOverLeftStrategyNumber
:
624 retval
= !DatumGetBool(DirectFunctionCall2(box_right
,
625 PointerGetDatum(key
),
626 PointerGetDatum(query
)));
628 case RTOverlapStrategyNumber
:
629 retval
= DatumGetBool(DirectFunctionCall2(box_overlap
,
630 PointerGetDatum(key
),
631 PointerGetDatum(query
)));
633 case RTOverRightStrategyNumber
:
634 retval
= !DatumGetBool(DirectFunctionCall2(box_left
,
635 PointerGetDatum(key
),
636 PointerGetDatum(query
)));
638 case RTRightStrategyNumber
:
639 retval
= !DatumGetBool(DirectFunctionCall2(box_overleft
,
640 PointerGetDatum(key
),
641 PointerGetDatum(query
)));
643 case RTSameStrategyNumber
:
644 case RTContainsStrategyNumber
:
645 case RTOldContainsStrategyNumber
:
646 retval
= DatumGetBool(DirectFunctionCall2(box_contain
,
647 PointerGetDatum(key
),
648 PointerGetDatum(query
)));
650 case RTContainedByStrategyNumber
:
651 case RTOldContainedByStrategyNumber
:
652 retval
= DatumGetBool(DirectFunctionCall2(box_overlap
,
653 PointerGetDatum(key
),
654 PointerGetDatum(query
)));
656 case RTOverBelowStrategyNumber
:
657 retval
= !DatumGetBool(DirectFunctionCall2(box_above
,
658 PointerGetDatum(key
),
659 PointerGetDatum(query
)));
661 case RTBelowStrategyNumber
:
662 retval
= !DatumGetBool(DirectFunctionCall2(box_overabove
,
663 PointerGetDatum(key
),
664 PointerGetDatum(query
)));
666 case RTAboveStrategyNumber
:
667 retval
= !DatumGetBool(DirectFunctionCall2(box_overbelow
,
668 PointerGetDatum(key
),
669 PointerGetDatum(query
)));
671 case RTOverAboveStrategyNumber
:
672 retval
= !DatumGetBool(DirectFunctionCall2(box_below
,
673 PointerGetDatum(key
),
674 PointerGetDatum(query
)));
682 /**************************************************
684 **************************************************/
687 * GiST compress for polygons: represent a polygon by its bounding box
690 gist_poly_compress(PG_FUNCTION_ARGS
)
692 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
697 retval
= palloc(sizeof(GISTENTRY
));
698 if (DatumGetPointer(entry
->key
) != NULL
)
700 POLYGON
*in
= DatumGetPolygonP(entry
->key
);
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
);
712 gistentryinit(*retval
, (Datum
) 0,
713 entry
->rel
, entry
->page
,
714 entry
->offset
, FALSE
);
719 PG_RETURN_POINTER(retval
);
723 * The GiST Consistent method for polygons
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);
735 /* All cases served by this function are inexact */
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 /**************************************************
757 **************************************************/
760 * GiST compress for circles: represent a circle by its bounding box
763 gist_circle_compress(PG_FUNCTION_ARGS
)
765 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
770 retval
= palloc(sizeof(GISTENTRY
));
771 if (DatumGetCircleP(entry
->key
) != NULL
)
773 CIRCLE
*in
= DatumGetCircleP(entry
->key
);
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
);
788 gistentryinit(*retval
, (Datum
) 0,
789 entry
->rel
, entry
->page
,
790 entry
->offset
, FALSE
);
795 PG_RETURN_POINTER(retval
);
799 * The GiST Consistent method for circles
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);
812 /* All cases served by this function are inexact */
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
),
831 PG_RETURN_BOOL(result
);