1 /******************************************************************************
2 This file contains routines that can be bound to a Postgres backend and
3 called by the backend in the process of processing queries. The calling
4 format for these routines is dictated by Postgres architecture.
5 ******************************************************************************/
11 #include "access/gist.h"
12 #include "access/rtree.h"
13 #include "utils/elog.h"
14 #include "utils/palloc.h"
15 #include "utils/builtins.h"
19 #define max(a,b) ((a) > (b) ? (a) : (b))
20 #define min(a,b) ((a) <= (b) ? (a) : (b))
21 #define abs(a) ((a) < (0) ? (-a) : (a))
23 extern void set_parse_buffer(char *str);
24 extern int cube_yyparse();
27 ** Input/Output routines
29 NDBOX *cube_in(char *str);
30 char *cube_out(NDBOX * cube);
34 ** GiST support methods
36 bool g_cube_consistent(GISTENTRY *entry, NDBOX * query, StrategyNumber strategy);
37 GISTENTRY *g_cube_compress(GISTENTRY *entry);
38 GISTENTRY *g_cube_decompress(GISTENTRY *entry);
39 float *g_cube_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result);
40 GIST_SPLITVEC *g_cube_picksplit(bytea *entryvec, GIST_SPLITVEC *v);
41 bool g_cube_leaf_consistent(NDBOX * key, NDBOX * query, StrategyNumber strategy);
42 bool g_cube_internal_consistent(NDBOX * key, NDBOX * query, StrategyNumber strategy);
43 NDBOX *g_cube_union(bytea *entryvec, int *sizep);
44 NDBOX *g_cube_binary_union(NDBOX * r1, NDBOX * r2, int *sizep);
45 bool *g_cube_same(NDBOX * b1, NDBOX * b2, bool *result);
48 ** R-tree suport functions
50 bool cube_same(NDBOX * a, NDBOX * b);
51 bool cube_different(NDBOX * a, NDBOX * b);
52 bool cube_contains(NDBOX * a, NDBOX * b);
53 bool cube_contained(NDBOX * a, NDBOX * b);
54 bool cube_overlap(NDBOX * a, NDBOX * b);
55 NDBOX *cube_union(NDBOX * a, NDBOX * b);
56 NDBOX *cube_inter(NDBOX * a, NDBOX * b);
57 float *cube_size(NDBOX * a);
58 void rt_cube_size(NDBOX * a, float *sz);
61 ** These make no sense for this type, but R-tree wants them
63 bool cube_over_left(NDBOX * a, NDBOX * b);
64 bool cube_over_right(NDBOX * a, NDBOX * b);
65 bool cube_left(NDBOX * a, NDBOX * b);
66 bool cube_right(NDBOX * a, NDBOX * b);
71 bool cube_lt(NDBOX * a, NDBOX * b);
72 bool cube_gt(NDBOX * a, NDBOX * b);
73 float *cube_distance(NDBOX * a, NDBOX * b);
76 ** Auxiliary funxtions
78 static float distance_1D(float a1, float a2, float b1, float b2);
79 static NDBOX *swap_corners(NDBOX * a);
82 /*****************************************************************************
83 * Input/Output functions
84 *****************************************************************************/
86 /* NdBox = [(lowerleft),(upperright)] */
87 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
93 set_parse_buffer(str);
95 if (cube_yyparse(&result) != 0)
98 return ((NDBOX *) result);
102 * You might have noticed a slight inconsistency between the following
103 * declaration and the SQL definition:
104 * CREATE FUNCTION cube_out(opaque) RETURNS opaque ...
105 * The reason is that the argument pass into cube_out is really just a
106 * pointer. POSTGRES thinks all output functions are:
107 * char *out_func(char *);
110 cube_out(NDBOX * cube)
121 p = result = (char *) palloc(100);
124 * while printing the first (LL) corner, check if it is equal to the
127 p += sprintf(p, "(");
128 for (i = 0; i < dim; i++)
130 p += sprintf(p, "%g", cube->x[i]);
131 p += sprintf(p, ", ");
132 if (cube->x[i] != cube->x[i + dim])
135 p -= 2; /* get rid of the last ", " */
136 p += sprintf(p, ")");
140 p += sprintf(p, ",(");
141 for (i = dim; i < dim * 2; i++)
143 p += sprintf(p, "%g", cube->x[i]);
144 p += sprintf(p, ", ");
147 p += sprintf(p, ")");
154 /*****************************************************************************
156 *****************************************************************************/
159 ** The GiST Consistent method for boxes
160 ** Should return false if for all data items x below entry,
161 ** the predicate x op query == FALSE, where op is the oper
162 ** corresponding to strategy in the pg_amop table.
165 g_cube_consistent(GISTENTRY *entry,
167 StrategyNumber strategy)
171 * * if entry is not leaf, use g_cube_internal_consistent, * else use
172 * g_cube_leaf_consistent
174 if (GIST_LEAF(entry))
175 return (g_cube_leaf_consistent((NDBOX *) (entry->pred), query, strategy));
177 return (g_cube_internal_consistent((NDBOX *) (entry->pred), query, strategy));
182 ** The GiST Union method for boxes
183 ** returns the minimal bounding box that encloses all the entries in entryvec
186 g_cube_union(bytea *entryvec, int *sizep)
190 NDBOX *out = (NDBOX *) NULL;
194 * fprintf(stderr, "union\n");
196 numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
197 tmp = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[0]).pred;
200 * sizep = sizeof(NDBOX); -- NDBOX has variable size
204 for (i = 1; i < numranges; i++)
206 out = g_cube_binary_union(tmp, (NDBOX *)
207 (((GISTENTRY *) (VARDATA(entryvec)))[i]).pred,
211 * fprintf(stderr, "\t%s ^ %s -> %s\n", cube_out(tmp),
212 * cube_out((NDBOX *)(((GISTENTRY
213 * *)(VARDATA(entryvec)))[i]).pred), cube_out(out));
224 ** GiST Compress and Decompress methods for boxes
225 ** do not do anything.
228 g_cube_compress(GISTENTRY *entry)
234 g_cube_decompress(GISTENTRY *entry)
240 ** The GiST Penalty method for boxes
241 ** As in the R-tree paper, we use change in area as our penalty metric
244 g_cube_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
250 ud = (Datum) cube_union((NDBOX *) (origentry->pred), (NDBOX *) (newentry->pred));
251 rt_cube_size((NDBOX *) ud, &tmp1);
252 rt_cube_size((NDBOX *) (origentry->pred), &tmp2);
253 *result = tmp1 - tmp2;
257 * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result);
265 ** The GiST PickSplit method for boxes
266 ** We use Guttman's poly time split algorithm
269 g_cube_picksplit(bytea *entryvec,
292 OffsetNumber seed_1 = 0,
299 * fprintf(stderr, "picksplit\n");
301 maxoff = ((VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY)) - 2;
302 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
303 v->spl_left = (OffsetNumber *) palloc(nbytes);
304 v->spl_right = (OffsetNumber *) palloc(nbytes);
309 for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
311 datum_alpha = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[i].pred);
312 for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
314 datum_beta = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[j].pred);
316 /* compute the wasted space by unioning these guys */
317 /* size_waste = size_union - size_inter; */
318 union_d = (NDBOX *) cube_union(datum_alpha, datum_beta);
319 rt_cube_size(union_d, &size_union);
320 inter_d = (NDBOX *) cube_inter(datum_alpha, datum_beta);
321 rt_cube_size(inter_d, &size_inter);
322 size_waste = size_union - size_inter;
326 if (inter_d != (NDBOX *) NULL)
330 * are these a more promising split than what we've already
334 if (size_waste > waste || firsttime)
346 right = v->spl_right;
349 datum_alpha = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_1].pred);
350 datum_l = (NDBOX *) cube_union(datum_alpha, datum_alpha);
351 rt_cube_size((NDBOX *) datum_l, &size_l);
352 datum_beta = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_2].pred);;
353 datum_r = (NDBOX *) cube_union(datum_beta, datum_beta);
354 rt_cube_size((NDBOX *) datum_r, &size_r);
357 * Now split up the regions between the two seeds. An important
358 * property of this split algorithm is that the split vector v has the
359 * indices of items to be split in order in its left and right
360 * vectors. We exploit this property by doing a merge in the code
361 * that actually splits the page.
363 * For efficiency, we also place the new index tuple in this loop. This
364 * is handled at the very end, when we have placed all the existing
365 * tuples and i == maxoff + 1.
368 maxoff = OffsetNumberNext(maxoff);
369 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
373 * If we've already decided where to place this item, just put it
374 * on the right list. Otherwise, we need to figure out which page
375 * needs the least enlargement in order to store the item.
384 else if (i == seed_2)
391 /* okay, which page needs least enlargement? */
392 datum_alpha = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[i].pred);
393 union_dl = (NDBOX *) cube_union(datum_l, datum_alpha);
394 union_dr = (NDBOX *) cube_union(datum_r, datum_alpha);
395 rt_cube_size((NDBOX *) union_dl, &size_alpha);
396 rt_cube_size((NDBOX *) union_dr, &size_beta);
398 /* pick which page to add it to */
399 if (size_alpha - size_l < size_beta - size_r)
418 *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
420 v->spl_ldatum = (char *) datum_l;
421 v->spl_rdatum = (char *) datum_r;
430 g_cube_same(NDBOX * b1, NDBOX * b2, bool *result)
432 if (cube_same(b1, b2))
438 * fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" ));
447 g_cube_leaf_consistent(NDBOX * key,
449 StrategyNumber strategy)
454 * fprintf(stderr, "leaf_consistent, %d\n", strategy);
458 case RTLeftStrategyNumber:
459 retval = (bool) cube_left(key, query);
461 case RTOverLeftStrategyNumber:
462 retval = (bool) cube_over_left(key, query);
464 case RTOverlapStrategyNumber:
465 retval = (bool) cube_overlap(key, query);
467 case RTOverRightStrategyNumber:
468 retval = (bool) cube_over_right(key, query);
470 case RTRightStrategyNumber:
471 retval = (bool) cube_right(key, query);
473 case RTSameStrategyNumber:
474 retval = (bool) cube_same(key, query);
476 case RTContainsStrategyNumber:
477 retval = (bool) cube_contains(key, query);
479 case RTContainedByStrategyNumber:
480 retval = (bool) cube_contained(key, query);
489 g_cube_internal_consistent(NDBOX * key,
491 StrategyNumber strategy)
496 * fprintf(stderr, "internal_consistent, %d\n", strategy);
500 case RTLeftStrategyNumber:
501 case RTOverLeftStrategyNumber:
502 retval = (bool) cube_over_left(key, query);
504 case RTOverlapStrategyNumber:
505 retval = (bool) cube_overlap(key, query);
507 case RTOverRightStrategyNumber:
508 case RTRightStrategyNumber:
509 retval = (bool) cube_right(key, query);
511 case RTSameStrategyNumber:
512 case RTContainsStrategyNumber:
513 retval = (bool) cube_contains(key, query);
515 case RTContainedByStrategyNumber:
516 retval = (bool) cube_overlap(key, query);
525 g_cube_binary_union(NDBOX * r1, NDBOX * r2, int *sizep)
529 retval = cube_union(r1, r2);
530 *sizep = retval->size;
538 cube_union(NDBOX * box_a, NDBOX * box_b)
542 NDBOX *a = swap_corners(box_a);
543 NDBOX *b = swap_corners(box_b);
545 if (a->dim >= b->dim)
547 result = palloc(a->size);
548 result->size = a->size;
549 result->dim = a->dim;
553 result = palloc(b->size);
554 result->size = b->size;
555 result->dim = b->dim;
558 /* swap the box pointers if needed */
568 * use the potentially smaller of the two boxes (b) to fill in the
569 * result, padding absent dimensions with zeroes
571 for (i = 0; i < b->dim; i++)
573 result->x[i] = b->x[i];
574 result->x[i + a->dim] = b->x[i + b->dim];
576 for (i = b->dim; i < a->dim; i++)
579 result->x[i + a->dim] = 0;
582 /* compute the union */
583 for (i = 0; i < a->dim; i++)
584 result->x[i] = min(a->x[i], result->x[i]);
585 for (i = a->dim; i < a->dim * 2; i++)
586 result->x[i] = max(a->x[i], result->x[i]);
596 cube_inter(NDBOX * box_a, NDBOX * box_b)
600 NDBOX *a = swap_corners(box_a);
601 NDBOX *b = swap_corners(box_b);
603 if (a->dim >= b->dim)
605 result = palloc(a->size);
606 result->size = a->size;
607 result->dim = a->dim;
611 result = palloc(b->size);
612 result->size = b->size;
613 result->dim = b->dim;
616 /* swap the box pointers if needed */
626 * use the potentially smaller of the two boxes (b) to fill in the
627 * result, padding absent dimensions with zeroes
629 for (i = 0; i < b->dim; i++)
631 result->x[i] = b->x[i];
632 result->x[i + a->dim] = b->x[i + b->dim];
634 for (i = b->dim; i < a->dim; i++)
637 result->x[i + a->dim] = 0;
640 /* compute the intersection */
641 for (i = 0; i < a->dim; i++)
642 result->x[i] = max(a->x[i], result->x[i]);
643 for (i = a->dim; i < a->dim * 2; i++)
644 result->x[i] = min(a->x[i], result->x[i]);
650 * Is it OK to return a non-null intersection for non-overlapping
664 result = (float *) palloc(sizeof(float));
667 for (i = 0, j = a->dim; i < a->dim; i++, j++)
668 *result = (*result) * abs((a->x[j] - a->x[i]));
674 rt_cube_size(NDBOX * a, float *size)
679 if (a == (NDBOX *) NULL)
684 for (i = 0, j = a->dim; i < a->dim; i++, j++)
685 *size = (*size) * abs((a->x[j] - a->x[i]));
690 /* The following four methods compare the projections of the boxes
691 onto the 0-th coordinate axis. These methods are useless for dimensions
692 larger than 2, but it seems that R-tree requires all its strategies
693 map to real functions that return something */
695 /* is the right edge of (a) located to the left of
696 the right edge of (b)? */
698 cube_over_left(NDBOX * box_a, NDBOX * box_b)
703 if ((box_a == NULL) || (box_b == NULL))
706 a = swap_corners(box_a);
707 b = swap_corners(box_b);
709 return (a->x[a->dim - 1] <= b->x[b->dim - 1] && !cube_left(a, b) && !cube_right(a, b));
712 /* is the left edge of (a) located to the right of
713 the left edge of (b)? */
715 cube_over_right(NDBOX * box_a, NDBOX * box_b)
720 if ((box_a == NULL) || (box_b == NULL))
723 a = swap_corners(box_a);
724 b = swap_corners(box_b);
726 return (a->x[a->dim - 1] >= b->x[b->dim - 1] && !cube_left(a, b) && !cube_right(a, b));
730 /* return 'true' if the projection of 'a' is
731 entirely on the left of the projection of 'b' */
733 cube_left(NDBOX * box_a, NDBOX * box_b)
738 if ((box_a == NULL) || (box_b == NULL))
741 a = swap_corners(box_a);
742 b = swap_corners(box_b);
744 return (a->x[a->dim - 1] < b->x[0]);
747 /* return 'true' if the projection of 'a' is
748 entirely on the right of the projection of 'b' */
750 cube_right(NDBOX * box_a, NDBOX * box_b)
755 if ((box_a == NULL) || (box_b == NULL))
758 a = swap_corners(box_a);
759 b = swap_corners(box_b);
761 return (a->x[0] > b->x[b->dim - 1]);
764 /* make up a metric in which one box will be 'lower' than the other
765 -- this can be useful for srting and to determine uniqueness */
767 cube_lt(NDBOX * box_a, NDBOX * box_b)
774 if ((box_a == NULL) || (box_b == NULL))
777 a = swap_corners(box_a);
778 b = swap_corners(box_b);
779 dim = min(a->dim, b->dim);
782 * if all common dimensions are equal, the cube with more dimensions
793 /* compare the common dimensions */
794 for (i = 0; i < dim; i++)
796 if (a->x[i] > b->x[i])
798 if (a->x[i] < b->x[i])
801 for (i = 0; i < dim; i++)
803 if (a->x[i + a->dim] > b->x[i + b->dim])
805 if (a->x[i + a->dim] < b->x[i + b->dim])
809 /* compare extra dimensions to zero */
812 for (i = dim; i < a->dim; i++)
819 for (i = 0; i < dim; i++)
821 if (a->x[i + a->dim] > 0)
823 if (a->x[i + a->dim] < 0)
829 for (i = dim; i < b->dim; i++)
836 for (i = 0; i < dim; i++)
838 if (b->x[i + b->dim] > 0)
840 if (b->x[i + b->dim] < 0)
850 cube_gt(NDBOX * box_a, NDBOX * box_b)
857 if ((box_a == NULL) || (box_b == NULL))
860 a = swap_corners(box_a);
861 b = swap_corners(box_b);
862 dim = min(a->dim, b->dim);
865 * if all common dimensions are equal, the cube with more dimensions
876 /* compare the common dimensions */
877 for (i = 0; i < dim; i++)
879 if (a->x[i] < b->x[i])
881 if (a->x[i] > b->x[i])
884 for (i = 0; i < dim; i++)
886 if (a->x[i + a->dim] < b->x[i + b->dim])
888 if (a->x[i + a->dim] > b->x[i + b->dim])
893 /* compare extra dimensions to zero */
896 for (i = dim; i < a->dim; i++)
903 for (i = 0; i < dim; i++)
905 if (a->x[i + a->dim] < 0)
907 if (a->x[i + a->dim] > 0)
913 for (i = dim; i < b->dim; i++)
920 for (i = 0; i < dim; i++)
922 if (b->x[i + b->dim] < 0)
924 if (b->x[i + b->dim] > 0)
935 cube_same(NDBOX * box_a, NDBOX * box_b)
941 if ((box_a == NULL) || (box_b == NULL))
944 a = swap_corners(box_a);
945 b = swap_corners(box_b);
947 /* swap the box pointers if necessary */
956 for (i = 0; i < b->dim; i++)
958 if (a->x[i] != b->x[i])
960 if (a->x[i + a->dim] != b->x[i + b->dim])
965 * all dimensions of (b) are compared to those of (a); instead of
966 * those in (a) absent in (b), compare (a) to zero
968 for (i = b->dim; i < a->dim; i++)
972 if (a->x[i + a->dim] != 0)
984 cube_different(NDBOX * box_a, NDBOX * box_b)
986 return (!cube_same(box_a, box_b));
991 /* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */
993 cube_contains(NDBOX * box_a, NDBOX * box_b)
999 if ((box_a == NULL) || (box_b == NULL))
1002 a = swap_corners(box_a);
1003 b = swap_corners(box_b);
1005 if (a->dim < b->dim)
1009 * the further comparisons will make sense if the excess
1010 * dimensions of (b) were zeroes
1012 for (i = a->dim; i < b->dim; i++)
1016 if (b->x[i + b->dim] != 0)
1021 /* Can't care less about the excess dimensions of (a), if any */
1022 for (i = 0; i < min(a->dim, b->dim); i++)
1024 if (a->x[i] > b->x[i])
1026 if (a->x[i + a->dim] < b->x[i + b->dim])
1037 /* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */
1039 cube_contained(NDBOX * a, NDBOX * b)
1041 if (cube_contains(b, a) == TRUE)
1048 /* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */
1050 cube_overlap(NDBOX * box_a, NDBOX * box_b)
1057 * This *very bad* error was found in the source: if ( (a==NULL) ||
1058 * (b=NULL) ) return(FALSE);
1060 if ((box_a == NULL) || (box_b == NULL))
1063 a = swap_corners(box_a);
1064 b = swap_corners(box_b);
1066 /* swap the box pointers if needed */
1067 if (a->dim < b->dim)
1075 /* compare within the dimensions of (b) */
1076 for (i = 0; i < b->dim; i++)
1078 if (a->x[i] > b->x[i + b->dim])
1080 if (a->x[i + a->dim] < b->x[i])
1084 /* compare to zero those dimensions in (a) absent in (b) */
1085 for (i = b->dim; i < a->dim; i++)
1089 if (a->x[i + a->dim] < 0)
1101 /* The distance is computed as a per axis sum of the squared distances
1102 between 1D projections of the boxes onto Cartesian axes. Assuming zero
1103 distance between overlapping projections, this metric coincides with the
1104 "common sense" geometric distance */
1106 cube_distance(NDBOX * a, NDBOX * b)
1113 result = (float *) palloc(sizeof(float));
1115 /* swap the box pointers if needed */
1116 if (a->dim < b->dim)
1125 /* compute within the dimensions of (b) */
1126 for (i = 0; i < b->dim; i++)
1128 d = distance_1D(a->x[i], a->x[i + a->dim], b->x[i], b->x[i + b->dim]);
1132 /* compute distance to zero for those dimensions in (a) absent in (b) */
1133 for (i = b->dim; i < a->dim; i++)
1135 d = distance_1D(a->x[i], a->x[i + a->dim], 0.0, 0.0);
1139 *result = (float) sqrt(distance);
1145 distance_1D(float a1, float a2, float b1, float b2)
1147 /* interval (a) is entirely on the left of (b) */
1148 if ((a1 <= b1) && (a2 <= b1) && (a1 <= b2) && (a2 <= b2))
1149 return (min(b1, b2) - max(a1, a2));
1151 /* interval (a) is entirely on the right of (b) */
1152 if ((a1 > b1) && (a2 > b1) && (a1 > b2) && (a2 > b2))
1153 return (min(a1, a2) - max(b1, b2));
1155 /* the rest are all sorts of intersections */
1159 /* normalize the box's co-ordinates by placing min(xLL,xUR) to LL
1160 and max(xLL,xUR) to UR
1163 swap_corners(NDBOX * a)
1169 result = palloc(a->size);
1170 result->size = a->size;
1171 result->dim = a->dim;
1173 for (i = 0, j = a->dim; i < a->dim; i++, j++)
1175 result->x[i] = min(a->x[i], a->x[j]);
1176 result->x[j] = max(a->x[i], a->x[j]);