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
135 PG_RETURN_NDBOX_P(result);
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
201 SET_POINT_BIT(result);
202
203 PG_RETURN_NDBOX_P(result);
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);
238 SET_POINT_BIT(result);
239
240 for (i = 0; i < dim; i++)
241 result->x[i] = dur[i];
242
243 PG_RETURN_NDBOX_P(result);
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))
278 SET_POINT_BIT(result);
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);
292 PG_RETURN_NDBOX_P(result);
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
492{
495 float *result = (float *) PG_GETARG_POINTER(2);
496 NDBOX *ud;
497 double tmp1,
498 tmp2;
499
504 *result = (float) (tmp1 - tmp2);
505
506 PG_RETURN_FLOAT8(*result);
507}
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
677 PG_RETURN_NDBOX_P(result);
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 */
802 if (cube_is_point_internal(result))
803 {
804 size = POINT_SIZE(dim);
805 SET_VARSIZE(result, size);
806 SET_POINT_BIT(result);
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 */
877 if (cube_is_point_internal(result))
878 {
879 size = POINT_SIZE(dim);
880 result = repalloc(result, size);
881 SET_VARSIZE(result, size);
882 SET_POINT_BIT(result);
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 */
899 PG_RETURN_NDBOX_P(result);
900}
901
902/* cube_size */
903Datum
905{
907 double result;
908
909 rt_cube_size(a, &result);
910 PG_FREE_IF_COPY(a, 0);
911 PG_RETURN_FLOAT8(result);
912}
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/* make up a metric in which one box will be 'lower' than the other
940 -- this can be useful for sorting and to determine uniqueness */
941int32
943{
944 int i;
945 int dim;
946
947 dim = Min(DIM(a), DIM(b));
948
949 /* compare the common dimensions */
950 for (i = 0; i < dim; i++)
951 {
952 if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
953 Min(LL_COORD(b, i), UR_COORD(b, i)))
954 return 1;
955 if (Min(LL_COORD(a, i), UR_COORD(a, i)) <
956 Min(LL_COORD(b, i), UR_COORD(b, i)))
957 return -1;
958 }
959 for (i = 0; i < dim; i++)
960 {
961 if (Max(LL_COORD(a, i), UR_COORD(a, i)) >
962 Max(LL_COORD(b, i), UR_COORD(b, i)))
963 return 1;
964 if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
965 Max(LL_COORD(b, i), UR_COORD(b, i)))
966 return -1;
967 }
968
969 /* compare extra dimensions to zero */
970 if (DIM(a) > DIM(b))
971 {
972 for (i = dim; i < DIM(a); i++)
973 {
974 if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
975 return 1;
976 if (Min(LL_COORD(a, i), UR_COORD(a, i)) < 0)
977 return -1;
978 }
979 for (i = dim; i < DIM(a); i++)
980 {
981 if (Max(LL_COORD(a, i), UR_COORD(a, i)) > 0)
982 return 1;
983 if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
984 return -1;
985 }
986
987 /*
988 * if all common dimensions are equal, the cube with more dimensions
989 * wins
990 */
991 return 1;
992 }
993 if (DIM(a) < DIM(b))
994 {
995 for (i = dim; i < DIM(b); i++)
996 {
997 if (Min(LL_COORD(b, i), UR_COORD(b, i)) > 0)
998 return -1;
999 if (Min(LL_COORD(b, i), UR_COORD(b, i)) < 0)
1000 return 1;
1001 }
1002 for (i = dim; i < DIM(b); i++)
1003 {
1004 if (Max(LL_COORD(b, i), UR_COORD(b, i)) > 0)
1005 return -1;
1006 if (Max(LL_COORD(b, i), UR_COORD(b, i)) < 0)
1007 return 1;
1008 }
1009
1010 /*
1011 * if all common dimensions are equal, the cube with more dimensions
1012 * wins
1013 */
1014 return -1;
1015 }
1016
1017 /* They're really equal */
1018 return 0;
1019}
1020
1021Datum
1023{
1025 *b = PG_GETARG_NDBOX_P(1);
1026 int32 res;
1027
1028 res = cube_cmp_v0(a, b);
1029
1030 PG_FREE_IF_COPY(a, 0);
1031 PG_FREE_IF_COPY(b, 1);
1032 PG_RETURN_INT32(res);
1033}
1034
1035
1036Datum
1038{
1040 *b = PG_GETARG_NDBOX_P(1);
1041 int32 res;
1042
1043 res = cube_cmp_v0(a, b);
1044
1045 PG_FREE_IF_COPY(a, 0);
1046 PG_FREE_IF_COPY(b, 1);
1047 PG_RETURN_BOOL(res == 0);
1048}
1049
1050
1051Datum
1053{
1055 *b = PG_GETARG_NDBOX_P(1);
1056 int32 res;
1057
1058 res = cube_cmp_v0(a, b);
1059
1060 PG_FREE_IF_COPY(a, 0);
1061 PG_FREE_IF_COPY(b, 1);
1062 PG_RETURN_BOOL(res != 0);
1063}
1064
1065
1066Datum
1068{
1070 *b = PG_GETARG_NDBOX_P(1);
1071 int32 res;
1072
1073 res = cube_cmp_v0(a, b);
1074
1075 PG_FREE_IF_COPY(a, 0);
1076 PG_FREE_IF_COPY(b, 1);
1077 PG_RETURN_BOOL(res < 0);
1078}
1079
1080
1081Datum
1083{
1085 *b = PG_GETARG_NDBOX_P(1);
1086 int32 res;
1087
1088 res = cube_cmp_v0(a, b);
1089
1090 PG_FREE_IF_COPY(a, 0);
1091 PG_FREE_IF_COPY(b, 1);
1092 PG_RETURN_BOOL(res > 0);
1093}
1094
1095
1096Datum
1098{
1100 *b = PG_GETARG_NDBOX_P(1);
1101 int32 res;
1102
1103 res = cube_cmp_v0(a, b);
1104
1105 PG_FREE_IF_COPY(a, 0);
1106 PG_FREE_IF_COPY(b, 1);
1107 PG_RETURN_BOOL(res <= 0);
1108}
1109
1110
1111Datum
1113{
1115 *b = PG_GETARG_NDBOX_P(1);
1116 int32 res;
1117
1118 res = cube_cmp_v0(a, b);
1119
1120 PG_FREE_IF_COPY(a, 0);
1121 PG_FREE_IF_COPY(b, 1);
1122 PG_RETURN_BOOL(res >= 0);
1123}
1124
1125
1126/* Contains */
1127/* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */
1128bool
1130{
1131 int i;
1132
1133 if ((a == NULL) || (b == NULL))
1134 return false;
1135
1136 if (DIM(a) < DIM(b))
1137 {
1138 /*
1139 * the further comparisons will make sense if the excess dimensions of
1140 * (b) were zeroes Since both UL and UR coordinates must be zero, we
1141 * can check them all without worrying about which is which.
1142 */
1143 for (i = DIM(a); i < DIM(b); i++)
1144 {
1145 if (LL_COORD(b, i) != 0)
1146 return false;
1147 if (UR_COORD(b, i) != 0)
1148 return false;
1149 }
1150 }
1151
1152 /* Can't care less about the excess dimensions of (a), if any */
1153 for (i = 0; i < Min(DIM(a), DIM(b)); i++)
1154 {
1155 if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
1156 Min(LL_COORD(b, i), UR_COORD(b, i)))
1157 return false;
1158 if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
1159 Max(LL_COORD(b, i), UR_COORD(b, i)))
1160 return false;
1161 }
1162
1163 return true;
1164}
1165
1166Datum
1168{
1170 *b = PG_GETARG_NDBOX_P(1);
1171 bool res;
1172
1173 res = cube_contains_v0(a, b);
1174
1175 PG_FREE_IF_COPY(a, 0);
1176 PG_FREE_IF_COPY(b, 1);
1177 PG_RETURN_BOOL(res);
1178}
1179
1180/* Contained */
1181/* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */
1182Datum
1184{
1186 *b = PG_GETARG_NDBOX_P(1);
1187 bool res;
1188
1189 res = cube_contains_v0(b, a);
1190
1191 PG_FREE_IF_COPY(a, 0);
1192 PG_FREE_IF_COPY(b, 1);
1193 PG_RETURN_BOOL(res);
1194}
1195
1196/* Overlap */
1197/* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */
1198bool
1200{
1201 int i;
1202
1203 if ((a == NULL) || (b == NULL))
1204 return false;
1205
1206 /* swap the box pointers if needed */
1207 if (DIM(a) < DIM(b))
1208 {
1209 NDBOX *tmp = b;
1210
1211 b = a;
1212 a = tmp;
1213 }
1214
1215 /* compare within the dimensions of (b) */
1216 for (i = 0; i < DIM(b); i++)
1217 {
1218 if (Min(LL_COORD(a, i), UR_COORD(a, i)) > Max(LL_COORD(b, i), UR_COORD(b, i)))
1219 return false;
1220 if (Max(LL_COORD(a, i), UR_COORD(a, i)) < Min(LL_COORD(b, i), UR_COORD(b, i)))
1221 return false;
1222 }
1223
1224 /* compare to zero those dimensions in (a) absent in (b) */
1225 for (i = DIM(b); i < DIM(a); i++)
1226 {
1227 if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
1228 return false;
1229 if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
1230 return false;
1231 }
1232
1233 return true;
1234}
1235
1236
1237Datum
1239{
1241 *b = PG_GETARG_NDBOX_P(1);
1242 bool res;
1243
1244 res = cube_overlap_v0(a, b);
1245
1246 PG_FREE_IF_COPY(a, 0);
1247 PG_FREE_IF_COPY(b, 1);
1248 PG_RETURN_BOOL(res);
1249}
1250
1251
1252/* Distance */
1253/* The distance is computed as a per axis sum of the squared distances
1254 between 1D projections of the boxes onto Cartesian axes. Assuming zero
1255 distance between overlapping projections, this metric coincides with the
1256 "common sense" geometric distance */
1257Datum
1259{
1261 *b = PG_GETARG_NDBOX_P(1);
1262 bool swapped = false;
1263 double d,
1264 distance;
1265 int i;
1266
1267 /* swap the box pointers if needed */
1268 if (DIM(a) < DIM(b))
1269 {
1270 NDBOX *tmp = b;
1271
1272 b = a;
1273 a = tmp;
1274 swapped = true;
1275 }
1276
1277 distance = 0.0;
1278 /* compute within the dimensions of (b) */
1279 for (i = 0; i < DIM(b); i++)
1280 {
1281 d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), LL_COORD(b, i), UR_COORD(b, i));
1282 distance += d * d;
1283 }
1284
1285 /* compute distance to zero for those dimensions in (a) absent in (b) */
1286 for (i = DIM(b); i < DIM(a); i++)
1287 {
1288 d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0);
1289 distance += d * d;
1290 }
1291
1292 if (swapped)
1293 {
1294 PG_FREE_IF_COPY(b, 0);
1295 PG_FREE_IF_COPY(a, 1);
1296 }
1297 else
1298 {
1299 PG_FREE_IF_COPY(a, 0);
1300 PG_FREE_IF_COPY(b, 1);
1301 }
1302
1303 PG_RETURN_FLOAT8(sqrt(distance));
1304}
1305
1306Datum
1308{
1310 *b = PG_GETARG_NDBOX_P(1);
1311 bool swapped = false;
1312 double distance;
1313 int i;
1314
1315 /* swap the box pointers if needed */
1316 if (DIM(a) < DIM(b))
1317 {
1318 NDBOX *tmp = b;
1319
1320 b = a;
1321 a = tmp;
1322 swapped = true;
1323 }
1324
1325 distance = 0.0;
1326 /* compute within the dimensions of (b) */
1327 for (i = 0; i < DIM(b); i++)
1328 distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1329 LL_COORD(b, i), UR_COORD(b, i)));
1330
1331 /* compute distance to zero for those dimensions in (a) absent in (b) */
1332 for (i = DIM(b); i < DIM(a); i++)
1333 distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1334 0.0, 0.0));
1335
1336 if (swapped)
1337 {
1338 PG_FREE_IF_COPY(b, 0);
1339 PG_FREE_IF_COPY(a, 1);
1340 }
1341 else
1342 {
1343 PG_FREE_IF_COPY(a, 0);
1344 PG_FREE_IF_COPY(b, 1);
1345 }
1346
1347 PG_RETURN_FLOAT8(distance);
1348}
1349
1350Datum
1352{
1354 *b = PG_GETARG_NDBOX_P(1);
1355 bool swapped = false;
1356 double d,
1357 distance;
1358 int i;
1359
1360 /* swap the box pointers if needed */
1361 if (DIM(a) < DIM(b))
1362 {
1363 NDBOX *tmp = b;
1364
1365 b = a;
1366 a = tmp;
1367 swapped = true;
1368 }
1369
1370 distance = 0.0;
1371 /* compute within the dimensions of (b) */
1372 for (i = 0; i < DIM(b); i++)
1373 {
1375 LL_COORD(b, i), UR_COORD(b, i)));
1376 if (d > distance)
1377 distance = d;
1378 }
1379
1380 /* compute distance to zero for those dimensions in (a) absent in (b) */
1381 for (i = DIM(b); i < DIM(a); i++)
1382 {
1383 d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0));
1384 if (d > distance)
1385 distance = d;
1386 }
1387
1388 if (swapped)
1389 {
1390 PG_FREE_IF_COPY(b, 0);
1391 PG_FREE_IF_COPY(a, 1);
1392 }
1393 else
1394 {
1395 PG_FREE_IF_COPY(a, 0);
1396 PG_FREE_IF_COPY(b, 1);
1397 }
1398
1399 PG_RETURN_FLOAT8(distance);
1400}
1401
1402Datum
1404{
1405 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1407 NDBOX *cube = DatumGetNDBOXP(entry->key);
1408 double retval;
1409
1410 if (strategy == CubeKNNDistanceCoord)
1411 {
1412 /*
1413 * Handle ordering by ~> operator. See comments of cube_coord_llur()
1414 * for details
1415 */
1416 int coord = PG_GETARG_INT32(1);
1417 bool isLeaf = GistPageIsLeaf(entry->page);
1418 bool inverse = false;
1419
1420 /* 0 is the only unsupported coordinate value */
1421 if (coord == 0)
1422 ereport(ERROR,
1424 errmsg("zero cube index is not defined")));
1425
1426 /* Return inversed value for negative coordinate */
1427 if (coord < 0)
1428 {
1429 coord = -coord;
1430 inverse = true;
1431 }
1432
1433 if (coord <= 2 * DIM(cube))
1434 {
1435 /* dimension index */
1436 int index = (coord - 1) / 2;
1437
1438 /* whether this is upper bound (lower bound otherwise) */
1439 bool upper = ((coord - 1) % 2 == 1);
1440
1441 if (IS_POINT(cube))
1442 {
1443 retval = cube->x[index];
1444 }
1445 else
1446 {
1447 if (isLeaf)
1448 {
1449 /* For leaf just return required upper/lower bound */
1450 if (upper)
1451 retval = Max(cube->x[index], cube->x[index + DIM(cube)]);
1452 else
1453 retval = Min(cube->x[index], cube->x[index + DIM(cube)]);
1454 }
1455 else
1456 {
1457 /*
1458 * For non-leaf we should always return lower bound,
1459 * because even upper bound of a child in the subtree can
1460 * be as small as our lower bound. For inversed case we
1461 * return upper bound because it becomes lower bound for
1462 * inversed value.
1463 */
1464 if (!inverse)
1465 retval = Min(cube->x[index], cube->x[index + DIM(cube)]);
1466 else
1467 retval = Max(cube->x[index], cube->x[index + DIM(cube)]);
1468 }
1469 }
1470 }
1471 else
1472 {
1473 retval = 0.0;
1474 }
1475
1476 /* Inverse return value if needed */
1477 if (inverse)
1478 retval = -retval;
1479 }
1480 else
1481 {
1482 NDBOX *query = PG_GETARG_NDBOX_P(1);
1483
1484 switch (strategy)
1485 {
1489 break;
1493 break;
1497 break;
1498 default:
1499 elog(ERROR, "unrecognized cube strategy number: %d", strategy);
1500 retval = 0; /* keep compiler quiet */
1501 break;
1502 }
1503 }
1504 PG_RETURN_FLOAT8(retval);
1505}
1506
1507static double
1508distance_1D(double a1, double a2, double b1, double b2)
1509{
1510 /* interval (a) is entirely on the left of (b) */
1511 if ((a1 <= b1) && (a2 <= b1) && (a1 <= b2) && (a2 <= b2))
1512 return (Min(b1, b2) - Max(a1, a2));
1513
1514 /* interval (a) is entirely on the right of (b) */
1515 if ((a1 > b1) && (a2 > b1) && (a1 > b2) && (a2 > b2))
1516 return (Min(a1, a2) - Max(b1, b2));
1517
1518 /* the rest are all sorts of intersections */
1519 return 0.0;
1520}
1521
1522/* Test if a box is also a point */
1523Datum
1525{
1527 bool result;
1528
1529 result = cube_is_point_internal(cube);
1531 PG_RETURN_BOOL(result);
1532}
1533
1534static bool
1536{
1537 int i;
1538
1539 if (IS_POINT(cube))
1540 return true;
1541
1542 /*
1543 * Even if the point-flag is not set, all the lower-left coordinates might
1544 * match the upper-right coordinates, so that the value is in fact a
1545 * point. Such values don't arise with current code - the point flag is
1546 * always set if appropriate - but they might be present on-disk in
1547 * clusters upgraded from pre-9.4 versions.
1548 */
1549 for (i = 0; i < DIM(cube); i++)
1550 {
1551 if (LL_COORD(cube, i) != UR_COORD(cube, i))
1552 return false;
1553 }
1554 return true;
1555}
1556
1557/* Return dimensions in use in the data structure */
1558Datum
1560{
1562 int dim = DIM(c);
1563
1564 PG_FREE_IF_COPY(c, 0);
1565 PG_RETURN_INT32(dim);
1566}
1567
1568/* Return a specific normalized LL coordinate */
1569Datum
1571{
1573 int n = PG_GETARG_INT32(1);
1574 double result;
1575
1576 if (DIM(c) >= n && n > 0)
1577 result = Min(LL_COORD(c, n - 1), UR_COORD(c, n - 1));
1578 else
1579 result = 0;
1580
1581 PG_FREE_IF_COPY(c, 0);
1582 PG_RETURN_FLOAT8(result);
1583}
1584
1585/* Return a specific normalized UR coordinate */
1586Datum
1588{
1590 int n = PG_GETARG_INT32(1);
1591 double result;
1592
1593 if (DIM(c) >= n && n > 0)
1594 result = Max(LL_COORD(c, n - 1), UR_COORD(c, n - 1));
1595 else
1596 result = 0;
1597
1598 PG_FREE_IF_COPY(c, 0);
1599 PG_RETURN_FLOAT8(result);
1600}
1601
1602/*
1603 * Function returns cube coordinate.
1604 * Numbers from 1 to DIM denotes first corner coordinates.
1605 * Numbers from DIM+1 to 2*DIM denotes second corner coordinates.
1606 */
1607Datum
1609{
1611 int coord = PG_GETARG_INT32(1);
1612
1614 ereport(ERROR,
1616 errmsg("cube index %d is out of bounds", coord)));
1617
1618 if (IS_POINT(cube))
1619 PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]);
1620 else
1621 PG_RETURN_FLOAT8(cube->x[coord - 1]);
1622}
1623
1624
1625/*----
1626 * This function works like cube_coord(), but rearranges coordinates in the
1627 * way suitable to support coordinate ordering using KNN-GiST. For historical
1628 * reasons this extension allows us to create cubes in form ((2,1),(1,2)) and
1629 * instead of normalizing such cube to ((1,1),(2,2)) it stores cube in original
1630 * way. But in order to get cubes ordered by one of dimensions from the index
1631 * without explicit sort step we need this representation-independent coordinate
1632 * getter. Moreover, indexed dataset may contain cubes of different dimensions
1633 * number. Accordingly, this coordinate getter should be able to return
1634 * lower/upper bound for particular dimension independently on number of cube
1635 * dimensions. Also, KNN-GiST supports only ascending sorting. In order to
1636 * support descending sorting, this function returns inverse of value when
1637 * negative coordinate is given.
1638 *
1639 * Long story short, this function uses following meaning of coordinates:
1640 * # (2 * N - 1) -- lower bound of Nth dimension,
1641 * # (2 * N) -- upper bound of Nth dimension,
1642 * # - (2 * N - 1) -- negative of lower bound of Nth dimension,
1643 * # - (2 * N) -- negative of upper bound of Nth dimension.
1644 *
1645 * When given coordinate exceeds number of cube dimensions, then 0 returned
1646 * (reproducing logic of GiST indexing of variable-length cubes).
1647 */
1648Datum
1650{
1652 int coord = PG_GETARG_INT32(1);
1653 bool inverse = false;
1654 float8 result;
1655
1656 /* 0 is the only unsupported coordinate value */
1657 if (coord == 0)
1658 ereport(ERROR,
1660 errmsg("zero cube index is not defined")));
1661
1662 /* Return inversed value for negative coordinate */
1663 if (coord < 0)
1664 {
1665 coord = -coord;
1666 inverse = true;
1667 }
1668
1669 if (coord <= 2 * DIM(cube))
1670 {
1671 /* dimension index */
1672 int index = (coord - 1) / 2;
1673
1674 /* whether this is upper bound (lower bound otherwise) */
1675 bool upper = ((coord - 1) % 2 == 1);
1676
1677 if (IS_POINT(cube))
1678 {
1679 result = cube->x[index];
1680 }
1681 else
1682 {
1683 if (upper)
1684 result = Max(cube->x[index], cube->x[index + DIM(cube)]);
1685 else
1686 result = Min(cube->x[index], cube->x[index + DIM(cube)]);
1687 }
1688 }
1689 else
1690 {
1691 /*
1692 * Return zero if coordinate is out of bound. That reproduces logic
1693 * of how cubes with low dimension number are expanded during GiST
1694 * indexing.
1695 */
1696 result = 0.0;
1697 }
1698
1699 /* Inverse value if needed */
1700 if (inverse)
1701 result = -result;
1702
1703 PG_RETURN_FLOAT8(result);
1704}
1705
1706/* Increase or decrease box size by a radius in at least n dimensions. */
1707Datum
1709{
1711 double r = PG_GETARG_FLOAT8(1);
1712 int32 n = PG_GETARG_INT32(2);
1713 NDBOX *result;
1714 int dim = 0;
1715 int size;
1716 int i,
1717 j;
1718
1719 if (n > CUBE_MAX_DIM)
1720 n = CUBE_MAX_DIM;
1721 if (r > 0 && n > 0)
1722 dim = n;
1723 if (DIM(a) > dim)
1724 dim = DIM(a);
1725
1726 size = CUBE_SIZE(dim);
1727 result = (NDBOX *) palloc0(size);
1728 SET_VARSIZE(result, size);
1729 SET_DIM(result, dim);
1730
1731 for (i = 0, j = dim; i < DIM(a); i++, j++)
1732 {
1733 if (LL_COORD(a, i) >= UR_COORD(a, i))
1734 {
1735 result->x[i] = UR_COORD(a, i) - r;
1736 result->x[j] = LL_COORD(a, i) + r;
1737 }
1738 else
1739 {
1740 result->x[i] = LL_COORD(a, i) - r;
1741 result->x[j] = UR_COORD(a, i) + r;
1742 }
1743 if (result->x[i] > result->x[j])
1744 {
1745 result->x[i] = (result->x[i] + result->x[j]) / 2;
1746 result->x[j] = result->x[i];
1747 }
1748 }
1749 /* dim > a->dim only if r > 0 */
1750 for (; i < dim; i++, j++)
1751 {
1752 result->x[i] = -r;
1753 result->x[j] = r;
1754 }
1755
1756 /*
1757 * Check if the result was in fact a point, and set the flag in the datum
1758 * accordingly. (we don't bother to repalloc it smaller)
1759 */
1760 if (cube_is_point_internal(result))
1761 {
1762 size = POINT_SIZE(dim);
1763 SET_VARSIZE(result, size);
1764 SET_POINT_BIT(result);
1765 }
1766
1767 PG_FREE_IF_COPY(a, 0);
1768 PG_RETURN_NDBOX_P(result);
1769}
1770
1771/* Create a one dimensional box with identical upper and lower coordinates */
1772Datum
1774{
1775 double x = PG_GETARG_FLOAT8(0);
1776 NDBOX *result;
1777 int size;
1778
1779 size = POINT_SIZE(1);
1780 result = (NDBOX *) palloc0(size);
1781 SET_VARSIZE(result, size);
1782 SET_DIM(result, 1);
1783 SET_POINT_BIT(result);
1784 result->x[0] = x;
1785
1786 PG_RETURN_NDBOX_P(result);
1787}
1788
1789/* Create a one dimensional box */
1790Datum
1792{
1793 double x0 = PG_GETARG_FLOAT8(0);
1794 double x1 = PG_GETARG_FLOAT8(1);
1795 NDBOX *result;
1796 int size;
1797
1798 if (x0 == x1)
1799 {
1800 size = POINT_SIZE(1);
1801 result = (NDBOX *) palloc0(size);
1802 SET_VARSIZE(result, size);
1803 SET_DIM(result, 1);
1804 SET_POINT_BIT(result);
1805 result->x[0] = x0;
1806 }
1807 else
1808 {
1809 size = CUBE_SIZE(1);
1810 result = (NDBOX *) palloc0(size);
1811 SET_VARSIZE(result, size);
1812 SET_DIM(result, 1);
1813 result->x[0] = x0;
1814 result->x[1] = x1;
1815 }
1816
1817 PG_RETURN_NDBOX_P(result);
1818}
1819
1820/* Add a dimension to an existing cube with the same values for the new
1821 coordinate */
1822Datum
1824{
1826 double x = PG_GETARG_FLOAT8(1);
1827 NDBOX *result;
1828 int size;
1829 int i;
1830
1831 if (DIM(cube) + 1 > CUBE_MAX_DIM)
1832 ereport(ERROR,
1834 errmsg("can't extend cube"),
1835 errdetail("A cube cannot have more than %d dimensions.",
1836 CUBE_MAX_DIM)));
1837
1838 if (IS_POINT(cube))
1839 {
1840 size = POINT_SIZE((DIM(cube) + 1));
1841 result = (NDBOX *) palloc0(size);
1842 SET_VARSIZE(result, size);
1843 SET_DIM(result, DIM(cube) + 1);
1844 SET_POINT_BIT(result);
1845 for (i = 0; i < DIM(cube); i++)
1846 result->x[i] = cube->x[i];
1847 result->x[DIM(result) - 1] = x;
1848 }
1849 else
1850 {
1851 size = CUBE_SIZE((DIM(cube) + 1));
1852 result = (NDBOX *) palloc0(size);
1853 SET_VARSIZE(result, size);
1854 SET_DIM(result, DIM(cube) + 1);
1855 for (i = 0; i < DIM(cube); i++)
1856 {
1857 result->x[i] = cube->x[i];
1858 result->x[DIM(result) + i] = cube->x[DIM(cube) + i];
1859 }
1860 result->x[DIM(result) - 1] = x;
1861 result->x[2 * DIM(result) - 1] = x;
1862 }
1863
1865 PG_RETURN_NDBOX_P(result);
1866}
1867
1868/* Add a dimension to an existing cube */
1869Datum
1871{
1873 double x1 = PG_GETARG_FLOAT8(1);
1874 double x2 = PG_GETARG_FLOAT8(2);
1875 NDBOX *result;
1876 int size;
1877 int i;
1878
1879 if (DIM(cube) + 1 > CUBE_MAX_DIM)
1880 ereport(ERROR,
1882 errmsg("can't extend cube"),
1883 errdetail("A cube cannot have more than %d dimensions.",
1884 CUBE_MAX_DIM)));
1885
1886 if (IS_POINT(cube) && (x1 == x2))
1887 {
1888 size = POINT_SIZE((DIM(cube) + 1));
1889 result = (NDBOX *) palloc0(size);
1890 SET_VARSIZE(result, size);
1891 SET_DIM(result, DIM(cube) + 1);
1892 SET_POINT_BIT(result);
1893 for (i = 0; i < DIM(cube); i++)
1894 result->x[i] = cube->x[i];
1895 result->x[DIM(result) - 1] = x1;
1896 }
1897 else
1898 {
1899 size = CUBE_SIZE((DIM(cube) + 1));
1900 result = (NDBOX *) palloc0(size);
1901 SET_VARSIZE(result, size);
1902 SET_DIM(result, DIM(cube) + 1);
1903 for (i = 0; i < DIM(cube); i++)
1904 {
1905 result->x[i] = LL_COORD(cube, i);
1906 result->x[DIM(result) + i] = UR_COORD(cube, i);
1907 }
1908 result->x[DIM(result) - 1] = x1;
1909 result->x[2 * DIM(result) - 1] = x2;
1910 }
1911
1913 PG_RETURN_NDBOX_P(result);
1914}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:262
#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:997
#define Max(x, y)
Definition c.h:991
double float8
Definition c.h:644
int32_t int32
Definition c.h:542
size_t Size
Definition c.h:619
Datum cube_gt(PG_FUNCTION_ARGS)
Definition cube.c:1082
Datum cube_eq(PG_FUNCTION_ARGS)
Definition cube.c:1037
Datum cube_le(PG_FUNCTION_ARGS)
Definition cube.c:1097
Datum cube_coord(PG_FUNCTION_ARGS)
Definition cube.c:1608
Datum distance_taxicab(PG_FUNCTION_ARGS)
Definition cube.c:1307
Datum cube_ll_coord(PG_FUNCTION_ARGS)
Definition cube.c:1570
Datum cube_subset(PG_FUNCTION_ARGS)
Definition cube.c:247
Datum cube_distance(PG_FUNCTION_ARGS)
Definition cube.c:1258
static bool cube_is_point_internal(NDBOX *cube)
Definition cube.c:1535
bool cube_overlap_v0(NDBOX *a, NDBOX *b)
Definition cube.c:1199
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:1129
Datum distance_chebyshev(PG_FUNCTION_ARGS)
Definition cube.c:1351
Datum g_cube_picksplit(PG_FUNCTION_ARGS)
Definition cube.c:516
int32 cube_cmp_v0(NDBOX *a, NDBOX *b)
Definition cube.c:942
Datum cube_dim(PG_FUNCTION_ARGS)
Definition cube.c:1559
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:1708
Datum cube_c_f8(PG_FUNCTION_ARGS)
Definition cube.c:1823
#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:1587
Datum g_cube_distance(PG_FUNCTION_ARGS)
Definition cube.c:1403
Datum cube_contained(PG_FUNCTION_ARGS)
Definition cube.c:1183
Datum cube_cmp(PG_FUNCTION_ARGS)
Definition cube.c:1022
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:1508
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:1067
Datum cube_contains(PG_FUNCTION_ARGS)
Definition cube.c:1167
Datum cube_union(PG_FUNCTION_ARGS)
Definition cube.c:813
Datum cube_f8_f8(PG_FUNCTION_ARGS)
Definition cube.c:1791
Datum g_cube_decompress(PG_FUNCTION_ARGS)
Definition cube.c:468
Datum cube_f8(PG_FUNCTION_ARGS)
Definition cube.c:1773
Datum cube_a_f8(PG_FUNCTION_ARGS)
Definition cube.c:210
Datum cube_c_f8_f8(PG_FUNCTION_ARGS)
Definition cube.c:1870
Datum cube_coord_llur(PG_FUNCTION_ARGS)
Definition cube.c:1649
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:1524
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:1238
Datum cube_ge(PG_FUNCTION_ARGS)
Definition cube.c:1112
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:1052
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 errdetail(const char *fmt,...)
Definition elog.c:1216
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define palloc_object(type)
Definition fe_memutils.h:74
char * float8out_internal(double num)
Definition float.c:537
#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:686
#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:1632
void * palloc0(Size size)
Definition mcxt.c:1417
void * palloc(Size size)
Definition mcxt.c:1387
#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 Datum PointerGetDatum(const void *X)
Definition postgres.h:352
static float8 DatumGetFloat8(Datum X)
Definition postgres.h:495
uint64_t Datum
Definition postgres.h:70
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
double x[FLEXIBLE_ARRAY_MEMBER]
Definition cubedata.h:33
Definition type.h:96
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