Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / backend / access / gist / gistproc.c
blob1e135e13a35cee8e035c716d20391b3c1e6588f0
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-2009, 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);
90 /* Oid subtype = PG_GETARG_OID(3); */
91 bool *recheck = (bool *) PG_GETARG_POINTER(4);
93 /* All cases served by this function are exact */
94 *recheck = false;
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),
105 query,
106 strategy));
107 else
108 PG_RETURN_BOOL(rtree_internal_consistent(DatumGetBoxP(entry->key),
109 query,
110 strategy));
113 static void
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
131 Datum
132 gist_box_union(PG_FUNCTION_ARGS)
134 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
135 int *sizep = (int *) PG_GETARG_POINTER(1);
136 int numranges,
138 BOX *cur,
139 *pageunion;
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.
161 Datum
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.
172 Datum
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
183 Datum
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);
189 Datum ud;
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);
196 static void
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)
207 BOX LRl = *union1,
208 LRr = *union2;
209 BOX RLl = *union2,
210 RLr = *union1;
211 double sizeLR,
212 sizeRL;
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)));
222 if (sizeLR > sizeRL)
223 firstToLeft = false;
226 else
228 float p1,
230 GISTENTRY oldUnion,
231 addon;
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))
242 firstToLeft = false;
246 if (firstToLeft)
248 v->spl_left = list1;
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);
259 else
261 v->spl_left = list2;
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
280 static void
281 fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
283 OffsetNumber i,
284 maxoff;
285 BOX *unionL = NULL,
286 *unionR = NULL;
287 int nbytes;
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;
303 if (unionL == NULL)
305 unionL = (BOX *) palloc(sizeof(BOX));
306 *unionL = *cur;
308 else
309 adjustBox(unionL, cur);
311 v->spl_nleft++;
313 else
315 v->spl_right[v->spl_nright] = i;
316 if (unionR == NULL)
318 unionR = (BOX *) palloc(sizeof(BOX));
319 *unionR = *cur;
321 else
322 adjustBox(unionR, cur);
324 v->spl_nright++;
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
345 Datum
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);
350 OffsetNumber i;
351 OffsetNumber *listL,
352 *listR,
353 *listB,
354 *listT;
355 BOX *unionL,
356 *unionR,
357 *unionB,
358 *unionT;
359 int posL,
360 posR,
361 posB,
362 posT;
363 BOX pageunion;
364 BOX *cur;
365 char direction = ' ';
366 bool allisequal = true;
367 OffsetNumber maxoff;
368 int nbytes;
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));
376 /* find MBR */
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
386 allisequal = false;
388 adjustBox(&pageunion, cur);
391 if (allisequal)
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 { \
411 if ( pos ) { \
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; \
416 } else { \
417 memcpy( (void*)(unionD), (void*) cur, sizeof( BOX ) ); \
419 (list)[pos] = num; \
420 (pos)++; \
421 } while(0)
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);
428 else
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);
432 else
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,
443 avgCenterY = 0.0;
444 double CenterX,
445 CenterY;
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)
469 if (posL > posR)
470 ADDLIST(listR, unionR, posR, i);
471 else
472 ADDLIST(listL, unionL, posL, i);
474 else
475 ADDLIST(listR, unionR, posR, i);
477 if (CenterY < avgCenterY)
478 ADDLIST(listB, unionB, posB, i);
479 else if (CenterY == avgCenterY)
481 if (posB > posT)
482 ADDLIST(listT, unionT, posT, i);
483 else
484 ADDLIST(listB, unionB, posB, i);
486 else
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))
499 direction = 'x';
500 else if (Max(posL, posR) > Max(posB, posT))
501 direction = 'y';
502 else
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));
510 double sizeLR,
511 sizeBT;
513 sizeLR = size_box(interLR);
514 sizeBT = size_box(interBT);
516 if (sizeLR < sizeBT)
517 direction = 'x';
518 else
519 direction = 'y';
522 if (direction == 'x')
523 chooseLR(v,
524 listL, posL, unionL,
525 listR, posR, unionR);
526 else
527 chooseLR(v,
528 listB, posB, unionB,
529 listT, posT, unionT);
531 PG_RETURN_POINTER(v);
535 * Equality method
537 Datum
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);
544 if (b1 && b2)
545 *result = DatumGetBool(DirectFunctionCall2(box_same,
546 PointerGetDatum(b1),
547 PointerGetDatum(b2)));
548 else
549 *result = (b1 == NULL && b2 == NULL) ? TRUE : FALSE;
550 PG_RETURN_POINTER(result);
554 * Leaf-level consistency for boxes: just apply the query operator
556 static bool
557 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
559 bool retval;
561 switch (strategy)
563 case RTLeftStrategyNumber:
564 retval = DatumGetBool(DirectFunctionCall2(box_left,
565 PointerGetDatum(key),
566 PointerGetDatum(query)));
567 break;
568 case RTOverLeftStrategyNumber:
569 retval = DatumGetBool(DirectFunctionCall2(box_overleft,
570 PointerGetDatum(key),
571 PointerGetDatum(query)));
572 break;
573 case RTOverlapStrategyNumber:
574 retval = DatumGetBool(DirectFunctionCall2(box_overlap,
575 PointerGetDatum(key),
576 PointerGetDatum(query)));
577 break;
578 case RTOverRightStrategyNumber:
579 retval = DatumGetBool(DirectFunctionCall2(box_overright,
580 PointerGetDatum(key),
581 PointerGetDatum(query)));
582 break;
583 case RTRightStrategyNumber:
584 retval = DatumGetBool(DirectFunctionCall2(box_right,
585 PointerGetDatum(key),
586 PointerGetDatum(query)));
587 break;
588 case RTSameStrategyNumber:
589 retval = DatumGetBool(DirectFunctionCall2(box_same,
590 PointerGetDatum(key),
591 PointerGetDatum(query)));
592 break;
593 case RTContainsStrategyNumber:
594 case RTOldContainsStrategyNumber:
595 retval = DatumGetBool(DirectFunctionCall2(box_contain,
596 PointerGetDatum(key),
597 PointerGetDatum(query)));
598 break;
599 case RTContainedByStrategyNumber:
600 case RTOldContainedByStrategyNumber:
601 retval = DatumGetBool(DirectFunctionCall2(box_contained,
602 PointerGetDatum(key),
603 PointerGetDatum(query)));
604 break;
605 case RTOverBelowStrategyNumber:
606 retval = DatumGetBool(DirectFunctionCall2(box_overbelow,
607 PointerGetDatum(key),
608 PointerGetDatum(query)));
609 break;
610 case RTBelowStrategyNumber:
611 retval = DatumGetBool(DirectFunctionCall2(box_below,
612 PointerGetDatum(key),
613 PointerGetDatum(query)));
614 break;
615 case RTAboveStrategyNumber:
616 retval = DatumGetBool(DirectFunctionCall2(box_above,
617 PointerGetDatum(key),
618 PointerGetDatum(query)));
619 break;
620 case RTOverAboveStrategyNumber:
621 retval = DatumGetBool(DirectFunctionCall2(box_overabove,
622 PointerGetDatum(key),
623 PointerGetDatum(query)));
624 break;
625 default:
626 retval = FALSE;
628 return retval;
631 static double
632 size_box(Datum dbox)
634 BOX *box = DatumGetBoxP(dbox);
636 if (box == NULL || box->high.x <= box->low.x || box->high.y <= box->low.y)
637 return 0.0;
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.
651 static bool
652 rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy)
654 bool retval;
656 switch (strategy)
658 case RTLeftStrategyNumber:
659 retval = !DatumGetBool(DirectFunctionCall2(box_overright,
660 PointerGetDatum(key),
661 PointerGetDatum(query)));
662 break;
663 case RTOverLeftStrategyNumber:
664 retval = !DatumGetBool(DirectFunctionCall2(box_right,
665 PointerGetDatum(key),
666 PointerGetDatum(query)));
667 break;
668 case RTOverlapStrategyNumber:
669 retval = DatumGetBool(DirectFunctionCall2(box_overlap,
670 PointerGetDatum(key),
671 PointerGetDatum(query)));
672 break;
673 case RTOverRightStrategyNumber:
674 retval = !DatumGetBool(DirectFunctionCall2(box_left,
675 PointerGetDatum(key),
676 PointerGetDatum(query)));
677 break;
678 case RTRightStrategyNumber:
679 retval = !DatumGetBool(DirectFunctionCall2(box_overleft,
680 PointerGetDatum(key),
681 PointerGetDatum(query)));
682 break;
683 case RTSameStrategyNumber:
684 case RTContainsStrategyNumber:
685 case RTOldContainsStrategyNumber:
686 retval = DatumGetBool(DirectFunctionCall2(box_contain,
687 PointerGetDatum(key),
688 PointerGetDatum(query)));
689 break;
690 case RTContainedByStrategyNumber:
691 case RTOldContainedByStrategyNumber:
692 retval = DatumGetBool(DirectFunctionCall2(box_overlap,
693 PointerGetDatum(key),
694 PointerGetDatum(query)));
695 break;
696 case RTOverBelowStrategyNumber:
697 retval = !DatumGetBool(DirectFunctionCall2(box_above,
698 PointerGetDatum(key),
699 PointerGetDatum(query)));
700 break;
701 case RTBelowStrategyNumber:
702 retval = !DatumGetBool(DirectFunctionCall2(box_overabove,
703 PointerGetDatum(key),
704 PointerGetDatum(query)));
705 break;
706 case RTAboveStrategyNumber:
707 retval = !DatumGetBool(DirectFunctionCall2(box_overbelow,
708 PointerGetDatum(key),
709 PointerGetDatum(query)));
710 break;
711 case RTOverAboveStrategyNumber:
712 retval = !DatumGetBool(DirectFunctionCall2(box_below,
713 PointerGetDatum(key),
714 PointerGetDatum(query)));
715 break;
716 default:
717 retval = FALSE;
719 return retval;
722 /**************************************************
723 * Polygon ops
724 **************************************************/
727 * GiST compress for polygons: represent a polygon by its bounding box
729 Datum
730 gist_poly_compress(PG_FUNCTION_ARGS)
732 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
733 GISTENTRY *retval;
735 if (entry->leafkey)
737 retval = palloc(sizeof(GISTENTRY));
738 if (DatumGetPointer(entry->key) != NULL)
740 POLYGON *in = DatumGetPolygonP(entry->key);
741 BOX *r;
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);
750 else
752 gistentryinit(*retval, (Datum) 0,
753 entry->rel, entry->page,
754 entry->offset, FALSE);
757 else
758 retval = entry;
759 PG_RETURN_POINTER(retval);
763 * The GiST Consistent method for polygons
765 Datum
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);
774 bool result;
776 /* All cases served by this function are inexact */
777 *recheck = true;
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 /**************************************************
797 * Circle ops
798 **************************************************/
801 * GiST compress for circles: represent a circle by its bounding box
803 Datum
804 gist_circle_compress(PG_FUNCTION_ARGS)
806 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
807 GISTENTRY *retval;
809 if (entry->leafkey)
811 retval = palloc(sizeof(GISTENTRY));
812 if (DatumGetCircleP(entry->key) != NULL)
814 CIRCLE *in = DatumGetCircleP(entry->key);
815 BOX *r;
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);
827 else
829 gistentryinit(*retval, (Datum) 0,
830 entry->rel, entry->page,
831 entry->offset, FALSE);
834 else
835 retval = entry;
836 PG_RETURN_POINTER(retval);
840 * The GiST Consistent method for circles
842 Datum
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);
851 BOX bbox;
852 bool result;
854 /* All cases served by this function are inexact */
855 *recheck = true;
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),
871 &bbox, strategy);
873 PG_RETURN_BOOL(result);