PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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);
103NDBOX *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep);
104bool g_cube_leaf_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
157 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
158 errmsg("cannot work with arrays containing NULLs")));
159
160 dim = ARRNELEMS(ur);
161 if (dim > CUBE_MAX_DIM)
163 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
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)
170 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
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
219 if (array_contains_nulls(ur))
221 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
222 errmsg("cannot work with arrays containing NULLs")));
223
224 dim = ARRNELEMS(ur);
225 if (dim > CUBE_MAX_DIM)
227 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
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
259 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
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)
267 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
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)))
284 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
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{
298 NDBOX *cube = PG_GETARG_NDBOX_P(0);
300 int dim = DIM(cube);
301 int i;
302
304
306 for (i = 0; i < dim; i++)
307 {
308 if (i > 0)
311 }
313
314 if (!cube_is_point_internal(cube))
315 {
317 for (i = 0; i < dim; i++)
318 {
319 if (i > 0)
322 }
324 }
325
326 PG_FREE_IF_COPY(cube, 0);
328}
329
330/*
331 * cube_send - a binary output handler for cube type
332 */
333Datum
335{
336 NDBOX *cube = PG_GETARG_NDBOX_P(0);
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)
368 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
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
380 PG_RETURN_NDBOX_P(cube);
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
401 /* Oid subtype = PG_GETARG_OID(3); */
402 bool *recheck = (bool *) PG_GETARG_POINTER(4);
403 bool res;
404
405 /* All cases served by this function are exact */
406 *recheck = false;
407
408 /*
409 * if entry is not leaf, use g_cube_internal_consistent, else use
410 * g_cube_leaf_consistent
411 */
412 if (GIST_LEAF(entry))
414 query, strategy);
415 else
417 query, strategy);
418
419 PG_FREE_IF_COPY(query, 1);
420 PG_RETURN_BOOL(res);
421}
422
423
424/*
425** The GiST Union method for boxes
426** returns the minimal bounding box that encloses all the entries in entryvec
427*/
428Datum
430{
432 int *sizep = (int *) PG_GETARG_POINTER(1);
433 NDBOX *out = (NDBOX *) NULL;
434 NDBOX *tmp;
435 int i;
436
437 tmp = DatumGetNDBOXP(entryvec->vector[0].key);
438
439 /*
440 * sizep = sizeof(NDBOX); -- NDBOX has variable size
441 */
442 *sizep = VARSIZE(tmp);
443
444 for (i = 1; i < entryvec->n; i++)
445 {
446 out = g_cube_binary_union(tmp,
447 DatumGetNDBOXP(entryvec->vector[i].key),
448 sizep);
449 tmp = out;
450 }
451
453}
454
455/*
456** GiST Compress and Decompress methods for boxes
457** do not do anything.
458*/
459
460Datum
462{
464}
465
466Datum
468{
469 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
470 NDBOX *key = DatumGetNDBOXP(entry->key);
471
472 if (key != DatumGetNDBOXP(entry->key))
473 {
474 GISTENTRY *retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
475
477 entry->rel, entry->page,
478 entry->offset, false);
479 PG_RETURN_POINTER(retval);
480 }
481 PG_RETURN_POINTER(entry);
482}
483
484
485/*
486** The GiST Penalty method for boxes
487** As in the R-tree paper, we use change in area as our penalty metric
488*/
489Datum
491{
492 GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
493 GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
494 float *result = (float *) PG_GETARG_POINTER(2);
495 NDBOX *ud;
496 double tmp1,
497 tmp2;
498
499 ud = cube_union_v0(DatumGetNDBOXP(origentry->key),
500 DatumGetNDBOXP(newentry->key));
501 rt_cube_size(ud, &tmp1);
502 rt_cube_size(DatumGetNDBOXP(origentry->key), &tmp2);
503 *result = (float) (tmp1 - tmp2);
504
505 PG_RETURN_FLOAT8(*result);
506}
507
508
509
510/*
511** The GiST PickSplit method for boxes
512** We use Guttman's poly time split algorithm
513*/
514Datum
516{
520 j;
521 NDBOX *datum_alpha,
522 *datum_beta;
523 NDBOX *datum_l,
524 *datum_r;
525 NDBOX *union_d,
526 *union_dl,
527 *union_dr;
528 NDBOX *inter_d;
529 bool firsttime;
530 double size_alpha,
531 size_beta,
532 size_union,
533 size_inter;
534 double size_waste,
535 waste;
536 double size_l,
537 size_r;
538 int nbytes;
539 OffsetNumber seed_1 = 1,
540 seed_2 = 2;
541 OffsetNumber *left,
542 *right;
543 OffsetNumber maxoff;
544
545 maxoff = entryvec->n - 2;
546 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
547 v->spl_left = (OffsetNumber *) palloc(nbytes);
548 v->spl_right = (OffsetNumber *) palloc(nbytes);
549
550 firsttime = true;
551 waste = 0.0;
552
553 for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
554 {
555 datum_alpha = DatumGetNDBOXP(entryvec->vector[i].key);
556 for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
557 {
558 datum_beta = DatumGetNDBOXP(entryvec->vector[j].key);
559
560 /* compute the wasted space by unioning these guys */
561 /* size_waste = size_union - size_inter; */
562 union_d = cube_union_v0(datum_alpha, datum_beta);
563 rt_cube_size(union_d, &size_union);
565 entryvec->vector[i].key,
566 entryvec->vector[j].key));
567 rt_cube_size(inter_d, &size_inter);
568 size_waste = size_union - size_inter;
569
570 /*
571 * are these a more promising split than what we've already seen?
572 */
573
574 if (size_waste > waste || firsttime)
575 {
576 waste = size_waste;
577 seed_1 = i;
578 seed_2 = j;
579 firsttime = false;
580 }
581 }
582 }
583
584 left = v->spl_left;
585 v->spl_nleft = 0;
586 right = v->spl_right;
587 v->spl_nright = 0;
588
589 datum_alpha = DatumGetNDBOXP(entryvec->vector[seed_1].key);
590 datum_l = cube_union_v0(datum_alpha, datum_alpha);
591 rt_cube_size(datum_l, &size_l);
592 datum_beta = DatumGetNDBOXP(entryvec->vector[seed_2].key);
593 datum_r = cube_union_v0(datum_beta, datum_beta);
594 rt_cube_size(datum_r, &size_r);
595
596 /*
597 * Now split up the regions between the two seeds. An important property
598 * of this split algorithm is that the split vector v has the indices of
599 * items to be split in order in its left and right vectors. We exploit
600 * this property by doing a merge in the code that actually splits the
601 * page.
602 *
603 * For efficiency, we also place the new index tuple in this loop. This is
604 * handled at the very end, when we have placed all the existing tuples
605 * and i == maxoff + 1.
606 */
607
608 maxoff = OffsetNumberNext(maxoff);
609 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
610 {
611 /*
612 * If we've already decided where to place this item, just put it on
613 * the right list. Otherwise, we need to figure out which page needs
614 * the least enlargement in order to store the item.
615 */
616
617 if (i == seed_1)
618 {
619 *left++ = i;
620 v->spl_nleft++;
621 continue;
622 }
623 else if (i == seed_2)
624 {
625 *right++ = i;
626 v->spl_nright++;
627 continue;
628 }
629
630 /* okay, which page needs least enlargement? */
631 datum_alpha = DatumGetNDBOXP(entryvec->vector[i].key);
632 union_dl = cube_union_v0(datum_l, datum_alpha);
633 union_dr = cube_union_v0(datum_r, datum_alpha);
634 rt_cube_size(union_dl, &size_alpha);
635 rt_cube_size(union_dr, &size_beta);
636
637 /* pick which page to add it to */
638 if (size_alpha - size_l < size_beta - size_r)
639 {
640 datum_l = union_dl;
641 size_l = size_alpha;
642 *left++ = i;
643 v->spl_nleft++;
644 }
645 else
646 {
647 datum_r = union_dr;
648 size_r = size_beta;
649 *right++ = i;
650 v->spl_nright++;
651 }
652 }
653 *left = *right = FirstOffsetNumber; /* sentinel value */
654
655 v->spl_ldatum = PointerGetDatum(datum_l);
656 v->spl_rdatum = PointerGetDatum(datum_r);
657
659}
660
661/*
662** Equality method
663*/
664Datum
666{
667 NDBOX *b1 = PG_GETARG_NDBOX_P(0);
668 NDBOX *b2 = PG_GETARG_NDBOX_P(1);
669 bool *result = (bool *) PG_GETARG_POINTER(2);
670
671 if (cube_cmp_v0(b1, b2) == 0)
672 *result = true;
673 else
674 *result = false;
675
676 PG_RETURN_NDBOX_P(result);
677}
678
679/*
680** SUPPORT ROUTINES
681*/
682bool
684 NDBOX *query,
685 StrategyNumber strategy)
686{
687 bool retval;
688
689 switch (strategy)
690 {
692 retval = cube_overlap_v0(key, query);
693 break;
695 retval = (cube_cmp_v0(key, query) == 0);
696 break;
699 retval = cube_contains_v0(key, query);
700 break;
703 retval = cube_contains_v0(query, key);
704 break;
705 default:
706 retval = false;
707 }
708 return retval;
709}
710
711bool
713 NDBOX *query,
714 StrategyNumber strategy)
715{
716 bool retval;
717
718 switch (strategy)
719 {
721 retval = (bool) cube_overlap_v0(key, query);
722 break;
726 retval = (bool) cube_contains_v0(key, query);
727 break;
730 retval = (bool) cube_overlap_v0(key, query);
731 break;
732 default:
733 retval = false;
734 }
735 return retval;
736}
737
738NDBOX *
739g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
740{
741 NDBOX *retval;
742
743 retval = cube_union_v0(r1, r2);
744 *sizep = VARSIZE(retval);
745
746 return retval;
747}
748
749
750/* cube_union_v0 */
751NDBOX *
753{
754 int i;
755 NDBOX *result;
756 int dim;
757 int size;
758
759 /* trivial case */
760 if (a == b)
761 return a;
762
763 /* swap the arguments if needed, so that 'a' is always larger than 'b' */
764 if (DIM(a) < DIM(b))
765 {
766 NDBOX *tmp = b;
767
768 b = a;
769 a = tmp;
770 }
771 dim = DIM(a);
772
773 size = CUBE_SIZE(dim);
774 result = palloc0(size);
775 SET_VARSIZE(result, size);
776 SET_DIM(result, dim);
777
778 /* First compute the union of the dimensions present in both args */
779 for (i = 0; i < DIM(b); i++)
780 {
781 result->x[i] = Min(Min(LL_COORD(a, i), UR_COORD(a, i)),
782 Min(LL_COORD(b, i), UR_COORD(b, i)));
783 result->x[i + DIM(a)] = Max(Max(LL_COORD(a, i), UR_COORD(a, i)),
784 Max(LL_COORD(b, i), UR_COORD(b, i)));
785 }
786 /* continue on the higher dimensions only present in 'a' */
787 for (; i < DIM(a); i++)
788 {
789 result->x[i] = Min(0,
790 Min(LL_COORD(a, i), UR_COORD(a, i))
791 );
792 result->x[i + dim] = Max(0,
793 Max(LL_COORD(a, i), UR_COORD(a, i))
794 );
795 }
796
797 /*
798 * Check if the result was in fact a point, and set the flag in the datum
799 * accordingly. (we don't bother to repalloc it smaller)
800 */
801 if (cube_is_point_internal(result))
802 {
803 size = POINT_SIZE(dim);
804 SET_VARSIZE(result, size);
805 SET_POINT_BIT(result);
806 }
807
808 return result;
809}
810
811Datum
813{
816 NDBOX *res;
817
818 res = cube_union_v0(a, b);
819
820 PG_FREE_IF_COPY(a, 0);
821 PG_FREE_IF_COPY(b, 1);
823}
824
825/* cube_inter */
826Datum
828{
831 NDBOX *result;
832 bool swapped = false;
833 int i;
834 int dim;
835 int size;
836
837 /* swap the arguments if needed, so that 'a' is always larger than 'b' */
838 if (DIM(a) < DIM(b))
839 {
840 NDBOX *tmp = b;
841
842 b = a;
843 a = tmp;
844 swapped = true;
845 }
846 dim = DIM(a);
847
848 size = CUBE_SIZE(dim);
849 result = (NDBOX *) palloc0(size);
850 SET_VARSIZE(result, size);
851 SET_DIM(result, dim);
852
853 /* First compute intersection of the dimensions present in both args */
854 for (i = 0; i < DIM(b); i++)
855 {
856 result->x[i] = Max(Min(LL_COORD(a, i), UR_COORD(a, i)),
857 Min(LL_COORD(b, i), UR_COORD(b, i)));
858 result->x[i + DIM(a)] = Min(Max(LL_COORD(a, i), UR_COORD(a, i)),
859 Max(LL_COORD(b, i), UR_COORD(b, i)));
860 }
861 /* continue on the higher dimensions only present in 'a' */
862 for (; i < DIM(a); i++)
863 {
864 result->x[i] = Max(0,
865 Min(LL_COORD(a, i), UR_COORD(a, i))
866 );
867 result->x[i + DIM(a)] = Min(0,
868 Max(LL_COORD(a, i), UR_COORD(a, i))
869 );
870 }
871
872 /*
873 * Check if the result was in fact a point, and set the flag in the datum
874 * accordingly. (we don't bother to repalloc it smaller)
875 */
876 if (cube_is_point_internal(result))
877 {
878 size = POINT_SIZE(dim);
879 result = repalloc(result, size);
880 SET_VARSIZE(result, size);
881 SET_POINT_BIT(result);
882 }
883
884 if (swapped)
885 {
886 PG_FREE_IF_COPY(b, 0);
887 PG_FREE_IF_COPY(a, 1);
888 }
889 else
890 {
891 PG_FREE_IF_COPY(a, 0);
892 PG_FREE_IF_COPY(b, 1);
893 }
894
895 /*
896 * Is it OK to return a non-null intersection for non-overlapping boxes?
897 */
898 PG_RETURN_NDBOX_P(result);
899}
900
901/* cube_size */
902Datum
904{
906 double result;
907
908 rt_cube_size(a, &result);
909 PG_FREE_IF_COPY(a, 0);
910 PG_RETURN_FLOAT8(result);
911}
912
913void
914rt_cube_size(NDBOX *a, double *size)
915{
916 double result;
917 int i;
918
919 if (a == (NDBOX *) NULL)
920 {
921 /* special case for GiST */
922 result = 0.0;
923 }
924 else if (IS_POINT(a) || DIM(a) == 0)
925 {
926 /* necessarily has zero size */
927 result = 0.0;
928 }
929 else
930 {
931 result = 1.0;
932 for (i = 0; i < DIM(a); i++)
933 result *= fabs(UR_COORD(a, i) - LL_COORD(a, i));
934 }
935 *size = result;
936}
937
938/* make up a metric in which one box will be 'lower' than the other
939 -- this can be useful for sorting and to determine uniqueness */
940int32
942{
943 int i;
944 int dim;
945
946 dim = Min(DIM(a), DIM(b));
947
948 /* compare the common dimensions */
949 for (i = 0; i < dim; i++)
950 {
951 if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
952 Min(LL_COORD(b, i), UR_COORD(b, i)))
953 return 1;
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 }
958 for (i = 0; i < dim; i++)
959 {
960 if (Max(LL_COORD(a, i), UR_COORD(a, i)) >
961 Max(LL_COORD(b, i), UR_COORD(b, i)))
962 return 1;
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 }
967
968 /* compare extra dimensions to zero */
969 if (DIM(a) > DIM(b))
970 {
971 for (i = dim; i < DIM(a); i++)
972 {
973 if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
974 return 1;
975 if (Min(LL_COORD(a, i), UR_COORD(a, i)) < 0)
976 return -1;
977 }
978 for (i = dim; i < DIM(a); i++)
979 {
980 if (Max(LL_COORD(a, i), UR_COORD(a, i)) > 0)
981 return 1;
982 if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
983 return -1;
984 }
985
986 /*
987 * if all common dimensions are equal, the cube with more dimensions
988 * wins
989 */
990 return 1;
991 }
992 if (DIM(a) < DIM(b))
993 {
994 for (i = dim; i < DIM(b); i++)
995 {
996 if (Min(LL_COORD(b, i), UR_COORD(b, i)) > 0)
997 return -1;
998 if (Min(LL_COORD(b, i), UR_COORD(b, i)) < 0)
999 return 1;
1000 }
1001 for (i = dim; i < DIM(b); i++)
1002 {
1003 if (Max(LL_COORD(b, i), UR_COORD(b, i)) > 0)
1004 return -1;
1005 if (Max(LL_COORD(b, i), UR_COORD(b, i)) < 0)
1006 return 1;
1007 }
1008
1009 /*
1010 * if all common dimensions are equal, the cube with more dimensions
1011 * wins
1012 */
1013 return -1;
1014 }
1015
1016 /* They're really equal */
1017 return 0;
1018}
1019
1020Datum
1022{
1024 *b = PG_GETARG_NDBOX_P(1);
1025 int32 res;
1026
1027 res = cube_cmp_v0(a, b);
1028
1029 PG_FREE_IF_COPY(a, 0);
1030 PG_FREE_IF_COPY(b, 1);
1031 PG_RETURN_INT32(res);
1032}
1033
1034
1035Datum
1037{
1039 *b = PG_GETARG_NDBOX_P(1);
1040 int32 res;
1041
1042 res = cube_cmp_v0(a, b);
1043
1044 PG_FREE_IF_COPY(a, 0);
1045 PG_FREE_IF_COPY(b, 1);
1046 PG_RETURN_BOOL(res == 0);
1047}
1048
1049
1050Datum
1052{
1054 *b = PG_GETARG_NDBOX_P(1);
1055 int32 res;
1056
1057 res = cube_cmp_v0(a, b);
1058
1059 PG_FREE_IF_COPY(a, 0);
1060 PG_FREE_IF_COPY(b, 1);
1061 PG_RETURN_BOOL(res != 0);
1062}
1063
1064
1065Datum
1067{
1069 *b = PG_GETARG_NDBOX_P(1);
1070 int32 res;
1071
1072 res = cube_cmp_v0(a, b);
1073
1074 PG_FREE_IF_COPY(a, 0);
1075 PG_FREE_IF_COPY(b, 1);
1076 PG_RETURN_BOOL(res < 0);
1077}
1078
1079
1080Datum
1082{
1084 *b = PG_GETARG_NDBOX_P(1);
1085 int32 res;
1086
1087 res = cube_cmp_v0(a, b);
1088
1089 PG_FREE_IF_COPY(a, 0);
1090 PG_FREE_IF_COPY(b, 1);
1091 PG_RETURN_BOOL(res > 0);
1092}
1093
1094
1095Datum
1097{
1099 *b = PG_GETARG_NDBOX_P(1);
1100 int32 res;
1101
1102 res = cube_cmp_v0(a, b);
1103
1104 PG_FREE_IF_COPY(a, 0);
1105 PG_FREE_IF_COPY(b, 1);
1106 PG_RETURN_BOOL(res <= 0);
1107}
1108
1109
1110Datum
1112{
1114 *b = PG_GETARG_NDBOX_P(1);
1115 int32 res;
1116
1117 res = cube_cmp_v0(a, b);
1118
1119 PG_FREE_IF_COPY(a, 0);
1120 PG_FREE_IF_COPY(b, 1);
1121 PG_RETURN_BOOL(res >= 0);
1122}
1123
1124
1125/* Contains */
1126/* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */
1127bool
1129{
1130 int i;
1131
1132 if ((a == NULL) || (b == NULL))
1133 return false;
1134
1135 if (DIM(a) < DIM(b))
1136 {
1137 /*
1138 * the further comparisons will make sense if the excess dimensions of
1139 * (b) were zeroes Since both UL and UR coordinates must be zero, we
1140 * can check them all without worrying about which is which.
1141 */
1142 for (i = DIM(a); i < DIM(b); i++)
1143 {
1144 if (LL_COORD(b, i) != 0)
1145 return false;
1146 if (UR_COORD(b, i) != 0)
1147 return false;
1148 }
1149 }
1150
1151 /* Can't care less about the excess dimensions of (a), if any */
1152 for (i = 0; i < Min(DIM(a), DIM(b)); i++)
1153 {
1154 if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
1155 Min(LL_COORD(b, i), UR_COORD(b, i)))
1156 return false;
1157 if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
1158 Max(LL_COORD(b, i), UR_COORD(b, i)))
1159 return false;
1160 }
1161
1162 return true;
1163}
1164
1165Datum
1167{
1169 *b = PG_GETARG_NDBOX_P(1);
1170 bool res;
1171
1172 res = cube_contains_v0(a, b);
1173
1174 PG_FREE_IF_COPY(a, 0);
1175 PG_FREE_IF_COPY(b, 1);
1176 PG_RETURN_BOOL(res);
1177}
1178
1179/* Contained */
1180/* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */
1181Datum
1183{
1185 *b = PG_GETARG_NDBOX_P(1);
1186 bool res;
1187
1188 res = cube_contains_v0(b, a);
1189
1190 PG_FREE_IF_COPY(a, 0);
1191 PG_FREE_IF_COPY(b, 1);
1192 PG_RETURN_BOOL(res);
1193}
1194
1195/* Overlap */
1196/* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */
1197bool
1199{
1200 int i;
1201
1202 if ((a == NULL) || (b == NULL))
1203 return false;
1204
1205 /* swap the box pointers if needed */
1206 if (DIM(a) < DIM(b))
1207 {
1208 NDBOX *tmp = b;
1209
1210 b = a;
1211 a = tmp;
1212 }
1213
1214 /* compare within the dimensions of (b) */
1215 for (i = 0; i < DIM(b); i++)
1216 {
1217 if (Min(LL_COORD(a, i), UR_COORD(a, i)) > Max(LL_COORD(b, i), UR_COORD(b, i)))
1218 return false;
1219 if (Max(LL_COORD(a, i), UR_COORD(a, i)) < Min(LL_COORD(b, i), UR_COORD(b, i)))
1220 return false;
1221 }
1222
1223 /* compare to zero those dimensions in (a) absent in (b) */
1224 for (i = DIM(b); i < DIM(a); i++)
1225 {
1226 if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
1227 return false;
1228 if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
1229 return false;
1230 }
1231
1232 return true;
1233}
1234
1235
1236Datum
1238{
1240 *b = PG_GETARG_NDBOX_P(1);
1241 bool res;
1242
1243 res = cube_overlap_v0(a, b);
1244
1245 PG_FREE_IF_COPY(a, 0);
1246 PG_FREE_IF_COPY(b, 1);
1247 PG_RETURN_BOOL(res);
1248}
1249
1250
1251/* Distance */
1252/* The distance is computed as a per axis sum of the squared distances
1253 between 1D projections of the boxes onto Cartesian axes. Assuming zero
1254 distance between overlapping projections, this metric coincides with the
1255 "common sense" geometric distance */
1256Datum
1258{
1260 *b = PG_GETARG_NDBOX_P(1);
1261 bool swapped = false;
1262 double d,
1263 distance;
1264 int i;
1265
1266 /* swap the box pointers if needed */
1267 if (DIM(a) < DIM(b))
1268 {
1269 NDBOX *tmp = b;
1270
1271 b = a;
1272 a = tmp;
1273 swapped = true;
1274 }
1275
1276 distance = 0.0;
1277 /* compute within the dimensions of (b) */
1278 for (i = 0; i < DIM(b); i++)
1279 {
1280 d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), LL_COORD(b, i), UR_COORD(b, i));
1281 distance += d * d;
1282 }
1283
1284 /* compute distance to zero for those dimensions in (a) absent in (b) */
1285 for (i = DIM(b); i < DIM(a); i++)
1286 {
1287 d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0);
1288 distance += d * d;
1289 }
1290
1291 if (swapped)
1292 {
1293 PG_FREE_IF_COPY(b, 0);
1294 PG_FREE_IF_COPY(a, 1);
1295 }
1296 else
1297 {
1298 PG_FREE_IF_COPY(a, 0);
1299 PG_FREE_IF_COPY(b, 1);
1300 }
1301
1302 PG_RETURN_FLOAT8(sqrt(distance));
1303}
1304
1305Datum
1307{
1309 *b = PG_GETARG_NDBOX_P(1);
1310 bool swapped = false;
1311 double distance;
1312 int i;
1313
1314 /* swap the box pointers if needed */
1315 if (DIM(a) < DIM(b))
1316 {
1317 NDBOX *tmp = b;
1318
1319 b = a;
1320 a = tmp;
1321 swapped = true;
1322 }
1323
1324 distance = 0.0;
1325 /* compute within the dimensions of (b) */
1326 for (i = 0; i < DIM(b); i++)
1327 distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1328 LL_COORD(b, i), UR_COORD(b, i)));
1329
1330 /* compute distance to zero for those dimensions in (a) absent in (b) */
1331 for (i = DIM(b); i < DIM(a); i++)
1332 distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1333 0.0, 0.0));
1334
1335 if (swapped)
1336 {
1337 PG_FREE_IF_COPY(b, 0);
1338 PG_FREE_IF_COPY(a, 1);
1339 }
1340 else
1341 {
1342 PG_FREE_IF_COPY(a, 0);
1343 PG_FREE_IF_COPY(b, 1);
1344 }
1345
1346 PG_RETURN_FLOAT8(distance);
1347}
1348
1349Datum
1351{
1353 *b = PG_GETARG_NDBOX_P(1);
1354 bool swapped = false;
1355 double d,
1356 distance;
1357 int i;
1358
1359 /* swap the box pointers if needed */
1360 if (DIM(a) < DIM(b))
1361 {
1362 NDBOX *tmp = b;
1363
1364 b = a;
1365 a = tmp;
1366 swapped = true;
1367 }
1368
1369 distance = 0.0;
1370 /* compute within the dimensions of (b) */
1371 for (i = 0; i < DIM(b); i++)
1372 {
1373 d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1374 LL_COORD(b, i), UR_COORD(b, i)));
1375 if (d > distance)
1376 distance = d;
1377 }
1378
1379 /* compute distance to zero for those dimensions in (a) absent in (b) */
1380 for (i = DIM(b); i < DIM(a); i++)
1381 {
1382 d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0));
1383 if (d > distance)
1384 distance = d;
1385 }
1386
1387 if (swapped)
1388 {
1389 PG_FREE_IF_COPY(b, 0);
1390 PG_FREE_IF_COPY(a, 1);
1391 }
1392 else
1393 {
1394 PG_FREE_IF_COPY(a, 0);
1395 PG_FREE_IF_COPY(b, 1);
1396 }
1397
1398 PG_RETURN_FLOAT8(distance);
1399}
1400
1401Datum
1403{
1404 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1406 NDBOX *cube = DatumGetNDBOXP(entry->key);
1407 double retval;
1408
1409 if (strategy == CubeKNNDistanceCoord)
1410 {
1411 /*
1412 * Handle ordering by ~> operator. See comments of cube_coord_llur()
1413 * for details
1414 */
1415 int coord = PG_GETARG_INT32(1);
1416 bool isLeaf = GistPageIsLeaf(entry->page);
1417 bool inverse = false;
1418
1419 /* 0 is the only unsupported coordinate value */
1420 if (coord == 0)
1421 ereport(ERROR,
1422 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
1423 errmsg("zero cube index is not defined")));
1424
1425 /* Return inversed value for negative coordinate */
1426 if (coord < 0)
1427 {
1428 coord = -coord;
1429 inverse = true;
1430 }
1431
1432 if (coord <= 2 * DIM(cube))
1433 {
1434 /* dimension index */
1435 int index = (coord - 1) / 2;
1436
1437 /* whether this is upper bound (lower bound otherwise) */
1438 bool upper = ((coord - 1) % 2 == 1);
1439
1440 if (IS_POINT(cube))
1441 {
1442 retval = cube->x[index];
1443 }
1444 else
1445 {
1446 if (isLeaf)
1447 {
1448 /* For leaf just return required upper/lower bound */
1449 if (upper)
1450 retval = Max(cube->x[index], cube->x[index + DIM(cube)]);
1451 else
1452 retval = Min(cube->x[index], cube->x[index + DIM(cube)]);
1453 }
1454 else
1455 {
1456 /*
1457 * For non-leaf we should always return lower bound,
1458 * because even upper bound of a child in the subtree can
1459 * be as small as our lower bound. For inversed case we
1460 * return upper bound because it becomes lower bound for
1461 * inversed value.
1462 */
1463 if (!inverse)
1464 retval = Min(cube->x[index], cube->x[index + DIM(cube)]);
1465 else
1466 retval = Max(cube->x[index], cube->x[index + DIM(cube)]);
1467 }
1468 }
1469 }
1470 else
1471 {
1472 retval = 0.0;
1473 }
1474
1475 /* Inverse return value if needed */
1476 if (inverse)
1477 retval = -retval;
1478 }
1479 else
1480 {
1481 NDBOX *query = PG_GETARG_NDBOX_P(1);
1482
1483 switch (strategy)
1484 {
1487 PointerGetDatum(cube), PointerGetDatum(query)));
1488 break;
1491 PointerGetDatum(cube), PointerGetDatum(query)));
1492 break;
1495 PointerGetDatum(cube), PointerGetDatum(query)));
1496 break;
1497 default:
1498 elog(ERROR, "unrecognized cube strategy number: %d", strategy);
1499 retval = 0; /* keep compiler quiet */
1500 break;
1501 }
1502 }
1503 PG_RETURN_FLOAT8(retval);
1504}
1505
1506static double
1507distance_1D(double a1, double a2, double b1, double b2)
1508{
1509 /* interval (a) is entirely on the left of (b) */
1510 if ((a1 <= b1) && (a2 <= b1) && (a1 <= b2) && (a2 <= b2))
1511 return (Min(b1, b2) - Max(a1, a2));
1512
1513 /* interval (a) is entirely on the right of (b) */
1514 if ((a1 > b1) && (a2 > b1) && (a1 > b2) && (a2 > b2))
1515 return (Min(a1, a2) - Max(b1, b2));
1516
1517 /* the rest are all sorts of intersections */
1518 return 0.0;
1519}
1520
1521/* Test if a box is also a point */
1522Datum
1524{
1525 NDBOX *cube = PG_GETARG_NDBOX_P(0);
1526 bool result;
1527
1528 result = cube_is_point_internal(cube);
1529 PG_FREE_IF_COPY(cube, 0);
1530 PG_RETURN_BOOL(result);
1531}
1532
1533static bool
1535{
1536 int i;
1537
1538 if (IS_POINT(cube))
1539 return true;
1540
1541 /*
1542 * Even if the point-flag is not set, all the lower-left coordinates might
1543 * match the upper-right coordinates, so that the value is in fact a
1544 * point. Such values don't arise with current code - the point flag is
1545 * always set if appropriate - but they might be present on-disk in
1546 * clusters upgraded from pre-9.4 versions.
1547 */
1548 for (i = 0; i < DIM(cube); i++)
1549 {
1550 if (LL_COORD(cube, i) != UR_COORD(cube, i))
1551 return false;
1552 }
1553 return true;
1554}
1555
1556/* Return dimensions in use in the data structure */
1557Datum
1559{
1561 int dim = DIM(c);
1562
1563 PG_FREE_IF_COPY(c, 0);
1564 PG_RETURN_INT32(dim);
1565}
1566
1567/* Return a specific normalized LL coordinate */
1568Datum
1570{
1572 int n = PG_GETARG_INT32(1);
1573 double result;
1574
1575 if (DIM(c) >= n && n > 0)
1576 result = Min(LL_COORD(c, n - 1), UR_COORD(c, n - 1));
1577 else
1578 result = 0;
1579
1580 PG_FREE_IF_COPY(c, 0);
1581 PG_RETURN_FLOAT8(result);
1582}
1583
1584/* Return a specific normalized UR coordinate */
1585Datum
1587{
1589 int n = PG_GETARG_INT32(1);
1590 double result;
1591
1592 if (DIM(c) >= n && n > 0)
1593 result = Max(LL_COORD(c, n - 1), UR_COORD(c, n - 1));
1594 else
1595 result = 0;
1596
1597 PG_FREE_IF_COPY(c, 0);
1598 PG_RETURN_FLOAT8(result);
1599}
1600
1601/*
1602 * Function returns cube coordinate.
1603 * Numbers from 1 to DIM denotes first corner coordinates.
1604 * Numbers from DIM+1 to 2*DIM denotes second corner coordinates.
1605 */
1606Datum
1608{
1609 NDBOX *cube = PG_GETARG_NDBOX_P(0);
1610 int coord = PG_GETARG_INT32(1);
1611
1612 if (coord <= 0 || coord > 2 * DIM(cube))
1613 ereport(ERROR,
1614 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
1615 errmsg("cube index %d is out of bounds", coord)));
1616
1617 if (IS_POINT(cube))
1618 PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]);
1619 else
1620 PG_RETURN_FLOAT8(cube->x[coord - 1]);
1621}
1622
1623
1624/*----
1625 * This function works like cube_coord(), but rearranges coordinates in the
1626 * way suitable to support coordinate ordering using KNN-GiST. For historical
1627 * reasons this extension allows us to create cubes in form ((2,1),(1,2)) and
1628 * instead of normalizing such cube to ((1,1),(2,2)) it stores cube in original
1629 * way. But in order to get cubes ordered by one of dimensions from the index
1630 * without explicit sort step we need this representation-independent coordinate
1631 * getter. Moreover, indexed dataset may contain cubes of different dimensions
1632 * number. Accordingly, this coordinate getter should be able to return
1633 * lower/upper bound for particular dimension independently on number of cube
1634 * dimensions. Also, KNN-GiST supports only ascending sorting. In order to
1635 * support descending sorting, this function returns inverse of value when
1636 * negative coordinate is given.
1637 *
1638 * Long story short, this function uses following meaning of coordinates:
1639 * # (2 * N - 1) -- lower bound of Nth dimension,
1640 * # (2 * N) -- upper bound of Nth dimension,
1641 * # - (2 * N - 1) -- negative of lower bound of Nth dimension,
1642 * # - (2 * N) -- negative of upper bound of Nth dimension.
1643 *
1644 * When given coordinate exceeds number of cube dimensions, then 0 returned
1645 * (reproducing logic of GiST indexing of variable-length cubes).
1646 */
1647Datum
1649{
1650 NDBOX *cube = PG_GETARG_NDBOX_P(0);
1651 int coord = PG_GETARG_INT32(1);
1652 bool inverse = false;
1653 float8 result;
1654
1655 /* 0 is the only unsupported coordinate value */
1656 if (coord == 0)
1657 ereport(ERROR,
1658 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
1659 errmsg("zero cube index is not defined")));
1660
1661 /* Return inversed value for negative coordinate */
1662 if (coord < 0)
1663 {
1664 coord = -coord;
1665 inverse = true;
1666 }
1667
1668 if (coord <= 2 * DIM(cube))
1669 {
1670 /* dimension index */
1671 int index = (coord - 1) / 2;
1672
1673 /* whether this is upper bound (lower bound otherwise) */
1674 bool upper = ((coord - 1) % 2 == 1);
1675
1676 if (IS_POINT(cube))
1677 {
1678 result = cube->x[index];
1679 }
1680 else
1681 {
1682 if (upper)
1683 result = Max(cube->x[index], cube->x[index + DIM(cube)]);
1684 else
1685 result = Min(cube->x[index], cube->x[index + DIM(cube)]);
1686 }
1687 }
1688 else
1689 {
1690 /*
1691 * Return zero if coordinate is out of bound. That reproduces logic
1692 * of how cubes with low dimension number are expanded during GiST
1693 * indexing.
1694 */
1695 result = 0.0;
1696 }
1697
1698 /* Inverse value if needed */
1699 if (inverse)
1700 result = -result;
1701
1702 PG_RETURN_FLOAT8(result);
1703}
1704
1705/* Increase or decrease box size by a radius in at least n dimensions. */
1706Datum
1708{
1710 double r = PG_GETARG_FLOAT8(1);
1711 int32 n = PG_GETARG_INT32(2);
1712 NDBOX *result;
1713 int dim = 0;
1714 int size;
1715 int i,
1716 j;
1717
1718 if (n > CUBE_MAX_DIM)
1719 n = CUBE_MAX_DIM;
1720 if (r > 0 && n > 0)
1721 dim = n;
1722 if (DIM(a) > dim)
1723 dim = DIM(a);
1724
1725 size = CUBE_SIZE(dim);
1726 result = (NDBOX *) palloc0(size);
1727 SET_VARSIZE(result, size);
1728 SET_DIM(result, dim);
1729
1730 for (i = 0, j = dim; i < DIM(a); i++, j++)
1731 {
1732 if (LL_COORD(a, i) >= UR_COORD(a, i))
1733 {
1734 result->x[i] = UR_COORD(a, i) - r;
1735 result->x[j] = LL_COORD(a, i) + r;
1736 }
1737 else
1738 {
1739 result->x[i] = LL_COORD(a, i) - r;
1740 result->x[j] = UR_COORD(a, i) + r;
1741 }
1742 if (result->x[i] > result->x[j])
1743 {
1744 result->x[i] = (result->x[i] + result->x[j]) / 2;
1745 result->x[j] = result->x[i];
1746 }
1747 }
1748 /* dim > a->dim only if r > 0 */
1749 for (; i < dim; i++, j++)
1750 {
1751 result->x[i] = -r;
1752 result->x[j] = r;
1753 }
1754
1755 /*
1756 * Check if the result was in fact a point, and set the flag in the datum
1757 * accordingly. (we don't bother to repalloc it smaller)
1758 */
1759 if (cube_is_point_internal(result))
1760 {
1761 size = POINT_SIZE(dim);
1762 SET_VARSIZE(result, size);
1763 SET_POINT_BIT(result);
1764 }
1765
1766 PG_FREE_IF_COPY(a, 0);
1767 PG_RETURN_NDBOX_P(result);
1768}
1769
1770/* Create a one dimensional box with identical upper and lower coordinates */
1771Datum
1773{
1774 double x = PG_GETARG_FLOAT8(0);
1775 NDBOX *result;
1776 int size;
1777
1778 size = POINT_SIZE(1);
1779 result = (NDBOX *) palloc0(size);
1780 SET_VARSIZE(result, size);
1781 SET_DIM(result, 1);
1782 SET_POINT_BIT(result);
1783 result->x[0] = x;
1784
1785 PG_RETURN_NDBOX_P(result);
1786}
1787
1788/* Create a one dimensional box */
1789Datum
1791{
1792 double x0 = PG_GETARG_FLOAT8(0);
1793 double x1 = PG_GETARG_FLOAT8(1);
1794 NDBOX *result;
1795 int size;
1796
1797 if (x0 == x1)
1798 {
1799 size = POINT_SIZE(1);
1800 result = (NDBOX *) palloc0(size);
1801 SET_VARSIZE(result, size);
1802 SET_DIM(result, 1);
1803 SET_POINT_BIT(result);
1804 result->x[0] = x0;
1805 }
1806 else
1807 {
1808 size = CUBE_SIZE(1);
1809 result = (NDBOX *) palloc0(size);
1810 SET_VARSIZE(result, size);
1811 SET_DIM(result, 1);
1812 result->x[0] = x0;
1813 result->x[1] = x1;
1814 }
1815
1816 PG_RETURN_NDBOX_P(result);
1817}
1818
1819/* Add a dimension to an existing cube with the same values for the new
1820 coordinate */
1821Datum
1823{
1824 NDBOX *cube = PG_GETARG_NDBOX_P(0);
1825 double x = PG_GETARG_FLOAT8(1);
1826 NDBOX *result;
1827 int size;
1828 int i;
1829
1830 if (DIM(cube) + 1 > CUBE_MAX_DIM)
1831 ereport(ERROR,
1832 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1833 errmsg("can't extend cube"),
1834 errdetail("A cube cannot have more than %d dimensions.",
1835 CUBE_MAX_DIM)));
1836
1837 if (IS_POINT(cube))
1838 {
1839 size = POINT_SIZE((DIM(cube) + 1));
1840 result = (NDBOX *) palloc0(size);
1841 SET_VARSIZE(result, size);
1842 SET_DIM(result, DIM(cube) + 1);
1843 SET_POINT_BIT(result);
1844 for (i = 0; i < DIM(cube); i++)
1845 result->x[i] = cube->x[i];
1846 result->x[DIM(result) - 1] = x;
1847 }
1848 else
1849 {
1850 size = CUBE_SIZE((DIM(cube) + 1));
1851 result = (NDBOX *) palloc0(size);
1852 SET_VARSIZE(result, size);
1853 SET_DIM(result, DIM(cube) + 1);
1854 for (i = 0; i < DIM(cube); i++)
1855 {
1856 result->x[i] = cube->x[i];
1857 result->x[DIM(result) + i] = cube->x[DIM(cube) + i];
1858 }
1859 result->x[DIM(result) - 1] = x;
1860 result->x[2 * DIM(result) - 1] = x;
1861 }
1862
1863 PG_FREE_IF_COPY(cube, 0);
1864 PG_RETURN_NDBOX_P(result);
1865}
1866
1867/* Add a dimension to an existing cube */
1868Datum
1870{
1871 NDBOX *cube = PG_GETARG_NDBOX_P(0);
1872 double x1 = PG_GETARG_FLOAT8(1);
1873 double x2 = PG_GETARG_FLOAT8(2);
1874 NDBOX *result;
1875 int size;
1876 int i;
1877
1878 if (DIM(cube) + 1 > CUBE_MAX_DIM)
1879 ereport(ERROR,
1880 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1881 errmsg("can't extend cube"),
1882 errdetail("A cube cannot have more than %d dimensions.",
1883 CUBE_MAX_DIM)));
1884
1885 if (IS_POINT(cube) && (x1 == x2))
1886 {
1887 size = POINT_SIZE((DIM(cube) + 1));
1888 result = (NDBOX *) palloc0(size);
1889 SET_VARSIZE(result, size);
1890 SET_DIM(result, DIM(cube) + 1);
1891 SET_POINT_BIT(result);
1892 for (i = 0; i < DIM(cube); i++)
1893 result->x[i] = cube->x[i];
1894 result->x[DIM(result) - 1] = x1;
1895 }
1896 else
1897 {
1898 size = CUBE_SIZE((DIM(cube) + 1));
1899 result = (NDBOX *) palloc0(size);
1900 SET_VARSIZE(result, size);
1901 SET_DIM(result, DIM(cube) + 1);
1902 for (i = 0; i < DIM(cube); i++)
1903 {
1904 result->x[i] = LL_COORD(cube, i);
1905 result->x[DIM(result) + i] = UR_COORD(cube, i);
1906 }
1907 result->x[DIM(result) - 1] = x1;
1908 result->x[2 * DIM(result) - 1] = x2;
1909 }
1910
1911 PG_FREE_IF_COPY(cube, 0);
1912 PG_RETURN_NDBOX_P(result);
1913}
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(ArrayType *array)
Definition: arrayfuncs.c:3767
#define Min(x, y)
Definition: c.h:975
#define Max(x, y)
Definition: c.h:969
double float8
Definition: c.h:601
int32_t int32
Definition: c.h:498
size_t Size
Definition: c.h:576
Datum cube_gt(PG_FUNCTION_ARGS)
Definition: cube.c:1081
Datum cube_eq(PG_FUNCTION_ARGS)
Definition: cube.c:1036
Datum cube_le(PG_FUNCTION_ARGS)
Definition: cube.c:1096
Datum cube_coord(PG_FUNCTION_ARGS)
Definition: cube.c:1607
Datum distance_taxicab(PG_FUNCTION_ARGS)
Definition: cube.c:1306
Datum cube_ll_coord(PG_FUNCTION_ARGS)
Definition: cube.c:1569
Datum cube_subset(PG_FUNCTION_ARGS)
Definition: cube.c:247
Datum cube_distance(PG_FUNCTION_ARGS)
Definition: cube.c:1257
static bool cube_is_point_internal(NDBOX *cube)
Definition: cube.c:1534
bool cube_overlap_v0(NDBOX *a, NDBOX *b)
Definition: cube.c:1198
bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy)
Definition: cube.c:683
bool cube_contains_v0(NDBOX *a, NDBOX *b)
Definition: cube.c:1128
Datum distance_chebyshev(PG_FUNCTION_ARGS)
Definition: cube.c:1350
Datum g_cube_picksplit(PG_FUNCTION_ARGS)
Definition: cube.c:515
int32 cube_cmp_v0(NDBOX *a, NDBOX *b)
Definition: cube.c:941
Datum cube_dim(PG_FUNCTION_ARGS)
Definition: cube.c:1558
Datum g_cube_union(PG_FUNCTION_ARGS)
Definition: cube.c:429
Datum cube_in(PG_FUNCTION_ARGS)
Definition: cube.c:121
Datum cube_enlarge(PG_FUNCTION_ARGS)
Definition: cube.c:1707
Datum cube_c_f8(PG_FUNCTION_ARGS)
Definition: cube.c:1822
#define ARRNELEMS(x)
Definition: cube.c:29
Datum g_cube_same(PG_FUNCTION_ARGS)
Definition: cube.c:665
Datum cube_ur_coord(PG_FUNCTION_ARGS)
Definition: cube.c:1586
Datum g_cube_distance(PG_FUNCTION_ARGS)
Definition: cube.c:1402
Datum cube_contained(PG_FUNCTION_ARGS)
Definition: cube.c:1182
Datum cube_cmp(PG_FUNCTION_ARGS)
Definition: cube.c:1021
Datum cube_a_f8_f8(PG_FUNCTION_ARGS)
Definition: cube.c:143
#define ARRPTR(x)
Definition: cube.c:28
PG_MODULE_MAGIC_EXT(.name="cube",.version=PG_VERSION)
Datum g_cube_consistent(PG_FUNCTION_ARGS)
Definition: cube.c:395
NDBOX * cube_union_v0(NDBOX *a, NDBOX *b)
Definition: cube.c:752
static double distance_1D(double a1, double a2, double b1, double b2)
Definition: cube.c:1507
Datum cube_size(PG_FUNCTION_ARGS)
Definition: cube.c:903
Datum cube_recv(PG_FUNCTION_ARGS)
Definition: cube.c:356
void rt_cube_size(NDBOX *a, double *size)
Definition: cube.c:914
Datum cube_lt(PG_FUNCTION_ARGS)
Definition: cube.c:1066
Datum cube_contains(PG_FUNCTION_ARGS)
Definition: cube.c:1166
Datum cube_union(PG_FUNCTION_ARGS)
Definition: cube.c:812
Datum cube_f8_f8(PG_FUNCTION_ARGS)
Definition: cube.c:1790
Datum g_cube_decompress(PG_FUNCTION_ARGS)
Definition: cube.c:467
Datum cube_f8(PG_FUNCTION_ARGS)
Definition: cube.c:1772
Datum cube_a_f8(PG_FUNCTION_ARGS)
Definition: cube.c:210
Datum cube_c_f8_f8(PG_FUNCTION_ARGS)
Definition: cube.c:1869
Datum cube_coord_llur(PG_FUNCTION_ARGS)
Definition: cube.c:1648
Datum cube_inter(PG_FUNCTION_ARGS)
Definition: cube.c:827
Datum g_cube_compress(PG_FUNCTION_ARGS)
Definition: cube.c:461
PG_FUNCTION_INFO_V1(cube_in)
Datum cube_is_point(PG_FUNCTION_ARGS)
Definition: cube.c:1523
bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy)
Definition: cube.c:712
NDBOX * g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
Definition: cube.c:739
Datum cube_send(PG_FUNCTION_ARGS)
Definition: cube.c:334
Datum cube_overlap(PG_FUNCTION_ARGS)
Definition: cube.c:1237
Datum cube_ge(PG_FUNCTION_ARGS)
Definition: cube.c:1111
Datum cube_out(PG_FUNCTION_ARGS)
Definition: cube.c:296
Datum g_cube_penalty(PG_FUNCTION_ARGS)
Definition: cube.c:490
Datum cube_ne(PG_FUNCTION_ARGS)
Definition: cube.c:1051
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:67
#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:1204
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:149
char * float8out_internal(double num)
Definition: float.c:537
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:684
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:282
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:367
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_GETARG_UINT16(n)
Definition: fmgr.h:272
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#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
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:2167
void * palloc0(Size size)
Definition: mcxt.c:1970
void * palloc(Size size)
Definition: mcxt.c:1940
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:80
static char * buf
Definition: pg_test_fsync.c:72
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static float8 DatumGetFloat8(Datum X)
Definition: postgres.h:499
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
float8 pq_getmsgfloat8(StringInfo msg)
Definition: pqformat.c:488
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:326
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:346
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
#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
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
StringInfoData * StringInfo
Definition: stringinfo.h:54
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
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:237
int32 n
Definition: gist.h:236
Definition: cubedata.h:10
double x[FLEXIBLE_ARRAY_MEMBER]
Definition: cubedata.h:33
unsigned int header
Definition: cubedata.h:27
Definition: type.h:96
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
#define VARSIZE(PTR)
Definition: varatt.h:279
const char * name