PostgreSQL Source Code git master
Loading...
Searching...
No Matches
cube.c
Go to the documentation of this file.
1/******************************************************************************
2 contrib/cube/cube.c
3
4 This file contains routines that can be bound to a Postgres backend and
5 called by the backend in the process of processing queries. The calling
6 format for these routines is dictated by Postgres architecture.
7******************************************************************************/
8
9#include "postgres.h"
10
11#include <math.h>
12
13#include "access/gist.h"
14#include "access/stratnum.h"
15#include "cubedata.h"
16#include "libpq/pqformat.h"
17#include "utils/array.h"
18#include "utils/float.h"
19
21 .name = "cube",
22 .version = PG_VERSION
23);
24
25/*
26 * Taken from the intarray contrib header
27 */
28#define ARRPTR(x) ( (double *) ARR_DATA_PTR(x) )
29#define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
30
31/*
32 * Input/Output routines
33 */
50
51/*
52 * GiST support methods
53 */
54
63
64/*
65 * B-tree support functions
66 */
74
75/*
76 * R-tree support functions
77 */
78
85
86/*
87 * miscellaneous
88 */
94
95/*
96 * For internal use only
97 */
100bool cube_overlap_v0(NDBOX *a, NDBOX *b);
102void rt_cube_size(NDBOX *a, double *size);
104bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy);
105bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy);
106
107/*
108 * Auxiliary functions
109 */
110static double distance_1D(double a1, double a2, double b1, double b2);
111static bool cube_is_point_internal(NDBOX *cube);
112
113
114/*****************************************************************************
115 * Input/Output functions
116 *****************************************************************************/
117
118/* NdBox = [(lowerleft),(upperright)] */
119/* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
120Datum
122{
123 char *str = PG_GETARG_CSTRING(0);
124 NDBOX *result;
125 Size scanbuflen;
126 yyscan_t scanner;
127
128 cube_scanner_init(str, &scanbuflen, &scanner);
129
130 cube_yyparse(&result, scanbuflen, fcinfo->context, scanner);
131
132 /* We might as well run this even on failure. */
133 cube_scanner_finish(scanner);
134
136}
137
138
139/*
140 * Allows the construction of a cube from 2 float[]'s
141 */
142Datum
144{
147 NDBOX *result;
148 int i;
149 int dim;
150 int size;
151 bool point;
152 double *dur,
153 *dll;
154
158 errmsg("cannot work with arrays containing NULLs")));
159
160 dim = ARRNELEMS(ur);
161 if (dim > CUBE_MAX_DIM)
164 errmsg("can't extend cube"),
165 errdetail("A cube cannot have more than %d dimensions.",
166 CUBE_MAX_DIM)));
167
168 if (ARRNELEMS(ll) != dim)
171 errmsg("UR and LL arrays must be of same length")));
172
173 dur = ARRPTR(ur);
174 dll = ARRPTR(ll);
175
176 /* Check if it's a point */
177 point = true;
178 for (i = 0; i < dim; i++)
179 {
180 if (dur[i] != dll[i])
181 {
182 point = false;
183 break;
184 }
185 }
186
187 size = point ? POINT_SIZE(dim) : CUBE_SIZE(dim);
188 result = (NDBOX *) palloc0(size);
189 SET_VARSIZE(result, size);
190 SET_DIM(result, dim);
191
192 for (i = 0; i < dim; i++)
193 result->x[i] = dur[i];
194
195 if (!point)
196 {
197 for (i = 0; i < dim; i++)
198 result->x[i + dim] = dll[i];
199 }
200 else
202
204}
205
206/*
207 * Allows the construction of a zero-volume cube from a float[]
208 */
209Datum
211{
213 NDBOX *result;
214 int i;
215 int dim;
216 int size;
217 double *dur;
218
222 errmsg("cannot work with arrays containing NULLs")));
223
224 dim = ARRNELEMS(ur);
225 if (dim > CUBE_MAX_DIM)
228 errmsg("array is too long"),
229 errdetail("A cube cannot have more than %d dimensions.",
230 CUBE_MAX_DIM)));
231
232 dur = ARRPTR(ur);
233
234 size = POINT_SIZE(dim);
235 result = (NDBOX *) palloc0(size);
236 SET_VARSIZE(result, size);
237 SET_DIM(result, dim);
239
240 for (i = 0; i < dim; i++)
241 result->x[i] = dur[i];
242
244}
245
246Datum
248{
251 NDBOX *result;
252 int size,
253 dim,
254 i;
255 int *dx;
256
260 errmsg("cannot work with arrays containing NULLs")));
261
262 dx = (int32 *) ARR_DATA_PTR(idx);
263
264 dim = ARRNELEMS(idx);
265 if (dim > CUBE_MAX_DIM)
268 errmsg("array is too long"),
269 errdetail("A cube cannot have more than %d dimensions.",
270 CUBE_MAX_DIM)));
271
272 size = IS_POINT(c) ? POINT_SIZE(dim) : CUBE_SIZE(dim);
273 result = (NDBOX *) palloc0(size);
274 SET_VARSIZE(result, size);
275 SET_DIM(result, dim);
276
277 if (IS_POINT(c))
279
280 for (i = 0; i < dim; i++)
281 {
282 if ((dx[i] <= 0) || (dx[i] > DIM(c)))
285 errmsg("Index out of bounds")));
286 result->x[i] = c->x[dx[i] - 1];
287 if (!IS_POINT(c))
288 result->x[i + dim] = c->x[dx[i] + DIM(c) - 1];
289 }
290
291 PG_FREE_IF_COPY(c, 0);
293}
294
295Datum
297{
300 int dim = DIM(cube);
301 int i;
302
304
306 for (i = 0; i < dim; i++)
307 {
308 if (i > 0)
311 }
313
315 {
317 for (i = 0; i < dim; i++)
318 {
319 if (i > 0)
322 }
324 }
325
328}
329
330/*
331 * cube_send - a binary output handler for cube type
332 */
333Datum
335{
338 int32 i,
339 nitems = DIM(cube);
340
342 pq_sendint32(&buf, cube->header);
343 if (!IS_POINT(cube))
344 nitems += nitems;
345 /* for symmetry with cube_recv, we don't use LL_COORD/UR_COORD here */
346 for (i = 0; i < nitems; i++)
347 pq_sendfloat8(&buf, cube->x[i]);
348
350}
351
352/*
353 * cube_recv - a binary input handler for cube type
354 */
355Datum
357{
359 int32 header;
360 int32 i,
361 nitems;
362 NDBOX *cube;
363
364 header = pq_getmsgint(buf, sizeof(int32));
365 nitems = (header & DIM_MASK);
366 if (nitems > CUBE_MAX_DIM)
369 errmsg("cube dimension is too large"),
370 errdetail("A cube cannot have more than %d dimensions.",
371 CUBE_MAX_DIM)));
372 if ((header & POINT_BIT) == 0)
373 nitems += nitems;
374 cube = palloc(offsetof(NDBOX, x) + sizeof(double) * nitems);
375 SET_VARSIZE(cube, offsetof(NDBOX, x) + sizeof(double) * nitems);
376 cube->header = header;
377 for (i = 0; i < nitems; i++)
378 cube->x[i] = pq_getmsgfloat8(buf);
379
381}
382
383
384/*****************************************************************************
385 * GiST functions
386 *****************************************************************************/
387
388/*
389 * The GiST Consistent method for boxes
390 * Should return false if for all data items x below entry,
391 * the predicate x op query == false, where op is the oper
392 * corresponding to strategy in the pg_amop table.
393 */
394Datum
396{
397 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
398 NDBOX *query = PG_GETARG_NDBOX_P(1);
400#ifdef NOT_USED
401 Oid subtype = PG_GETARG_OID(3);
402#endif
403 bool *recheck = (bool *) PG_GETARG_POINTER(4);
404 bool res;
405
406 /* All cases served by this function are exact */
407 *recheck = false;
408
409 /*
410 * if entry is not leaf, use g_cube_internal_consistent, else use
411 * g_cube_leaf_consistent
412 */
413 if (GIST_LEAF(entry))
415 query, strategy);
416 else
418 query, strategy);
419
420 PG_FREE_IF_COPY(query, 1);
421 PG_RETURN_BOOL(res);
422}
423
424
425/*
426 * The GiST Union method for boxes
427 * returns the minimal bounding box that encloses all the entries in entryvec
428 */
429Datum
431{
433 int *sizep = (int *) PG_GETARG_POINTER(1);
434 NDBOX *out = (NDBOX *) NULL;
435 NDBOX *tmp;
436 int i;
437
438 tmp = DatumGetNDBOXP(entryvec->vector[0].key);
439
440 /*
441 * sizep = sizeof(NDBOX); -- NDBOX has variable size
442 */
443 *sizep = VARSIZE(tmp);
444
445 for (i = 1; i < entryvec->n; i++)
446 {
447 out = g_cube_binary_union(tmp,
448 DatumGetNDBOXP(entryvec->vector[i].key),
449 sizep);
450 tmp = out;
451 }
452
454}
455
456/*
457 * GiST Compress and Decompress methods for boxes
458 * do not do anything.
459 */
460
461Datum
466
467Datum
469{
470 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
471 NDBOX *key = DatumGetNDBOXP(entry->key);
472
473 if (key != DatumGetNDBOXP(entry->key))
474 {
476
477 gistentryinit(*retval, PointerGetDatum(key),
478 entry->rel, entry->page,
479 entry->offset, false);
480 PG_RETURN_POINTER(retval);
481 }
482 PG_RETURN_POINTER(entry);
483}
484
485
486/*
487 * The GiST Penalty method for boxes
488 * As in the R-tree paper, we use change in area as our penalty metric
489 */
490Datum
508
509
510
511/*
512 * The GiST PickSplit method for boxes
513 * We use Guttman's poly time split algorithm
514 */
515Datum
517{
521 j;
523 *datum_beta;
524 NDBOX *datum_l,
525 *datum_r;
526 NDBOX *union_d,
527 *union_dl,
528 *union_dr;
529 NDBOX *inter_d;
530 bool firsttime;
531 double size_alpha,
532 size_beta,
535 double size_waste,
536 waste;
537 double size_l,
538 size_r;
539 int nbytes;
541 seed_2 = 2;
542 OffsetNumber *left,
543 *right;
544 OffsetNumber maxoff;
545
546 maxoff = entryvec->n - 2;
547 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
548 v->spl_left = (OffsetNumber *) palloc(nbytes);
549 v->spl_right = (OffsetNumber *) palloc(nbytes);
550
551 firsttime = true;
552 waste = 0.0;
553
554 for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
555 {
556 datum_alpha = DatumGetNDBOXP(entryvec->vector[i].key);
557 for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
558 {
559 datum_beta = DatumGetNDBOXP(entryvec->vector[j].key);
560
561 /* compute the wasted space by unioning these guys */
562 /* size_waste = size_union - size_inter; */
566 entryvec->vector[i].key,
567 entryvec->vector[j].key));
570
571 /*
572 * are these a more promising split than what we've already seen?
573 */
574
575 if (size_waste > waste || firsttime)
576 {
577 waste = size_waste;
578 seed_1 = i;
579 seed_2 = j;
580 firsttime = false;
581 }
582 }
583 }
584
585 left = v->spl_left;
586 v->spl_nleft = 0;
587 right = v->spl_right;
588 v->spl_nright = 0;
589
596
597 /*
598 * Now split up the regions between the two seeds. An important property
599 * of this split algorithm is that the split vector v has the indices of
600 * items to be split in order in its left and right vectors. We exploit
601 * this property by doing a merge in the code that actually splits the
602 * page.
603 *
604 * For efficiency, we also place the new index tuple in this loop. This is
605 * handled at the very end, when we have placed all the existing tuples
606 * and i == maxoff + 1.
607 */
608
609 maxoff = OffsetNumberNext(maxoff);
610 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
611 {
612 /*
613 * If we've already decided where to place this item, just put it on
614 * the right list. Otherwise, we need to figure out which page needs
615 * the least enlargement in order to store the item.
616 */
617
618 if (i == seed_1)
619 {
620 *left++ = i;
621 v->spl_nleft++;
622 continue;
623 }
624 else if (i == seed_2)
625 {
626 *right++ = i;
627 v->spl_nright++;
628 continue;
629 }
630
631 /* okay, which page needs least enlargement? */
632 datum_alpha = DatumGetNDBOXP(entryvec->vector[i].key);
637
638 /* pick which page to add it to */
640 {
643 *left++ = i;
644 v->spl_nleft++;
645 }
646 else
647 {
650 *right++ = i;
651 v->spl_nright++;
652 }
653 }
654 *left = *right = FirstOffsetNumber; /* sentinel value */
655
658
660}
661
662/*
663 * Equality method
664 */
665Datum
667{
670 bool *result = (bool *) PG_GETARG_POINTER(2);
671
672 if (cube_cmp_v0(b1, b2) == 0)
673 *result = true;
674 else
675 *result = false;
676
678}
679
680/*
681 * SUPPORT ROUTINES
682 */
683bool
685 NDBOX *query,
686 StrategyNumber strategy)
687{
688 bool retval;
689
690 switch (strategy)
691 {
693 retval = cube_overlap_v0(key, query);
694 break;
696 retval = (cube_cmp_v0(key, query) == 0);
697 break;
700 retval = cube_contains_v0(key, query);
701 break;
704 retval = cube_contains_v0(query, key);
705 break;
706 default:
707 retval = false;
708 }
709 return retval;
710}
711
712bool
714 NDBOX *query,
715 StrategyNumber strategy)
716{
717 bool retval;
718
719 switch (strategy)
720 {
722 retval = cube_overlap_v0(key, query);
723 break;
727 retval = cube_contains_v0(key, query);
728 break;
731 retval = cube_overlap_v0(key, query);
732 break;
733 default:
734 retval = false;
735 }
736 return retval;
737}
738
739NDBOX *
741{
742 NDBOX *retval;
743
744 retval = cube_union_v0(r1, r2);
745 *sizep = VARSIZE(retval);
746
747 return retval;
748}
749
750
751/* cube_union_v0 */
752NDBOX *
754{
755 int i;
756 NDBOX *result;
757 int dim;
758 int size;
759
760 /* trivial case */
761 if (a == b)
762 return a;
763
764 /* swap the arguments if needed, so that 'a' is always larger than 'b' */
765 if (DIM(a) < DIM(b))
766 {
767 NDBOX *tmp = b;
768
769 b = a;
770 a = tmp;
771 }
772 dim = DIM(a);
773
774 size = CUBE_SIZE(dim);
775 result = palloc0(size);
776 SET_VARSIZE(result, size);
777 SET_DIM(result, dim);
778
779 /* First compute the union of the dimensions present in both args */
780 for (i = 0; i < DIM(b); i++)
781 {
782 result->x[i] = Min(Min(LL_COORD(a, i), UR_COORD(a, i)),
783 Min(LL_COORD(b, i), UR_COORD(b, i)));
784 result->x[i + DIM(a)] = Max(Max(LL_COORD(a, i), UR_COORD(a, i)),
785 Max(LL_COORD(b, i), UR_COORD(b, i)));
786 }
787 /* continue on the higher dimensions only present in 'a' */
788 for (; i < DIM(a); i++)
789 {
790 result->x[i] = Min(0,
791 Min(LL_COORD(a, i), UR_COORD(a, i))
792 );
793 result->x[i + dim] = Max(0,
794 Max(LL_COORD(a, i), UR_COORD(a, i))
795 );
796 }
797
798 /*
799 * Check if the result was in fact a point, and set the flag in the datum
800 * accordingly. (we don't bother to repalloc it smaller)
801 */
803 {
804 size = POINT_SIZE(dim);
805 SET_VARSIZE(result, size);
807 }
808
809 return result;
810}
811
812Datum
814{
817 NDBOX *res;
818
819 res = cube_union_v0(a, b);
820
821 PG_FREE_IF_COPY(a, 0);
822 PG_FREE_IF_COPY(b, 1);
824}
825
826/* cube_inter */
827Datum
829{
832 NDBOX *result;
833 bool swapped = false;
834 int i;
835 int dim;
836 int size;
837
838 /* swap the arguments if needed, so that 'a' is always larger than 'b' */
839 if (DIM(a) < DIM(b))
840 {
841 NDBOX *tmp = b;
842
843 b = a;
844 a = tmp;
845 swapped = true;
846 }
847 dim = DIM(a);
848
849 size = CUBE_SIZE(dim);
850 result = (NDBOX *) palloc0(size);
851 SET_VARSIZE(result, size);
852 SET_DIM(result, dim);
853
854 /* First compute intersection of the dimensions present in both args */
855 for (i = 0; i < DIM(b); i++)
856 {
857 result->x[i] = Max(Min(LL_COORD(a, i), UR_COORD(a, i)),
858 Min(LL_COORD(b, i), UR_COORD(b, i)));
859 result->x[i + DIM(a)] = Min(Max(LL_COORD(a, i), UR_COORD(a, i)),
860 Max(LL_COORD(b, i), UR_COORD(b, i)));
861 }
862 /* continue on the higher dimensions only present in 'a' */
863 for (; i < DIM(a); i++)
864 {
865 result->x[i] = Max(0,
866 Min(LL_COORD(a, i), UR_COORD(a, i))
867 );
868 result->x[i + DIM(a)] = Min(0,
869 Max(LL_COORD(a, i), UR_COORD(a, i))
870 );
871 }
872
873 /*
874 * Check if the result was in fact a point, and set the flag in the datum
875 * accordingly. (we don't bother to repalloc it smaller)
876 */
878 {
879 size = POINT_SIZE(dim);
880 result = repalloc(result, size);
881 SET_VARSIZE(result, size);
883 }
884
885 if (swapped)
886 {
887 PG_FREE_IF_COPY(b, 0);
888 PG_FREE_IF_COPY(a, 1);
889 }
890 else
891 {
892 PG_FREE_IF_COPY(a, 0);
893 PG_FREE_IF_COPY(b, 1);
894 }
895
896 /*
897 * Is it OK to return a non-null intersection for non-overlapping boxes?
898 */
900}
901
902/* cube_size */
903Datum
913
914void
915rt_cube_size(NDBOX *a, double *size)
916{
917 double result;
918 int i;
919
920 if (a == (NDBOX *) NULL)
921 {
922 /* special case for GiST */
923 result = 0.0;
924 }
925 else if (IS_POINT(a) || DIM(a) == 0)
926 {
927 /* necessarily has zero size */
928 result = 0.0;
929 }
930 else
931 {
932 result = 1.0;
933 for (i = 0; i < DIM(a); i++)
934 result *= fabs(UR_COORD(a, i) - LL_COORD(a, i));
935 }
936 *size = result;
937}
938
939/*
940 * make up a metric in which one box will be 'lower' than the other
941 * -- this can be useful for sorting and to determine uniqueness
942 */
943int32
945{
946 int i;
947 int dim;
948
949 dim = Min(DIM(a), DIM(b));
950
951 /* compare the common dimensions */
952 for (i = 0; i < dim; i++)
953 {
954 if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
955 Min(LL_COORD(b, i), UR_COORD(b, i)))
956 return 1;
957 if (Min(LL_COORD(a, i), UR_COORD(a, i)) <
958 Min(LL_COORD(b, i), UR_COORD(b, i)))
959 return -1;
960 }
961 for (i = 0; i < dim; i++)
962 {
963 if (Max(LL_COORD(a, i), UR_COORD(a, i)) >
964 Max(LL_COORD(b, i), UR_COORD(b, i)))
965 return 1;
966 if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
967 Max(LL_COORD(b, i), UR_COORD(b, i)))
968 return -1;
969 }
970
971 /* compare extra dimensions to zero */
972 if (DIM(a) > DIM(b))
973 {
974 for (i = dim; i < DIM(a); i++)
975 {
976 if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
977 return 1;
978 if (Min(LL_COORD(a, i), UR_COORD(a, i)) < 0)
979 return -1;
980 }
981 for (i = dim; i < DIM(a); i++)
982 {
983 if (Max(LL_COORD(a, i), UR_COORD(a, i)) > 0)
984 return 1;
985 if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
986 return -1;
987 }
988
989 /*
990 * if all common dimensions are equal, the cube with more dimensions
991 * wins
992 */
993 return 1;
994 }
995 if (DIM(a) < DIM(b))
996 {
997 for (i = dim; i < DIM(b); i++)
998 {
999 if (Min(LL_COORD(b, i), UR_COORD(b, i)) > 0)
1000 return -1;
1001 if (Min(LL_COORD(b, i), UR_COORD(b, i)) < 0)
1002 return 1;
1003 }
1004 for (i = dim; i < DIM(b); i++)
1005 {
1006 if (Max(LL_COORD(b, i), UR_COORD(b, i)) > 0)
1007 return -1;
1008 if (Max(LL_COORD(b, i), UR_COORD(b, i)) < 0)
1009 return 1;
1010 }
1011
1012 /*
1013 * if all common dimensions are equal, the cube with more dimensions
1014 * wins
1015 */
1016 return -1;
1017 }
1018
1019 /* They're really equal */
1020 return 0;
1021}
1022
1023Datum
1025{
1027 *b = PG_GETARG_NDBOX_P(1);
1028 int32 res;
1029
1030 res = cube_cmp_v0(a, b);
1031
1032 PG_FREE_IF_COPY(a, 0);
1033 PG_FREE_IF_COPY(b, 1);
1034 PG_RETURN_INT32(res);
1035}
1036
1037
1038Datum
1040{
1042 *b = PG_GETARG_NDBOX_P(1);
1043 int32 res;
1044
1045 res = cube_cmp_v0(a, b);
1046
1047 PG_FREE_IF_COPY(a, 0);
1048 PG_FREE_IF_COPY(b, 1);
1049 PG_RETURN_BOOL(res == 0);
1050}
1051
1052
1053Datum
1055{
1057 *b = PG_GETARG_NDBOX_P(1);
1058 int32 res;
1059
1060 res = cube_cmp_v0(a, b);
1061
1062 PG_FREE_IF_COPY(a, 0);
1063 PG_FREE_IF_COPY(b, 1);
1064 PG_RETURN_BOOL(res != 0);
1065}
1066
1067
1068Datum
1070{
1072 *b = PG_GETARG_NDBOX_P(1);
1073 int32 res;
1074
1075 res = cube_cmp_v0(a, b);
1076
1077 PG_FREE_IF_COPY(a, 0);
1078 PG_FREE_IF_COPY(b, 1);
1079 PG_RETURN_BOOL(res < 0);
1080}
1081
1082
1083Datum
1085{
1087 *b = PG_GETARG_NDBOX_P(1);
1088 int32 res;
1089
1090 res = cube_cmp_v0(a, b);
1091
1092 PG_FREE_IF_COPY(a, 0);
1093 PG_FREE_IF_COPY(b, 1);
1094 PG_RETURN_BOOL(res > 0);
1095}
1096
1097
1098Datum
1100{
1102 *b = PG_GETARG_NDBOX_P(1);
1103 int32 res;
1104
1105 res = cube_cmp_v0(a, b);
1106
1107 PG_FREE_IF_COPY(a, 0);
1108 PG_FREE_IF_COPY(b, 1);
1109 PG_RETURN_BOOL(res <= 0);
1110}
1111
1112
1113Datum
1115{
1117 *b = PG_GETARG_NDBOX_P(1);
1118 int32 res;
1119
1120 res = cube_cmp_v0(a, b);
1121
1122 PG_FREE_IF_COPY(a, 0);
1123 PG_FREE_IF_COPY(b, 1);
1124 PG_RETURN_BOOL(res >= 0);
1125}
1126
1127
1128/* Contains */
1129/* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */
1130bool
1132{
1133 int i;
1134
1135 if ((a == NULL) || (b == NULL))
1136 return false;
1137
1138 if (DIM(a) < DIM(b))
1139 {
1140 /*
1141 * the further comparisons will make sense if the excess dimensions of
1142 * (b) were zeroes Since both UL and UR coordinates must be zero, we
1143 * can check them all without worrying about which is which.
1144 */
1145 for (i = DIM(a); i < DIM(b); i++)
1146 {
1147 if (LL_COORD(b, i) != 0)
1148 return false;
1149 if (UR_COORD(b, i) != 0)
1150 return false;
1151 }
1152 }
1153
1154 /* Can't care less about the excess dimensions of (a), if any */
1155 for (i = 0; i < Min(DIM(a), DIM(b)); i++)
1156 {
1157 if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
1158 Min(LL_COORD(b, i), UR_COORD(b, i)))
1159 return false;
1160 if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
1161 Max(LL_COORD(b, i), UR_COORD(b, i)))
1162 return false;
1163 }
1164
1165 return true;
1166}
1167
1168Datum
1170{
1172 *b = PG_GETARG_NDBOX_P(1);
1173 bool res;
1174
1175 res = cube_contains_v0(a, b);
1176
1177 PG_FREE_IF_COPY(a, 0);
1178 PG_FREE_IF_COPY(b, 1);
1179 PG_RETURN_BOOL(res);
1180}
1181
1182/* Contained */
1183/* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */
1184Datum
1186{
1188 *b = PG_GETARG_NDBOX_P(1);
1189 bool res;
1190
1191 res = cube_contains_v0(b, a);
1192
1193 PG_FREE_IF_COPY(a, 0);
1194 PG_FREE_IF_COPY(b, 1);
1195 PG_RETURN_BOOL(res);
1196}
1197
1198/* Overlap */
1199/* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */
1200bool
1202{
1203 int i;
1204
1205 if ((a == NULL) || (b == NULL))
1206 return false;
1207
1208 /* swap the box pointers if needed */
1209 if (DIM(a) < DIM(b))
1210 {
1211 NDBOX *tmp = b;
1212
1213 b = a;
1214 a = tmp;
1215 }
1216
1217 /* compare within the dimensions of (b) */
1218 for (i = 0; i < DIM(b); i++)
1219 {
1220 if (Min(LL_COORD(a, i), UR_COORD(a, i)) > Max(LL_COORD(b, i), UR_COORD(b, i)))
1221 return false;
1222 if (Max(LL_COORD(a, i), UR_COORD(a, i)) < Min(LL_COORD(b, i), UR_COORD(b, i)))
1223 return false;
1224 }
1225
1226 /* compare to zero those dimensions in (a) absent in (b) */
1227 for (i = DIM(b); i < DIM(a); i++)
1228 {
1229 if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
1230 return false;
1231 if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
1232 return false;
1233 }
1234
1235 return true;
1236}
1237
1238
1239Datum
1241{
1243 *b = PG_GETARG_NDBOX_P(1);
1244 bool res;
1245
1246 res = cube_overlap_v0(a, b);
1247
1248 PG_FREE_IF_COPY(a, 0);
1249 PG_FREE_IF_COPY(b, 1);
1250 PG_RETURN_BOOL(res);
1251}
1252
1253
1254/* Distance */
1255/*
1256 * The distance is computed as a per axis sum of the squared distances
1257 * between 1D projections of the boxes onto Cartesian axes. Assuming zero
1258 * distance between overlapping projections, this metric coincides with the
1259 * "common sense" geometric distance
1260 */
1261Datum
1263{
1265 *b = PG_GETARG_NDBOX_P(1);
1266 bool swapped = false;
1267 double d,
1268 distance;
1269 int i;
1270
1271 /* swap the box pointers if needed */
1272 if (DIM(a) < DIM(b))
1273 {
1274 NDBOX *tmp = b;
1275
1276 b = a;
1277 a = tmp;
1278 swapped = true;
1279 }
1280
1281 distance = 0.0;
1282 /* compute within the dimensions of (b) */
1283 for (i = 0; i < DIM(b); i++)
1284 {
1285 d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), LL_COORD(b, i), UR_COORD(b, i));
1286 distance += d * d;
1287 }
1288
1289 /* compute distance to zero for those dimensions in (a) absent in (b) */
1290 for (i = DIM(b); i < DIM(a); i++)
1291 {
1292 d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0);
1293 distance += d * d;
1294 }
1295
1296 if (swapped)
1297 {
1298 PG_FREE_IF_COPY(b, 0);
1299 PG_FREE_IF_COPY(a, 1);
1300 }
1301 else
1302 {
1303 PG_FREE_IF_COPY(a, 0);
1304 PG_FREE_IF_COPY(b, 1);
1305 }
1306
1307 PG_RETURN_FLOAT8(sqrt(distance));
1308}
1309
1310Datum
1312{
1314 *b = PG_GETARG_NDBOX_P(1);
1315 bool swapped = false;
1316 double distance;
1317 int i;
1318
1319 /* swap the box pointers if needed */
1320 if (DIM(a) < DIM(b))
1321 {
1322 NDBOX *tmp = b;
1323
1324 b = a;
1325 a = tmp;
1326 swapped = true;
1327 }
1328
1329 distance = 0.0;
1330 /* compute within the dimensions of (b) */
1331 for (i = 0; i < DIM(b); i++)
1332 distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1333 LL_COORD(b, i), UR_COORD(b, i)));
1334
1335 /* compute distance to zero for those dimensions in (a) absent in (b) */
1336 for (i = DIM(b); i < DIM(a); i++)
1337 distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1338 0.0, 0.0));
1339
1340 if (swapped)
1341 {
1342 PG_FREE_IF_COPY(b, 0);
1343 PG_FREE_IF_COPY(a, 1);
1344 }
1345 else
1346 {
1347 PG_FREE_IF_COPY(a, 0);
1348 PG_FREE_IF_COPY(b, 1);
1349 }
1350
1351 PG_RETURN_FLOAT8(distance);
1352}
1353
1354Datum
1356{
1358 *b = PG_GETARG_NDBOX_P(1);
1359 bool swapped = false;
1360 double d,
1361 distance;
1362 int i;
1363
1364 /* swap the box pointers if needed */
1365 if (DIM(a) < DIM(b))
1366 {
1367 NDBOX *tmp = b;
1368
1369 b = a;
1370 a = tmp;
1371 swapped = true;
1372 }
1373
1374 distance = 0.0;
1375 /* compute within the dimensions of (b) */
1376 for (i = 0; i < DIM(b); i++)
1377 {
1379 LL_COORD(b, i), UR_COORD(b, i)));
1380 if (d > distance)
1381 distance = d;
1382 }
1383
1384 /* compute distance to zero for those dimensions in (a) absent in (b) */
1385 for (i = DIM(b); i < DIM(a); i++)
1386 {
1387 d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0));
1388 if (d > distance)
1389 distance = d;
1390 }
1391
1392 if (swapped)
1393 {
1394 PG_FREE_IF_COPY(b, 0);
1395 PG_FREE_IF_COPY(a, 1);
1396 }
1397 else
1398 {
1399 PG_FREE_IF_COPY(a, 0);
1400 PG_FREE_IF_COPY(b, 1);
1401 }
1402
1403 PG_RETURN_FLOAT8(distance);
1404}
1405
1406Datum
1408{
1409 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1411 NDBOX *cube = DatumGetNDBOXP(entry->key);
1412 double retval;
1413
1414 if (strategy == CubeKNNDistanceCoord)
1415 {
1416 /*
1417 * Handle ordering by ~> operator. See comments of cube_coord_llur()
1418 * for details
1419 */
1420 int coord = PG_GETARG_INT32(1);
1421 bool isLeaf = GistPageIsLeaf(entry->page);
1422 bool inverse = false;
1423
1424 /* 0 is the only unsupported coordinate value */
1425 if (coord == 0)
1426 ereport(ERROR,
1428 errmsg("zero cube index is not defined")));
1429
1430 /* Return inversed value for negative coordinate */
1431 if (coord < 0)
1432 {
1433 coord = -coord;
1434 inverse = true;
1435 }
1436
1437 if (coord <= 2 * DIM(cube))
1438 {
1439 /* dimension index */
1440 int index = (coord - 1) / 2;
1441
1442 /* whether this is upper bound (lower bound otherwise) */
1443 bool upper = ((coord - 1) % 2 == 1);
1444
1445 if (IS_POINT(cube))
1446 {
1447 retval = cube->x[index];
1448 }
1449 else
1450 {
1451 if (isLeaf)
1452 {
1453 /* For leaf just return required upper/lower bound */
1454 if (upper)
1455 retval = Max(cube->x[index], cube->x[index + DIM(cube)]);
1456 else
1457 retval = Min(cube->x[index], cube->x[index + DIM(cube)]);
1458 }
1459 else
1460 {
1461 /*
1462 * For non-leaf we should always return lower bound,
1463 * because even upper bound of a child in the subtree can
1464 * be as small as our lower bound. For inversed case we
1465 * return upper bound because it becomes lower bound for
1466 * inversed value.
1467 */
1468 if (!inverse)
1469 retval = Min(cube->x[index], cube->x[index + DIM(cube)]);
1470 else
1471 retval = Max(cube->x[index], cube->x[index + DIM(cube)]);
1472 }
1473 }
1474 }
1475 else
1476 {
1477 retval = 0.0;
1478 }
1479
1480 /* Inverse return value if needed */
1481 if (inverse)
1482 retval = -retval;
1483 }
1484 else
1485 {
1486 NDBOX *query = PG_GETARG_NDBOX_P(1);
1487
1488 switch (strategy)
1489 {
1493 break;
1497 break;
1501 break;
1502 default:
1503 elog(ERROR, "unrecognized cube strategy number: %d", strategy);
1504 retval = 0; /* keep compiler quiet */
1505 break;
1506 }
1507 }
1508 PG_RETURN_FLOAT8(retval);
1509}
1510
1511static double
1512distance_1D(double a1, double a2, double b1, double b2)
1513{
1514 /* interval (a) is entirely on the left of (b) */
1515 if ((a1 <= b1) && (a2 <= b1) && (a1 <= b2) && (a2 <= b2))
1516 return (Min(b1, b2) - Max(a1, a2));
1517
1518 /* interval (a) is entirely on the right of (b) */
1519 if ((a1 > b1) && (a2 > b1) && (a1 > b2) && (a2 > b2))
1520 return (Min(a1, a2) - Max(b1, b2));
1521
1522 /* the rest are all sorts of intersections */
1523 return 0.0;
1524}
1525
1526/* Test if a box is also a point */
1527Datum
1537
1538static bool
1540{
1541 int i;
1542
1543 if (IS_POINT(cube))
1544 return true;
1545
1546 /*
1547 * Even if the point-flag is not set, all the lower-left coordinates might
1548 * match the upper-right coordinates, so that the value is in fact a
1549 * point. Such values don't arise with current code - the point flag is
1550 * always set if appropriate - but they might be present on-disk in
1551 * clusters upgraded from pre-9.4 versions.
1552 */
1553 for (i = 0; i < DIM(cube); i++)
1554 {
1555 if (LL_COORD(cube, i) != UR_COORD(cube, i))
1556 return false;
1557 }
1558 return true;
1559}
1560
1561/* Return dimensions in use in the data structure */
1562Datum
1564{
1566 int dim = DIM(c);
1567
1568 PG_FREE_IF_COPY(c, 0);
1569 PG_RETURN_INT32(dim);
1570}
1571
1572/* Return a specific normalized LL coordinate */
1573Datum
1575{
1577 int n = PG_GETARG_INT32(1);
1578 double result;
1579
1580 if (DIM(c) >= n && n > 0)
1581 result = Min(LL_COORD(c, n - 1), UR_COORD(c, n - 1));
1582 else
1583 result = 0;
1584
1585 PG_FREE_IF_COPY(c, 0);
1587}
1588
1589/* Return a specific normalized UR coordinate */
1590Datum
1592{
1594 int n = PG_GETARG_INT32(1);
1595 double result;
1596
1597 if (DIM(c) >= n && n > 0)
1598 result = Max(LL_COORD(c, n - 1), UR_COORD(c, n - 1));
1599 else
1600 result = 0;
1601
1602 PG_FREE_IF_COPY(c, 0);
1604}
1605
1606/*
1607 * Function returns cube coordinate.
1608 * Numbers from 1 to DIM denotes first corner coordinates.
1609 * Numbers from DIM+1 to 2*DIM denotes second corner coordinates.
1610 */
1611Datum
1613{
1615 int coord = PG_GETARG_INT32(1);
1616
1618 ereport(ERROR,
1620 errmsg("cube index %d is out of bounds", coord)));
1621
1622 if (IS_POINT(cube))
1623 PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]);
1624 else
1625 PG_RETURN_FLOAT8(cube->x[coord - 1]);
1626}
1627
1628
1629/*----
1630 * This function works like cube_coord(), but rearranges coordinates in the
1631 * way suitable to support coordinate ordering using KNN-GiST. For historical
1632 * reasons this extension allows us to create cubes in form ((2,1),(1,2)) and
1633 * instead of normalizing such cube to ((1,1),(2,2)) it stores cube in original
1634 * way. But in order to get cubes ordered by one of dimensions from the index
1635 * without explicit sort step we need this representation-independent coordinate
1636 * getter. Moreover, indexed dataset may contain cubes of different dimensions
1637 * number. Accordingly, this coordinate getter should be able to return
1638 * lower/upper bound for particular dimension independently on number of cube
1639 * dimensions. Also, KNN-GiST supports only ascending sorting. In order to
1640 * support descending sorting, this function returns inverse of value when
1641 * negative coordinate is given.
1642 *
1643 * Long story short, this function uses following meaning of coordinates:
1644 * # (2 * N - 1) -- lower bound of Nth dimension,
1645 * # (2 * N) -- upper bound of Nth dimension,
1646 * # - (2 * N - 1) -- negative of lower bound of Nth dimension,
1647 * # - (2 * N) -- negative of upper bound of Nth dimension.
1648 *
1649 * When given coordinate exceeds number of cube dimensions, then 0 returned
1650 * (reproducing logic of GiST indexing of variable-length cubes).
1651 */
1652Datum
1654{
1656 int coord = PG_GETARG_INT32(1);
1657 bool inverse = false;
1658 float8 result;
1659
1660 /* 0 is the only unsupported coordinate value */
1661 if (coord == 0)
1662 ereport(ERROR,
1664 errmsg("zero cube index is not defined")));
1665
1666 /* Return inversed value for negative coordinate */
1667 if (coord < 0)
1668 {
1669 coord = -coord;
1670 inverse = true;
1671 }
1672
1673 if (coord <= 2 * DIM(cube))
1674 {
1675 /* dimension index */
1676 int index = (coord - 1) / 2;
1677
1678 /* whether this is upper bound (lower bound otherwise) */
1679 bool upper = ((coord - 1) % 2 == 1);
1680
1681 if (IS_POINT(cube))
1682 {
1683 result = cube->x[index];
1684 }
1685 else
1686 {
1687 if (upper)
1688 result = Max(cube->x[index], cube->x[index + DIM(cube)]);
1689 else
1690 result = Min(cube->x[index], cube->x[index + DIM(cube)]);
1691 }
1692 }
1693 else
1694 {
1695 /*
1696 * Return zero if coordinate is out of bound. That reproduces logic
1697 * of how cubes with low dimension number are expanded during GiST
1698 * indexing.
1699 */
1700 result = 0.0;
1701 }
1702
1703 /* Inverse value if needed */
1704 if (inverse)
1705 result = -result;
1706
1708}
1709
1710/* Increase or decrease box size by a radius in at least n dimensions. */
1711Datum
1713{
1715 double r = PG_GETARG_FLOAT8(1);
1716 int32 n = PG_GETARG_INT32(2);
1717 NDBOX *result;
1718 int dim = 0;
1719 int size;
1720 int i,
1721 j;
1722
1723 if (n > CUBE_MAX_DIM)
1724 n = CUBE_MAX_DIM;
1725 if (r > 0 && n > 0)
1726 dim = n;
1727 if (DIM(a) > dim)
1728 dim = DIM(a);
1729
1730 size = CUBE_SIZE(dim);
1731 result = (NDBOX *) palloc0(size);
1732 SET_VARSIZE(result, size);
1733 SET_DIM(result, dim);
1734
1735 for (i = 0, j = dim; i < DIM(a); i++, j++)
1736 {
1737 if (LL_COORD(a, i) >= UR_COORD(a, i))
1738 {
1739 result->x[i] = UR_COORD(a, i) - r;
1740 result->x[j] = LL_COORD(a, i) + r;
1741 }
1742 else
1743 {
1744 result->x[i] = LL_COORD(a, i) - r;
1745 result->x[j] = UR_COORD(a, i) + r;
1746 }
1747 if (result->x[i] > result->x[j])
1748 {
1749 result->x[i] = (result->x[i] + result->x[j]) / 2;
1750 result->x[j] = result->x[i];
1751 }
1752 }
1753 /* dim > a->dim only if r > 0 */
1754 for (; i < dim; i++, j++)
1755 {
1756 result->x[i] = -r;
1757 result->x[j] = r;
1758 }
1759
1760 /*
1761 * Check if the result was in fact a point, and set the flag in the datum
1762 * accordingly. (we don't bother to repalloc it smaller)
1763 */
1765 {
1766 size = POINT_SIZE(dim);
1767 SET_VARSIZE(result, size);
1769 }
1770
1771 PG_FREE_IF_COPY(a, 0);
1773}
1774
1775/* Create a one dimensional box with identical upper and lower coordinates */
1776Datum
1778{
1779 double x = PG_GETARG_FLOAT8(0);
1780 NDBOX *result;
1781 int size;
1782
1783 size = POINT_SIZE(1);
1784 result = (NDBOX *) palloc0(size);
1785 SET_VARSIZE(result, size);
1786 SET_DIM(result, 1);
1788 result->x[0] = x;
1789
1791}
1792
1793/* Create a one dimensional box */
1794Datum
1796{
1797 double x0 = PG_GETARG_FLOAT8(0);
1798 double x1 = PG_GETARG_FLOAT8(1);
1799 NDBOX *result;
1800 int size;
1801
1802 if (x0 == x1)
1803 {
1804 size = POINT_SIZE(1);
1805 result = (NDBOX *) palloc0(size);
1806 SET_VARSIZE(result, size);
1807 SET_DIM(result, 1);
1809 result->x[0] = x0;
1810 }
1811 else
1812 {
1813 size = CUBE_SIZE(1);
1814 result = (NDBOX *) palloc0(size);
1815 SET_VARSIZE(result, size);
1816 SET_DIM(result, 1);
1817 result->x[0] = x0;
1818 result->x[1] = x1;
1819 }
1820
1822}
1823
1824/*
1825 * Add a dimension to an existing cube with the same values for the new
1826 * coordinate
1827 */
1828Datum
1830{
1832 double x = PG_GETARG_FLOAT8(1);
1833 NDBOX *result;
1834 int size;
1835 int i;
1836
1837 if (DIM(cube) + 1 > CUBE_MAX_DIM)
1838 ereport(ERROR,
1840 errmsg("can't extend cube"),
1841 errdetail("A cube cannot have more than %d dimensions.",
1842 CUBE_MAX_DIM)));
1843
1844 if (IS_POINT(cube))
1845 {
1846 size = POINT_SIZE((DIM(cube) + 1));
1847 result = (NDBOX *) palloc0(size);
1848 SET_VARSIZE(result, size);
1849 SET_DIM(result, DIM(cube) + 1);
1851 for (i = 0; i < DIM(cube); i++)
1852 result->x[i] = cube->x[i];
1853 result->x[DIM(result) - 1] = x;
1854 }
1855 else
1856 {
1857 size = CUBE_SIZE((DIM(cube) + 1));
1858 result = (NDBOX *) palloc0(size);
1859 SET_VARSIZE(result, size);
1860 SET_DIM(result, DIM(cube) + 1);
1861 for (i = 0; i < DIM(cube); i++)
1862 {
1863 result->x[i] = cube->x[i];
1864 result->x[DIM(result) + i] = cube->x[DIM(cube) + i];
1865 }
1866 result->x[DIM(result) - 1] = x;
1867 result->x[2 * DIM(result) - 1] = x;
1868 }
1869
1872}
1873
1874/* Add a dimension to an existing cube */
1875Datum
1877{
1879 double x1 = PG_GETARG_FLOAT8(1);
1880 double x2 = PG_GETARG_FLOAT8(2);
1881 NDBOX *result;
1882 int size;
1883 int i;
1884
1885 if (DIM(cube) + 1 > CUBE_MAX_DIM)
1886 ereport(ERROR,
1888 errmsg("can't extend cube"),
1889 errdetail("A cube cannot have more than %d dimensions.",
1890 CUBE_MAX_DIM)));
1891
1892 if (IS_POINT(cube) && (x1 == x2))
1893 {
1894 size = POINT_SIZE((DIM(cube) + 1));
1895 result = (NDBOX *) palloc0(size);
1896 SET_VARSIZE(result, size);
1897 SET_DIM(result, DIM(cube) + 1);
1899 for (i = 0; i < DIM(cube); i++)
1900 result->x[i] = cube->x[i];
1901 result->x[DIM(result) - 1] = x1;
1902 }
1903 else
1904 {
1905 size = CUBE_SIZE((DIM(cube) + 1));
1906 result = (NDBOX *) palloc0(size);
1907 SET_VARSIZE(result, size);
1908 SET_DIM(result, DIM(cube) + 1);
1909 for (i = 0; i < DIM(cube); i++)
1910 {
1911 result->x[i] = LL_COORD(cube, i);
1912 result->x[DIM(result) + i] = UR_COORD(cube, i);
1913 }
1914 result->x[DIM(result) - 1] = x1;
1915 result->x[2 * DIM(result) - 1] = x2;
1916 }
1917
1920}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:263
#define PG_GETARG_ARRAYTYPE_P(n)
Definition array.h:263
#define ARR_DATA_PTR(a)
Definition array.h:322
bool array_contains_nulls(const ArrayType *array)
#define Min(x, y)
Definition c.h:1091
#define Max(x, y)
Definition c.h:1085
double float8
Definition c.h:714
int32_t int32
Definition c.h:620
size_t Size
Definition c.h:689
uint32 result
Datum cube_gt(PG_FUNCTION_ARGS)
Definition cube.c:1084
Datum cube_eq(PG_FUNCTION_ARGS)
Definition cube.c:1039
Datum cube_le(PG_FUNCTION_ARGS)
Definition cube.c:1099
Datum cube_coord(PG_FUNCTION_ARGS)
Definition cube.c:1612
Datum distance_taxicab(PG_FUNCTION_ARGS)
Definition cube.c:1311
Datum cube_ll_coord(PG_FUNCTION_ARGS)
Definition cube.c:1574
Datum cube_subset(PG_FUNCTION_ARGS)
Definition cube.c:247
Datum cube_distance(PG_FUNCTION_ARGS)
Definition cube.c:1262
static bool cube_is_point_internal(NDBOX *cube)
Definition cube.c:1539
bool cube_overlap_v0(NDBOX *a, NDBOX *b)
Definition cube.c:1201
bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy)
Definition cube.c:684
bool cube_contains_v0(NDBOX *a, NDBOX *b)
Definition cube.c:1131
Datum distance_chebyshev(PG_FUNCTION_ARGS)
Definition cube.c:1355
Datum g_cube_picksplit(PG_FUNCTION_ARGS)
Definition cube.c:516
int32 cube_cmp_v0(NDBOX *a, NDBOX *b)
Definition cube.c:944
Datum cube_dim(PG_FUNCTION_ARGS)
Definition cube.c:1563
Datum g_cube_union(PG_FUNCTION_ARGS)
Definition cube.c:430
Datum cube_in(PG_FUNCTION_ARGS)
Definition cube.c:121
Datum cube_enlarge(PG_FUNCTION_ARGS)
Definition cube.c:1712
Datum cube_c_f8(PG_FUNCTION_ARGS)
Definition cube.c:1829
#define ARRNELEMS(x)
Definition cube.c:29
Datum g_cube_same(PG_FUNCTION_ARGS)
Definition cube.c:666
Datum cube_ur_coord(PG_FUNCTION_ARGS)
Definition cube.c:1591
Datum g_cube_distance(PG_FUNCTION_ARGS)
Definition cube.c:1407
Datum cube_contained(PG_FUNCTION_ARGS)
Definition cube.c:1185
Datum cube_cmp(PG_FUNCTION_ARGS)
Definition cube.c:1024
Datum cube_a_f8_f8(PG_FUNCTION_ARGS)
Definition cube.c:143
#define ARRPTR(x)
Definition cube.c:28
Datum g_cube_consistent(PG_FUNCTION_ARGS)
Definition cube.c:395
NDBOX * cube_union_v0(NDBOX *a, NDBOX *b)
Definition cube.c:753
static double distance_1D(double a1, double a2, double b1, double b2)
Definition cube.c:1512
Datum cube_size(PG_FUNCTION_ARGS)
Definition cube.c:904
Datum cube_recv(PG_FUNCTION_ARGS)
Definition cube.c:356
void rt_cube_size(NDBOX *a, double *size)
Definition cube.c:915
Datum cube_lt(PG_FUNCTION_ARGS)
Definition cube.c:1069
Datum cube_contains(PG_FUNCTION_ARGS)
Definition cube.c:1169
Datum cube_union(PG_FUNCTION_ARGS)
Definition cube.c:813
Datum cube_f8_f8(PG_FUNCTION_ARGS)
Definition cube.c:1795
Datum g_cube_decompress(PG_FUNCTION_ARGS)
Definition cube.c:468
Datum cube_f8(PG_FUNCTION_ARGS)
Definition cube.c:1777
Datum cube_a_f8(PG_FUNCTION_ARGS)
Definition cube.c:210
Datum cube_c_f8_f8(PG_FUNCTION_ARGS)
Definition cube.c:1876
Datum cube_coord_llur(PG_FUNCTION_ARGS)
Definition cube.c:1653
Datum cube_inter(PG_FUNCTION_ARGS)
Definition cube.c:828
Datum g_cube_compress(PG_FUNCTION_ARGS)
Definition cube.c:462
Datum cube_is_point(PG_FUNCTION_ARGS)
Definition cube.c:1528
bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy)
Definition cube.c:713
NDBOX * g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
Definition cube.c:740
Datum cube_send(PG_FUNCTION_ARGS)
Definition cube.c:334
Datum cube_overlap(PG_FUNCTION_ARGS)
Definition cube.c:1240
Datum cube_ge(PG_FUNCTION_ARGS)
Definition cube.c:1114
Datum cube_out(PG_FUNCTION_ARGS)
Definition cube.c:296
Datum g_cube_penalty(PG_FUNCTION_ARGS)
Definition cube.c:491
Datum cube_ne(PG_FUNCTION_ARGS)
Definition cube.c:1054
int cube_yyparse(NDBOX **result, Size scanbuflen, struct Node *escontext, yyscan_t yyscanner)
#define SET_DIM(cube, _dim)
Definition cubedata.h:43
void cube_scanner_init(const char *str, Size *scanbuflen, yyscan_t *yyscannerp)
Definition cubescan.l:102
void * yyscan_t
Definition cubedata.h:65
#define DatumGetNDBOXP(x)
Definition cubedata.h:52
#define LL_COORD(cube, i)
Definition cubedata.h:45
#define CUBE_SIZE(_dim)
Definition cubedata.h:49
#define IS_POINT(cube)
Definition cubedata.h:40
#define CubeKNNDistanceCoord
Definition cubedata.h:57
#define POINT_SIZE(_dim)
Definition cubedata.h:48
void cube_scanner_finish(yyscan_t yyscanner)
Definition cubescan.l:121
#define CubeKNNDistanceEuclid
Definition cubedata.h:59
#define DIM(cube)
Definition cubedata.h:42
#define CUBE_MAX_DIM
Definition cubedata.h:7
#define DIM_MASK
Definition cubedata.h:38
#define PG_RETURN_NDBOX_P(x)
Definition cubedata.h:54
#define CubeKNNDistanceTaxicab
Definition cubedata.h:58
#define SET_POINT_BIT(cube)
Definition cubedata.h:41
#define CubeKNNDistanceChebyshev
Definition cubedata.h:60
#define PG_GETARG_NDBOX_P(x)
Definition cubedata.h:53
#define POINT_BIT
Definition cubedata.h:37
#define UR_COORD(cube, i)
Definition cubedata.h:46
int errcode(int sqlerrcode)
Definition elog.c:875
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#define palloc_object(type)
Definition fe_memutils.h:89
char * float8out_internal(double num)
Definition float.c:578
#define PG_FREE_IF_COPY(ptr, n)
Definition fmgr.h:260
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define PG_RETURN_BYTEA_P(x)
Definition fmgr.h:373
#define DirectFunctionCall2(func, arg1, arg2)
Definition fmgr.h:690
#define PG_GETARG_FLOAT8(n)
Definition fmgr.h:283
#define PG_RETURN_FLOAT8(x)
Definition fmgr.h:369
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_MODULE_MAGIC_EXT(...)
Definition fmgr.h:540
#define PG_RETURN_CSTRING(x)
Definition fmgr.h:364
#define PG_GETARG_DATUM(n)
Definition fmgr.h:268
#define PG_GETARG_CSTRING(n)
Definition fmgr.h:278
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define PG_GETARG_UINT16(n)
Definition fmgr.h:272
#define PG_RETURN_INT32(x)
Definition fmgr.h:355
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
#define GIST_LEAF(entry)
Definition gist.h:171
#define GistPageIsLeaf(page)
Definition gist.h:170
#define gistentryinit(e, k, r, pg, o, l)
Definition gist.h:245
const char * str
static const FormData_pg_attribute a1
Definition heap.c:144
static const FormData_pg_attribute a2
Definition heap.c:157
#define nitems(x)
Definition indent.h:31
int b
Definition isn.c:74
int x
Definition isn.c:75
int a
Definition isn.c:73
int j
Definition isn.c:78
int i
Definition isn.c:77
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1635
void * palloc0(Size size)
Definition mcxt.c:1420
void * palloc(Size size)
Definition mcxt.c:1390
static char * errmsg
#define OffsetNumberNext(offsetNumber)
Definition off.h:52
uint16 OffsetNumber
Definition off.h:24
#define FirstOffsetNumber
Definition off.h:27
Datum upper(PG_FUNCTION_ARGS)
static char buf[DEFAULT_XLOG_SEG_SIZE]
static float8 DatumGetFloat8(Datum X)
Definition postgres.h:498
uint64_t Datum
Definition postgres.h:70
#define PointerGetDatum(X)
Definition postgres.h:354
unsigned int Oid
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition pqformat.c:414
float8 pq_getmsgfloat8(StringInfo msg)
Definition pqformat.c:487
void pq_begintypsend(StringInfo buf)
Definition pqformat.c:325
bytea * pq_endtypsend(StringInfo buf)
Definition pqformat.c:345
void pq_sendfloat8(StringInfo buf, float8 f)
Definition pqformat.c:276
static void pq_sendint32(StringInfo buf, uint32 i)
Definition pqformat.h:144
char * c
static int fb(int x)
#define RTOldContainsStrategyNumber
Definition stratnum.h:63
uint16 StrategyNumber
Definition stratnum.h:22
#define RTOverlapStrategyNumber
Definition stratnum.h:53
#define RTSameStrategyNumber
Definition stratnum.h:56
#define RTContainsStrategyNumber
Definition stratnum.h:57
#define RTOldContainedByStrategyNumber
Definition stratnum.h:64
#define RTContainedByStrategyNumber
Definition stratnum.h:58
struct StringInfoData * StringInfo
Definition string.h:15
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
OffsetNumber offset
Definition gist.h:164
Datum key
Definition gist.h:161
Page page
Definition gist.h:163
Relation rel
Definition gist.h:162
int spl_nleft
Definition gist.h:144
OffsetNumber * spl_right
Definition gist.h:148
Datum spl_ldatum
Definition gist.h:145
Datum spl_rdatum
Definition gist.h:150
int spl_nright
Definition gist.h:149
OffsetNumber * spl_left
Definition gist.h:143
Definition type.h:97
static Size VARSIZE(const void *PTR)
Definition varatt.h:298
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432
const char * name