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