PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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 <float.h>
12 #include <math.h>
13 
14 #include "access/gist.h"
15 #include "access/stratnum.h"
16 #include "utils/array.h"
17 #include "utils/builtins.h"
18 
19 #include "cubedata.h"
20 
22 
23 /*
24  * Taken from the intarray contrib header
25  */
26 #define ARRPTR(x) ( (double *) ARR_DATA_PTR(x) )
27 #define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
28 
29 /*
30 ** Input/Output routines
31 */
46 
47 /*
48 ** GiST support methods
49 */
50 
59 
60 /*
61 ** B-tree support functions
62 */
70 
71 /*
72 ** R-tree support functions
73 */
74 
81 
82 /*
83 ** miscellaneous
84 */
90 
91 /*
92 ** For internal use only
93 */
95 bool cube_contains_v0(NDBOX *a, NDBOX *b);
96 bool cube_overlap_v0(NDBOX *a, NDBOX *b);
98 void rt_cube_size(NDBOX *a, double *sz);
99 NDBOX *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep);
100 bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy);
101 bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy);
102 
103 /*
104 ** Auxiliary funxtions
105 */
106 static double distance_1D(double a1, double a2, double b1, double b2);
107 static bool cube_is_point_internal(NDBOX *cube);
108 
109 
110 /*****************************************************************************
111  * Input/Output functions
112  *****************************************************************************/
113 
114 /* NdBox = [(lowerleft),(upperright)] */
115 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
116 Datum
118 {
119  char *str = PG_GETARG_CSTRING(0);
120  NDBOX *result;
121 
122  cube_scanner_init(str);
123 
124  if (cube_yyparse(&result) != 0)
125  cube_yyerror(&result, "cube parser failed");
126 
128 
129  PG_RETURN_NDBOX(result);
130 }
131 
132 
133 /*
134 ** Allows the construction of a cube from 2 float[]'s
135 */
136 Datum
138 {
141  NDBOX *result;
142  int i;
143  int dim;
144  int size;
145  bool point;
146  double *dur,
147  *dll;
148 
150  ereport(ERROR,
151  (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
152  errmsg("cannot work with arrays containing NULLs")));
153 
154  dim = ARRNELEMS(ur);
155  if (ARRNELEMS(ll) != dim)
156  ereport(ERROR,
157  (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
158  errmsg("UR and LL arrays must be of same length")));
159 
160  dur = ARRPTR(ur);
161  dll = ARRPTR(ll);
162 
163  /* Check if it's a point */
164  point = true;
165  for (i = 0; i < dim; i++)
166  {
167  if (dur[i] != dll[i])
168  {
169  point = false;
170  break;
171  }
172  }
173 
174  size = point ? POINT_SIZE(dim) : CUBE_SIZE(dim);
175  result = (NDBOX *) palloc0(size);
176  SET_VARSIZE(result, size);
177  SET_DIM(result, dim);
178 
179  for (i = 0; i < dim; i++)
180  result->x[i] = dur[i];
181 
182  if (!point)
183  {
184  for (i = 0; i < dim; i++)
185  result->x[i + dim] = dll[i];
186  }
187  else
188  SET_POINT_BIT(result);
189 
190  PG_RETURN_NDBOX(result);
191 }
192 
193 /*
194 ** Allows the construction of a zero-volume cube from a float[]
195 */
196 Datum
198 {
200  NDBOX *result;
201  int i;
202  int dim;
203  int size;
204  double *dur;
205 
206  if (array_contains_nulls(ur))
207  ereport(ERROR,
208  (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
209  errmsg("cannot work with arrays containing NULLs")));
210 
211  dim = ARRNELEMS(ur);
212 
213  dur = ARRPTR(ur);
214 
215  size = POINT_SIZE(dim);
216  result = (NDBOX *) palloc0(size);
217  SET_VARSIZE(result, size);
218  SET_DIM(result, dim);
219  SET_POINT_BIT(result);
220 
221  for (i = 0; i < dim; i++)
222  result->x[i] = dur[i];
223 
224  PG_RETURN_NDBOX(result);
225 }
226 
227 Datum
229 {
230  NDBOX *c = PG_GETARG_NDBOX(0);
232  NDBOX *result;
233  int size,
234  dim,
235  i;
236  int *dx;
237 
238  if (array_contains_nulls(idx))
239  ereport(ERROR,
240  (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
241  errmsg("cannot work with arrays containing NULLs")));
242 
243  dx = (int32 *) ARR_DATA_PTR(idx);
244 
245  dim = ARRNELEMS(idx);
246  size = IS_POINT(c) ? POINT_SIZE(dim) : CUBE_SIZE(dim);
247  result = (NDBOX *) palloc0(size);
248  SET_VARSIZE(result, size);
249  SET_DIM(result, dim);
250 
251  if (IS_POINT(c))
252  SET_POINT_BIT(result);
253 
254  for (i = 0; i < dim; i++)
255  {
256  if ((dx[i] <= 0) || (dx[i] > DIM(c)))
257  ereport(ERROR,
258  (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
259  errmsg("Index out of bounds")));
260  result->x[i] = c->x[dx[i] - 1];
261  if (!IS_POINT(c))
262  result->x[i + dim] = c->x[dx[i] + DIM(c) - 1];
263  }
264 
265  PG_FREE_IF_COPY(c, 0);
266  PG_RETURN_NDBOX(result);
267 }
268 
269 Datum
271 {
272  NDBOX *cube = PG_GETARG_NDBOX(0);
274  int dim = DIM(cube);
275  int i;
276 
277  initStringInfo(&buf);
278 
279  appendStringInfoChar(&buf, '(');
280  for (i = 0; i < dim; i++)
281  {
282  if (i > 0)
283  appendStringInfoString(&buf, ", ");
285  }
286  appendStringInfoChar(&buf, ')');
287 
288  if (!cube_is_point_internal(cube))
289  {
290  appendStringInfoString(&buf, ",(");
291  for (i = 0; i < dim; i++)
292  {
293  if (i > 0)
294  appendStringInfoString(&buf, ", ");
296  }
297  appendStringInfoChar(&buf, ')');
298  }
299 
300  PG_FREE_IF_COPY(cube, 0);
301  PG_RETURN_CSTRING(buf.data);
302 }
303 
304 
305 /*****************************************************************************
306  * GiST functions
307  *****************************************************************************/
308 
309 /*
310 ** The GiST Consistent method for boxes
311 ** Should return false if for all data items x below entry,
312 ** the predicate x op query == FALSE, where op is the oper
313 ** corresponding to strategy in the pg_amop table.
314 */
315 Datum
317 {
318  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
319  NDBOX *query = PG_GETARG_NDBOX(1);
321 
322  /* Oid subtype = PG_GETARG_OID(3); */
323  bool *recheck = (bool *) PG_GETARG_POINTER(4);
324  bool res;
325 
326  /* All cases served by this function are exact */
327  *recheck = false;
328 
329  /*
330  * if entry is not leaf, use g_cube_internal_consistent, else use
331  * g_cube_leaf_consistent
332  */
333  if (GIST_LEAF(entry))
335  query, strategy);
336  else
338  query, strategy);
339 
340  PG_FREE_IF_COPY(query, 1);
341  PG_RETURN_BOOL(res);
342 }
343 
344 
345 /*
346 ** The GiST Union method for boxes
347 ** returns the minimal bounding box that encloses all the entries in entryvec
348 */
349 Datum
351 {
353  int *sizep = (int *) PG_GETARG_POINTER(1);
354  NDBOX *out = (NDBOX *) NULL;
355  NDBOX *tmp;
356  int i;
357 
358  tmp = DatumGetNDBOX(entryvec->vector[0].key);
359 
360  /*
361  * sizep = sizeof(NDBOX); -- NDBOX has variable size
362  */
363  *sizep = VARSIZE(tmp);
364 
365  for (i = 1; i < entryvec->n; i++)
366  {
367  out = g_cube_binary_union(tmp,
368  DatumGetNDBOX(entryvec->vector[i].key),
369  sizep);
370  tmp = out;
371  }
372 
373  PG_RETURN_POINTER(out);
374 }
375 
376 /*
377 ** GiST Compress and Decompress methods for boxes
378 ** do not do anything.
379 */
380 
381 Datum
383 {
385 }
386 
387 Datum
389 {
390  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
391  NDBOX *key = DatumGetNDBOX(PG_DETOAST_DATUM(entry->key));
392 
393  if (key != DatumGetNDBOX(entry->key))
394  {
395  GISTENTRY *retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
396 
397  gistentryinit(*retval, PointerGetDatum(key),
398  entry->rel, entry->page,
399  entry->offset, FALSE);
400  PG_RETURN_POINTER(retval);
401  }
402  PG_RETURN_POINTER(entry);
403 }
404 
405 
406 /*
407 ** The GiST Penalty method for boxes
408 ** As in the R-tree paper, we use change in area as our penalty metric
409 */
410 Datum
412 {
413  GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
414  GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
415  float *result = (float *) PG_GETARG_POINTER(2);
416  NDBOX *ud;
417  double tmp1,
418  tmp2;
419 
420  ud = cube_union_v0(DatumGetNDBOX(origentry->key),
421  DatumGetNDBOX(newentry->key));
422  rt_cube_size(ud, &tmp1);
423  rt_cube_size(DatumGetNDBOX(origentry->key), &tmp2);
424  *result = (float) (tmp1 - tmp2);
425 
426  PG_RETURN_FLOAT8(*result);
427 }
428 
429 
430 
431 /*
432 ** The GiST PickSplit method for boxes
433 ** We use Guttman's poly time split algorithm
434 */
435 Datum
437 {
440  OffsetNumber i,
441  j;
442  NDBOX *datum_alpha,
443  *datum_beta;
444  NDBOX *datum_l,
445  *datum_r;
446  NDBOX *union_d,
447  *union_dl,
448  *union_dr;
449  NDBOX *inter_d;
450  bool firsttime;
451  double size_alpha,
452  size_beta,
453  size_union,
454  size_inter;
455  double size_waste,
456  waste;
457  double size_l,
458  size_r;
459  int nbytes;
460  OffsetNumber seed_1 = 1,
461  seed_2 = 2;
462  OffsetNumber *left,
463  *right;
464  OffsetNumber maxoff;
465 
466  maxoff = entryvec->n - 2;
467  nbytes = (maxoff + 2) * sizeof(OffsetNumber);
468  v->spl_left = (OffsetNumber *) palloc(nbytes);
469  v->spl_right = (OffsetNumber *) palloc(nbytes);
470 
471  firsttime = true;
472  waste = 0.0;
473 
474  for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
475  {
476  datum_alpha = DatumGetNDBOX(entryvec->vector[i].key);
477  for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
478  {
479  datum_beta = DatumGetNDBOX(entryvec->vector[j].key);
480 
481  /* compute the wasted space by unioning these guys */
482  /* size_waste = size_union - size_inter; */
483  union_d = cube_union_v0(datum_alpha, datum_beta);
484  rt_cube_size(union_d, &size_union);
486  entryvec->vector[i].key, entryvec->vector[j].key));
487  rt_cube_size(inter_d, &size_inter);
488  size_waste = size_union - size_inter;
489 
490  /*
491  * are these a more promising split than what we've already seen?
492  */
493 
494  if (size_waste > waste || firsttime)
495  {
496  waste = size_waste;
497  seed_1 = i;
498  seed_2 = j;
499  firsttime = false;
500  }
501  }
502  }
503 
504  left = v->spl_left;
505  v->spl_nleft = 0;
506  right = v->spl_right;
507  v->spl_nright = 0;
508 
509  datum_alpha = DatumGetNDBOX(entryvec->vector[seed_1].key);
510  datum_l = cube_union_v0(datum_alpha, datum_alpha);
511  rt_cube_size(datum_l, &size_l);
512  datum_beta = DatumGetNDBOX(entryvec->vector[seed_2].key);
513  datum_r = cube_union_v0(datum_beta, datum_beta);
514  rt_cube_size(datum_r, &size_r);
515 
516  /*
517  * Now split up the regions between the two seeds. An important property
518  * of this split algorithm is that the split vector v has the indices of
519  * items to be split in order in its left and right vectors. We exploit
520  * this property by doing a merge in the code that actually splits the
521  * page.
522  *
523  * For efficiency, we also place the new index tuple in this loop. This is
524  * handled at the very end, when we have placed all the existing tuples
525  * and i == maxoff + 1.
526  */
527 
528  maxoff = OffsetNumberNext(maxoff);
529  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
530  {
531  /*
532  * If we've already decided where to place this item, just put it on
533  * the right list. Otherwise, we need to figure out which page needs
534  * the least enlargement in order to store the item.
535  */
536 
537  if (i == seed_1)
538  {
539  *left++ = i;
540  v->spl_nleft++;
541  continue;
542  }
543  else if (i == seed_2)
544  {
545  *right++ = i;
546  v->spl_nright++;
547  continue;
548  }
549 
550  /* okay, which page needs least enlargement? */
551  datum_alpha = DatumGetNDBOX(entryvec->vector[i].key);
552  union_dl = cube_union_v0(datum_l, datum_alpha);
553  union_dr = cube_union_v0(datum_r, datum_alpha);
554  rt_cube_size(union_dl, &size_alpha);
555  rt_cube_size(union_dr, &size_beta);
556 
557  /* pick which page to add it to */
558  if (size_alpha - size_l < size_beta - size_r)
559  {
560  datum_l = union_dl;
561  size_l = size_alpha;
562  *left++ = i;
563  v->spl_nleft++;
564  }
565  else
566  {
567  datum_r = union_dr;
568  size_r = size_beta;
569  *right++ = i;
570  v->spl_nright++;
571  }
572  }
573  *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
574 
575  v->spl_ldatum = PointerGetDatum(datum_l);
576  v->spl_rdatum = PointerGetDatum(datum_r);
577 
579 }
580 
581 /*
582 ** Equality method
583 */
584 Datum
586 {
587  NDBOX *b1 = PG_GETARG_NDBOX(0);
588  NDBOX *b2 = PG_GETARG_NDBOX(1);
589  bool *result = (bool *) PG_GETARG_POINTER(2);
590 
591  if (cube_cmp_v0(b1, b2) == 0)
592  *result = TRUE;
593  else
594  *result = FALSE;
595 
596  PG_RETURN_NDBOX(result);
597 }
598 
599 /*
600 ** SUPPORT ROUTINES
601 */
602 bool
604  NDBOX *query,
605  StrategyNumber strategy)
606 {
607  bool retval;
608 
609  switch (strategy)
610  {
612  retval = (bool) cube_overlap_v0(key, query);
613  break;
615  retval = (bool) (cube_cmp_v0(key, query) == 0);
616  break;
619  retval = (bool) cube_contains_v0(key, query);
620  break;
623  retval = (bool) cube_contains_v0(query, key);
624  break;
625  default:
626  retval = FALSE;
627  }
628  return (retval);
629 }
630 
631 bool
633  NDBOX *query,
634  StrategyNumber strategy)
635 {
636  bool retval;
637 
638  switch (strategy)
639  {
641  retval = (bool) cube_overlap_v0(key, query);
642  break;
646  retval = (bool) cube_contains_v0(key, query);
647  break;
650  retval = (bool) cube_overlap_v0(key, query);
651  break;
652  default:
653  retval = FALSE;
654  }
655  return (retval);
656 }
657 
658 NDBOX *
659 g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
660 {
661  NDBOX *retval;
662 
663  retval = cube_union_v0(r1, r2);
664  *sizep = VARSIZE(retval);
665 
666  return (retval);
667 }
668 
669 
670 /* cube_union_v0 */
671 NDBOX *
673 {
674  int i;
675  NDBOX *result;
676  int dim;
677  int size;
678 
679  /* trivial case */
680  if (a == b)
681  return a;
682 
683  /* swap the arguments if needed, so that 'a' is always larger than 'b' */
684  if (DIM(a) < DIM(b))
685  {
686  NDBOX *tmp = b;
687 
688  b = a;
689  a = tmp;
690  }
691  dim = DIM(a);
692 
693  size = CUBE_SIZE(dim);
694  result = palloc0(size);
695  SET_VARSIZE(result, size);
696  SET_DIM(result, dim);
697 
698  /* First compute the union of the dimensions present in both args */
699  for (i = 0; i < DIM(b); i++)
700  {
701  result->x[i] = Min(
702  Min(LL_COORD(a, i), UR_COORD(a, i)),
703  Min(LL_COORD(b, i), UR_COORD(b, i))
704  );
705  result->x[i + DIM(a)] = Max(
706  Max(LL_COORD(a, i), UR_COORD(a, i)),
707  Max(LL_COORD(b, i), UR_COORD(b, i))
708  );
709  }
710  /* continue on the higher dimensions only present in 'a' */
711  for (; i < DIM(a); i++)
712  {
713  result->x[i] = Min(0,
714  Min(LL_COORD(a, i), UR_COORD(a, i))
715  );
716  result->x[i + dim] = Max(0,
717  Max(LL_COORD(a, i), UR_COORD(a, i))
718  );
719  }
720 
721  /*
722  * Check if the result was in fact a point, and set the flag in the datum
723  * accordingly. (we don't bother to repalloc it smaller)
724  */
725  if (cube_is_point_internal(result))
726  {
727  size = POINT_SIZE(dim);
728  SET_VARSIZE(result, size);
729  SET_POINT_BIT(result);
730  }
731 
732  return (result);
733 }
734 
735 Datum
737 {
738  NDBOX *a = PG_GETARG_NDBOX(0);
739  NDBOX *b = PG_GETARG_NDBOX(1);
740  NDBOX *res;
741 
742  res = cube_union_v0(a, b);
743 
744  PG_FREE_IF_COPY(a, 0);
745  PG_FREE_IF_COPY(b, 1);
746  PG_RETURN_NDBOX(res);
747 }
748 
749 /* cube_inter */
750 Datum
752 {
753  NDBOX *a = PG_GETARG_NDBOX(0);
754  NDBOX *b = PG_GETARG_NDBOX(1);
755  NDBOX *result;
756  bool swapped = false;
757  int i;
758  int dim;
759  int size;
760 
761  /* swap the arguments if needed, so that 'a' is always larger than 'b' */
762  if (DIM(a) < DIM(b))
763  {
764  NDBOX *tmp = b;
765 
766  b = a;
767  a = tmp;
768  swapped = true;
769  }
770  dim = DIM(a);
771 
772  size = CUBE_SIZE(dim);
773  result = (NDBOX *) palloc0(size);
774  SET_VARSIZE(result, size);
775  SET_DIM(result, dim);
776 
777  /* First compute intersection of the dimensions present in both args */
778  for (i = 0; i < DIM(b); i++)
779  {
780  result->x[i] = Max(
781  Min(LL_COORD(a, i), UR_COORD(a, i)),
782  Min(LL_COORD(b, i), UR_COORD(b, i))
783  );
784  result->x[i + DIM(a)] = Min(
785  Max(LL_COORD(a, i), UR_COORD(a, i)),
786  Max(LL_COORD(b, i), UR_COORD(b, i))
787  );
788  }
789  /* continue on the higher dimensions only present in 'a' */
790  for (; i < DIM(a); i++)
791  {
792  result->x[i] = Max(0,
793  Min(LL_COORD(a, i), UR_COORD(a, i))
794  );
795  result->x[i + DIM(a)] = Min(0,
796  Max(LL_COORD(a, i), UR_COORD(a, i))
797  );
798  }
799 
800  /*
801  * Check if the result was in fact a point, and set the flag in the datum
802  * accordingly. (we don't bother to repalloc it smaller)
803  */
804  if (cube_is_point_internal(result))
805  {
806  size = POINT_SIZE(dim);
807  result = repalloc(result, size);
808  SET_VARSIZE(result, size);
809  SET_POINT_BIT(result);
810  }
811 
812  if (swapped)
813  {
814  PG_FREE_IF_COPY(b, 0);
815  PG_FREE_IF_COPY(a, 1);
816  }
817  else
818  {
819  PG_FREE_IF_COPY(a, 0);
820  PG_FREE_IF_COPY(b, 1);
821  }
822 
823  /*
824  * Is it OK to return a non-null intersection for non-overlapping boxes?
825  */
826  PG_RETURN_NDBOX(result);
827 }
828 
829 /* cube_size */
830 Datum
832 {
833  NDBOX *a = PG_GETARG_NDBOX(0);
834  double result;
835 
836  rt_cube_size(a, &result);
837  PG_FREE_IF_COPY(a, 0);
838  PG_RETURN_FLOAT8(result);
839 }
840 
841 void
842 rt_cube_size(NDBOX *a, double *size)
843 {
844  double result;
845  int i;
846 
847  if (a == (NDBOX *) NULL)
848  {
849  /* special case for GiST */
850  result = 0.0;
851  }
852  else if (IS_POINT(a) || DIM(a) == 0)
853  {
854  /* necessarily has zero size */
855  result = 0.0;
856  }
857  else
858  {
859  result = 1.0;
860  for (i = 0; i < DIM(a); i++)
861  result *= Abs(UR_COORD(a, i) - LL_COORD(a, i));
862  }
863  *size = result;
864 }
865 
866 /* make up a metric in which one box will be 'lower' than the other
867  -- this can be useful for sorting and to determine uniqueness */
868 int32
870 {
871  int i;
872  int dim;
873 
874  dim = Min(DIM(a), DIM(b));
875 
876  /* compare the common dimensions */
877  for (i = 0; i < dim; i++)
878  {
879  if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
880  Min(LL_COORD(b, i), UR_COORD(b, i)))
881  return 1;
882  if (Min(LL_COORD(a, i), UR_COORD(a, i)) <
883  Min(LL_COORD(b, i), UR_COORD(b, i)))
884  return -1;
885  }
886  for (i = 0; i < dim; i++)
887  {
888  if (Max(LL_COORD(a, i), UR_COORD(a, i)) >
889  Max(LL_COORD(b, i), UR_COORD(b, i)))
890  return 1;
891  if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
892  Max(LL_COORD(b, i), UR_COORD(b, i)))
893  return -1;
894  }
895 
896  /* compare extra dimensions to zero */
897  if (DIM(a) > DIM(b))
898  {
899  for (i = dim; i < DIM(a); i++)
900  {
901  if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
902  return 1;
903  if (Min(LL_COORD(a, i), UR_COORD(a, i)) < 0)
904  return -1;
905  }
906  for (i = dim; i < DIM(a); i++)
907  {
908  if (Max(LL_COORD(a, i), UR_COORD(a, i)) > 0)
909  return 1;
910  if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
911  return -1;
912  }
913 
914  /*
915  * if all common dimensions are equal, the cube with more dimensions
916  * wins
917  */
918  return 1;
919  }
920  if (DIM(a) < DIM(b))
921  {
922  for (i = dim; i < DIM(b); i++)
923  {
924  if (Min(LL_COORD(b, i), UR_COORD(b, i)) > 0)
925  return -1;
926  if (Min(LL_COORD(b, i), UR_COORD(b, i)) < 0)
927  return 1;
928  }
929  for (i = dim; i < DIM(b); i++)
930  {
931  if (Max(LL_COORD(b, i), UR_COORD(b, i)) > 0)
932  return -1;
933  if (Max(LL_COORD(b, i), UR_COORD(b, i)) < 0)
934  return 1;
935  }
936 
937  /*
938  * if all common dimensions are equal, the cube with more dimensions
939  * wins
940  */
941  return -1;
942  }
943 
944  /* They're really equal */
945  return 0;
946 }
947 
948 Datum
950 {
951  NDBOX *a = PG_GETARG_NDBOX(0),
952  *b = PG_GETARG_NDBOX(1);
953  int32 res;
954 
955  res = cube_cmp_v0(a, b);
956 
957  PG_FREE_IF_COPY(a, 0);
958  PG_FREE_IF_COPY(b, 1);
959  PG_RETURN_INT32(res);
960 }
961 
962 
963 Datum
965 {
966  NDBOX *a = PG_GETARG_NDBOX(0),
967  *b = PG_GETARG_NDBOX(1);
968  int32 res;
969 
970  res = cube_cmp_v0(a, b);
971 
972  PG_FREE_IF_COPY(a, 0);
973  PG_FREE_IF_COPY(b, 1);
974  PG_RETURN_BOOL(res == 0);
975 }
976 
977 
978 Datum
980 {
981  NDBOX *a = PG_GETARG_NDBOX(0),
982  *b = PG_GETARG_NDBOX(1);
983  int32 res;
984 
985  res = cube_cmp_v0(a, b);
986 
987  PG_FREE_IF_COPY(a, 0);
988  PG_FREE_IF_COPY(b, 1);
989  PG_RETURN_BOOL(res != 0);
990 }
991 
992 
993 Datum
995 {
996  NDBOX *a = PG_GETARG_NDBOX(0),
997  *b = PG_GETARG_NDBOX(1);
998  int32 res;
999 
1000  res = cube_cmp_v0(a, b);
1001 
1002  PG_FREE_IF_COPY(a, 0);
1003  PG_FREE_IF_COPY(b, 1);
1004  PG_RETURN_BOOL(res < 0);
1005 }
1006 
1007 
1008 Datum
1010 {
1011  NDBOX *a = PG_GETARG_NDBOX(0),
1012  *b = PG_GETARG_NDBOX(1);
1013  int32 res;
1014 
1015  res = cube_cmp_v0(a, b);
1016 
1017  PG_FREE_IF_COPY(a, 0);
1018  PG_FREE_IF_COPY(b, 1);
1019  PG_RETURN_BOOL(res > 0);
1020 }
1021 
1022 
1023 Datum
1025 {
1026  NDBOX *a = PG_GETARG_NDBOX(0),
1027  *b = PG_GETARG_NDBOX(1);
1028  int32 res;
1029 
1030  res = cube_cmp_v0(a, b);
1031 
1032  PG_FREE_IF_COPY(a, 0);
1033  PG_FREE_IF_COPY(b, 1);
1034  PG_RETURN_BOOL(res <= 0);
1035 }
1036 
1037 
1038 Datum
1040 {
1041  NDBOX *a = PG_GETARG_NDBOX(0),
1042  *b = PG_GETARG_NDBOX(1);
1043  int32 res;
1044 
1045  res = cube_cmp_v0(a, b);
1046 
1047  PG_FREE_IF_COPY(a, 0);
1048  PG_FREE_IF_COPY(b, 1);
1049  PG_RETURN_BOOL(res >= 0);
1050 }
1051 
1052 
1053 /* Contains */
1054 /* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */
1055 bool
1057 {
1058  int i;
1059 
1060  if ((a == NULL) || (b == NULL))
1061  return (FALSE);
1062 
1063  if (DIM(a) < DIM(b))
1064  {
1065  /*
1066  * the further comparisons will make sense if the excess dimensions of
1067  * (b) were zeroes Since both UL and UR coordinates must be zero, we
1068  * can check them all without worrying about which is which.
1069  */
1070  for (i = DIM(a); i < DIM(b); i++)
1071  {
1072  if (LL_COORD(b, i) != 0)
1073  return (FALSE);
1074  if (UR_COORD(b, i) != 0)
1075  return (FALSE);
1076  }
1077  }
1078 
1079  /* Can't care less about the excess dimensions of (a), if any */
1080  for (i = 0; i < Min(DIM(a), DIM(b)); i++)
1081  {
1082  if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
1083  Min(LL_COORD(b, i), UR_COORD(b, i)))
1084  return (FALSE);
1085  if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
1086  Max(LL_COORD(b, i), UR_COORD(b, i)))
1087  return (FALSE);
1088  }
1089 
1090  return (TRUE);
1091 }
1092 
1093 Datum
1095 {
1096  NDBOX *a = PG_GETARG_NDBOX(0),
1097  *b = PG_GETARG_NDBOX(1);
1098  bool res;
1099 
1100  res = cube_contains_v0(a, b);
1101 
1102  PG_FREE_IF_COPY(a, 0);
1103  PG_FREE_IF_COPY(b, 1);
1104  PG_RETURN_BOOL(res);
1105 }
1106 
1107 /* Contained */
1108 /* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */
1109 Datum
1111 {
1112  NDBOX *a = PG_GETARG_NDBOX(0),
1113  *b = PG_GETARG_NDBOX(1);
1114  bool res;
1115 
1116  res = cube_contains_v0(b, a);
1117 
1118  PG_FREE_IF_COPY(a, 0);
1119  PG_FREE_IF_COPY(b, 1);
1120  PG_RETURN_BOOL(res);
1121 }
1122 
1123 /* Overlap */
1124 /* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */
1125 bool
1127 {
1128  int i;
1129 
1130  if ((a == NULL) || (b == NULL))
1131  return (FALSE);
1132 
1133  /* swap the box pointers if needed */
1134  if (DIM(a) < DIM(b))
1135  {
1136  NDBOX *tmp = b;
1137 
1138  b = a;
1139  a = tmp;
1140  }
1141 
1142  /* compare within the dimensions of (b) */
1143  for (i = 0; i < DIM(b); i++)
1144  {
1145  if (Min(LL_COORD(a, i), UR_COORD(a, i)) > Max(LL_COORD(b, i), UR_COORD(b, i)))
1146  return (FALSE);
1147  if (Max(LL_COORD(a, i), UR_COORD(a, i)) < Min(LL_COORD(b, i), UR_COORD(b, i)))
1148  return (FALSE);
1149  }
1150 
1151  /* compare to zero those dimensions in (a) absent in (b) */
1152  for (i = DIM(b); i < DIM(a); i++)
1153  {
1154  if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
1155  return (FALSE);
1156  if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
1157  return (FALSE);
1158  }
1159 
1160  return (TRUE);
1161 }
1162 
1163 
1164 Datum
1166 {
1167  NDBOX *a = PG_GETARG_NDBOX(0),
1168  *b = PG_GETARG_NDBOX(1);
1169  bool res;
1170 
1171  res = cube_overlap_v0(a, b);
1172 
1173  PG_FREE_IF_COPY(a, 0);
1174  PG_FREE_IF_COPY(b, 1);
1175  PG_RETURN_BOOL(res);
1176 }
1177 
1178 
1179 /* Distance */
1180 /* The distance is computed as a per axis sum of the squared distances
1181  between 1D projections of the boxes onto Cartesian axes. Assuming zero
1182  distance between overlapping projections, this metric coincides with the
1183  "common sense" geometric distance */
1184 Datum
1186 {
1187  NDBOX *a = PG_GETARG_NDBOX(0),
1188  *b = PG_GETARG_NDBOX(1);
1189  bool swapped = false;
1190  double d,
1191  distance;
1192  int i;
1193 
1194  /* swap the box pointers if needed */
1195  if (DIM(a) < DIM(b))
1196  {
1197  NDBOX *tmp = b;
1198 
1199  b = a;
1200  a = tmp;
1201  swapped = true;
1202  }
1203 
1204  distance = 0.0;
1205  /* compute within the dimensions of (b) */
1206  for (i = 0; i < DIM(b); i++)
1207  {
1208  d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), LL_COORD(b, i), UR_COORD(b, i));
1209  distance += d * d;
1210  }
1211 
1212  /* compute distance to zero for those dimensions in (a) absent in (b) */
1213  for (i = DIM(b); i < DIM(a); i++)
1214  {
1215  d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0);
1216  distance += d * d;
1217  }
1218 
1219  if (swapped)
1220  {
1221  PG_FREE_IF_COPY(b, 0);
1222  PG_FREE_IF_COPY(a, 1);
1223  }
1224  else
1225  {
1226  PG_FREE_IF_COPY(a, 0);
1227  PG_FREE_IF_COPY(b, 1);
1228  }
1229 
1230  PG_RETURN_FLOAT8(sqrt(distance));
1231 }
1232 
1233 Datum
1235 {
1236  NDBOX *a = PG_GETARG_NDBOX(0),
1237  *b = PG_GETARG_NDBOX(1);
1238  bool swapped = false;
1239  double distance;
1240  int i;
1241 
1242  /* swap the box pointers if needed */
1243  if (DIM(a) < DIM(b))
1244  {
1245  NDBOX *tmp = b;
1246 
1247  b = a;
1248  a = tmp;
1249  swapped = true;
1250  }
1251 
1252  distance = 0.0;
1253  /* compute within the dimensions of (b) */
1254  for (i = 0; i < DIM(b); i++)
1255  distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1256  LL_COORD(b, i), UR_COORD(b, i)));
1257 
1258  /* compute distance to zero for those dimensions in (a) absent in (b) */
1259  for (i = DIM(b); i < DIM(a); i++)
1260  distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1261  0.0, 0.0));
1262 
1263  if (swapped)
1264  {
1265  PG_FREE_IF_COPY(b, 0);
1266  PG_FREE_IF_COPY(a, 1);
1267  }
1268  else
1269  {
1270  PG_FREE_IF_COPY(a, 0);
1271  PG_FREE_IF_COPY(b, 1);
1272  }
1273 
1274  PG_RETURN_FLOAT8(distance);
1275 }
1276 
1277 Datum
1279 {
1280  NDBOX *a = PG_GETARG_NDBOX(0),
1281  *b = PG_GETARG_NDBOX(1);
1282  bool swapped = false;
1283  double d,
1284  distance;
1285  int i;
1286 
1287  /* swap the box pointers if needed */
1288  if (DIM(a) < DIM(b))
1289  {
1290  NDBOX *tmp = b;
1291 
1292  b = a;
1293  a = tmp;
1294  swapped = true;
1295  }
1296 
1297  distance = 0.0;
1298  /* compute within the dimensions of (b) */
1299  for (i = 0; i < DIM(b); i++)
1300  {
1301  d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1302  LL_COORD(b, i), UR_COORD(b, i)));
1303  if (d > distance)
1304  distance = d;
1305  }
1306 
1307  /* compute distance to zero for those dimensions in (a) absent in (b) */
1308  for (i = DIM(b); i < DIM(a); i++)
1309  {
1310  d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0));
1311  if (d > distance)
1312  distance = d;
1313  }
1314 
1315  if (swapped)
1316  {
1317  PG_FREE_IF_COPY(b, 0);
1318  PG_FREE_IF_COPY(a, 1);
1319  }
1320  else
1321  {
1322  PG_FREE_IF_COPY(a, 0);
1323  PG_FREE_IF_COPY(b, 1);
1324  }
1325 
1326  PG_RETURN_FLOAT8(distance);
1327 }
1328 
1329 Datum
1331 {
1332  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1334  NDBOX *cube = DatumGetNDBOX(entry->key);
1335  double retval;
1336 
1337  if (strategy == CubeKNNDistanceCoord)
1338  {
1339  int coord = PG_GETARG_INT32(1);
1340 
1341  if (DIM(cube) == 0)
1342  retval = 0.0;
1343  else if (IS_POINT(cube))
1344  retval = cube->x[(coord - 1) % DIM(cube)];
1345  else
1346  retval = Min(cube->x[(coord - 1) % DIM(cube)],
1347  cube->x[(coord - 1) % DIM(cube) + DIM(cube)]);
1348  }
1349  else
1350  {
1351  NDBOX *query = PG_GETARG_NDBOX(1);
1352 
1353  switch (strategy)
1354  {
1357  PointerGetDatum(cube), PointerGetDatum(query)));
1358  break;
1359  case CubeKNNDistanceEuclid:
1361  PointerGetDatum(cube), PointerGetDatum(query)));
1362  break;
1365  PointerGetDatum(cube), PointerGetDatum(query)));
1366  break;
1367  default:
1368  elog(ERROR, "unrecognized cube strategy number: %d", strategy);
1369  retval = 0; /* keep compiler quiet */
1370  break;
1371  }
1372  }
1373  PG_RETURN_FLOAT8(retval);
1374 }
1375 
1376 static double
1377 distance_1D(double a1, double a2, double b1, double b2)
1378 {
1379  /* interval (a) is entirely on the left of (b) */
1380  if ((a1 <= b1) && (a2 <= b1) && (a1 <= b2) && (a2 <= b2))
1381  return (Min(b1, b2) - Max(a1, a2));
1382 
1383  /* interval (a) is entirely on the right of (b) */
1384  if ((a1 > b1) && (a2 > b1) && (a1 > b2) && (a2 > b2))
1385  return (Min(a1, a2) - Max(b1, b2));
1386 
1387  /* the rest are all sorts of intersections */
1388  return (0.0);
1389 }
1390 
1391 /* Test if a box is also a point */
1392 Datum
1394 {
1395  NDBOX *cube = PG_GETARG_NDBOX(0);
1396  bool result;
1397 
1398  result = cube_is_point_internal(cube);
1399  PG_FREE_IF_COPY(cube, 0);
1400  PG_RETURN_BOOL(result);
1401 }
1402 
1403 static bool
1405 {
1406  int i;
1407 
1408  if (IS_POINT(cube))
1409  return true;
1410 
1411  /*
1412  * Even if the point-flag is not set, all the lower-left coordinates might
1413  * match the upper-right coordinates, so that the value is in fact a
1414  * point. Such values don't arise with current code - the point flag is
1415  * always set if appropriate - but they might be present on-disk in
1416  * clusters upgraded from pre-9.4 versions.
1417  */
1418  for (i = 0; i < DIM(cube); i++)
1419  {
1420  if (LL_COORD(cube, i) != UR_COORD(cube, i))
1421  return false;
1422  }
1423  return true;
1424 }
1425 
1426 /* Return dimensions in use in the data structure */
1427 Datum
1429 {
1430  NDBOX *c = PG_GETARG_NDBOX(0);
1431  int dim = DIM(c);
1432 
1433  PG_FREE_IF_COPY(c, 0);
1434  PG_RETURN_INT32(dim);
1435 }
1436 
1437 /* Return a specific normalized LL coordinate */
1438 Datum
1440 {
1441  NDBOX *c = PG_GETARG_NDBOX(0);
1442  int n = PG_GETARG_INT32(1);
1443  double result;
1444 
1445  if (DIM(c) >= n && n > 0)
1446  result = Min(LL_COORD(c, n - 1), UR_COORD(c, n - 1));
1447  else
1448  result = 0;
1449 
1450  PG_FREE_IF_COPY(c, 0);
1451  PG_RETURN_FLOAT8(result);
1452 }
1453 
1454 /* Return a specific normalized UR coordinate */
1455 Datum
1457 {
1458  NDBOX *c = PG_GETARG_NDBOX(0);
1459  int n = PG_GETARG_INT32(1);
1460  double result;
1461 
1462  if (DIM(c) >= n && n > 0)
1463  result = Max(LL_COORD(c, n - 1), UR_COORD(c, n - 1));
1464  else
1465  result = 0;
1466 
1467  PG_FREE_IF_COPY(c, 0);
1468  PG_RETURN_FLOAT8(result);
1469 }
1470 
1471 /*
1472  * Function returns cube coordinate.
1473  * Numbers from 1 to DIM denotes first corner coordinates.
1474  * Numbers from DIM+1 to 2*DIM denotes second corner coordinates.
1475  */
1476 Datum
1478 {
1479  NDBOX *cube = PG_GETARG_NDBOX(0);
1480  int coord = PG_GETARG_INT32(1);
1481 
1482  if (coord <= 0 || coord > 2 * DIM(cube))
1483  ereport(ERROR,
1484  (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
1485  errmsg("cube index %d is out of bounds", coord)));
1486 
1487  if (IS_POINT(cube))
1488  PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]);
1489  else
1490  PG_RETURN_FLOAT8(cube->x[coord - 1]);
1491 }
1492 
1493 
1494 /*
1495  * This function works like cube_coord(),
1496  * but rearranges coordinates of corners to get cube representation
1497  * in the form of (lower left, upper right).
1498  * For historical reasons that extension allows us to create cubes in form
1499  * ((2,1),(1,2)) and instead of normalizing such cube to ((1,1),(2,2)) it
1500  * stores cube in original way. But to get cubes ordered by one of dimensions
1501  * directly from the index without extra sort step we need some
1502  * representation-independent coordinate getter. This function implements it.
1503  */
1504 Datum
1506 {
1507  NDBOX *cube = PG_GETARG_NDBOX(0);
1508  int coord = PG_GETARG_INT32(1);
1509 
1510  if (coord <= 0 || coord > 2 * DIM(cube))
1511  ereport(ERROR,
1512  (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
1513  errmsg("cube index %d is out of bounds", coord)));
1514 
1515  if (coord <= DIM(cube))
1516  {
1517  if (IS_POINT(cube))
1518  PG_RETURN_FLOAT8(cube->x[coord - 1]);
1519  else
1520  PG_RETURN_FLOAT8(Min(cube->x[coord - 1],
1521  cube->x[coord - 1 + DIM(cube)]));
1522  }
1523  else
1524  {
1525  if (IS_POINT(cube))
1526  PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]);
1527  else
1528  PG_RETURN_FLOAT8(Max(cube->x[coord - 1],
1529  cube->x[coord - 1 - DIM(cube)]));
1530  }
1531 }
1532 
1533 /* Increase or decrease box size by a radius in at least n dimensions. */
1534 Datum
1536 {
1537  NDBOX *a = PG_GETARG_NDBOX(0);
1538  double r = PG_GETARG_FLOAT8(1);
1539  int32 n = PG_GETARG_INT32(2);
1540  NDBOX *result;
1541  int dim = 0;
1542  int size;
1543  int i,
1544  j;
1545 
1546  if (n > CUBE_MAX_DIM)
1547  n = CUBE_MAX_DIM;
1548  if (r > 0 && n > 0)
1549  dim = n;
1550  if (DIM(a) > dim)
1551  dim = DIM(a);
1552 
1553  size = CUBE_SIZE(dim);
1554  result = (NDBOX *) palloc0(size);
1555  SET_VARSIZE(result, size);
1556  SET_DIM(result, dim);
1557 
1558  for (i = 0, j = dim; i < DIM(a); i++, j++)
1559  {
1560  if (LL_COORD(a, i) >= UR_COORD(a, i))
1561  {
1562  result->x[i] = UR_COORD(a, i) - r;
1563  result->x[j] = LL_COORD(a, i) + r;
1564  }
1565  else
1566  {
1567  result->x[i] = LL_COORD(a, i) - r;
1568  result->x[j] = UR_COORD(a, i) + r;
1569  }
1570  if (result->x[i] > result->x[j])
1571  {
1572  result->x[i] = (result->x[i] + result->x[j]) / 2;
1573  result->x[j] = result->x[i];
1574  }
1575  }
1576  /* dim > a->dim only if r > 0 */
1577  for (; i < dim; i++, j++)
1578  {
1579  result->x[i] = -r;
1580  result->x[j] = r;
1581  }
1582 
1583  /*
1584  * Check if the result was in fact a point, and set the flag in the datum
1585  * accordingly. (we don't bother to repalloc it smaller)
1586  */
1587  if (cube_is_point_internal(result))
1588  {
1589  size = POINT_SIZE(dim);
1590  SET_VARSIZE(result, size);
1591  SET_POINT_BIT(result);
1592  }
1593 
1594  PG_FREE_IF_COPY(a, 0);
1595  PG_RETURN_NDBOX(result);
1596 }
1597 
1598 /* Create a one dimensional box with identical upper and lower coordinates */
1599 Datum
1601 {
1602  double x = PG_GETARG_FLOAT8(0);
1603  NDBOX *result;
1604  int size;
1605 
1606  size = POINT_SIZE(1);
1607  result = (NDBOX *) palloc0(size);
1608  SET_VARSIZE(result, size);
1609  SET_DIM(result, 1);
1610  SET_POINT_BIT(result);
1611  result->x[0] = x;
1612 
1613  PG_RETURN_NDBOX(result);
1614 }
1615 
1616 /* Create a one dimensional box */
1617 Datum
1619 {
1620  double x0 = PG_GETARG_FLOAT8(0);
1621  double x1 = PG_GETARG_FLOAT8(1);
1622  NDBOX *result;
1623  int size;
1624 
1625  if (x0 == x1)
1626  {
1627  size = POINT_SIZE(1);
1628  result = (NDBOX *) palloc0(size);
1629  SET_VARSIZE(result, size);
1630  SET_DIM(result, 1);
1631  SET_POINT_BIT(result);
1632  result->x[0] = x0;
1633  }
1634  else
1635  {
1636  size = CUBE_SIZE(1);
1637  result = (NDBOX *) palloc0(size);
1638  SET_VARSIZE(result, size);
1639  SET_DIM(result, 1);
1640  result->x[0] = x0;
1641  result->x[1] = x1;
1642  }
1643 
1644  PG_RETURN_NDBOX(result);
1645 }
1646 
1647 /* Add a dimension to an existing cube with the same values for the new
1648  coordinate */
1649 Datum
1651 {
1652  NDBOX *cube = PG_GETARG_NDBOX(0);
1653  double x = PG_GETARG_FLOAT8(1);
1654  NDBOX *result;
1655  int size;
1656  int i;
1657 
1658  if (IS_POINT(cube))
1659  {
1660  size = POINT_SIZE((DIM(cube) + 1));
1661  result = (NDBOX *) palloc0(size);
1662  SET_VARSIZE(result, size);
1663  SET_DIM(result, DIM(cube) + 1);
1664  SET_POINT_BIT(result);
1665  for (i = 0; i < DIM(cube); i++)
1666  result->x[i] = cube->x[i];
1667  result->x[DIM(result) - 1] = x;
1668  }
1669  else
1670  {
1671  size = CUBE_SIZE((DIM(cube) + 1));
1672  result = (NDBOX *) palloc0(size);
1673  SET_VARSIZE(result, size);
1674  SET_DIM(result, DIM(cube) + 1);
1675  for (i = 0; i < DIM(cube); i++)
1676  {
1677  result->x[i] = cube->x[i];
1678  result->x[DIM(result) + i] = cube->x[DIM(cube) + i];
1679  }
1680  result->x[DIM(result) - 1] = x;
1681  result->x[2 * DIM(result) - 1] = x;
1682  }
1683 
1684  PG_FREE_IF_COPY(cube, 0);
1685  PG_RETURN_NDBOX(result);
1686 }
1687 
1688 /* Add a dimension to an existing cube */
1689 Datum
1691 {
1692  NDBOX *cube = PG_GETARG_NDBOX(0);
1693  double x1 = PG_GETARG_FLOAT8(1);
1694  double x2 = PG_GETARG_FLOAT8(2);
1695  NDBOX *result;
1696  int size;
1697  int i;
1698 
1699  if (IS_POINT(cube) && (x1 == x2))
1700  {
1701  size = POINT_SIZE((DIM(cube) + 1));
1702  result = (NDBOX *) palloc0(size);
1703  SET_VARSIZE(result, size);
1704  SET_DIM(result, DIM(cube) + 1);
1705  SET_POINT_BIT(result);
1706  for (i = 0; i < DIM(cube); i++)
1707  result->x[i] = cube->x[i];
1708  result->x[DIM(result) - 1] = x1;
1709  }
1710  else
1711  {
1712  size = CUBE_SIZE((DIM(cube) + 1));
1713  result = (NDBOX *) palloc0(size);
1714  SET_VARSIZE(result, size);
1715  SET_DIM(result, DIM(cube) + 1);
1716  for (i = 0; i < DIM(cube); i++)
1717  {
1718  result->x[i] = LL_COORD(cube, i);
1719  result->x[DIM(result) + i] = UR_COORD(cube, i);
1720  }
1721  result->x[DIM(result) - 1] = x1;
1722  result->x[2 * DIM(result) - 1] = x2;
1723  }
1724 
1725  PG_FREE_IF_COPY(cube, 0);
1726  PG_RETURN_NDBOX(result);
1727 }
Datum cube_lt(PG_FUNCTION_ARGS)
Definition: cube.c:994
#define GIST_LEAF(entry)
Definition: gist.h:133
Relation rel
Definition: gist.h:124
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:246
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:321
int32 cube_cmp_v0(NDBOX *a, NDBOX *b)
Definition: cube.c:869
Datum cube_distance(PG_FUNCTION_ARGS)
Definition: cube.c:1185
#define PG_GETARG_INT32(n)
Definition: fmgr.h:234
Datum cube_ne(PG_FUNCTION_ARGS)
Definition: cube.c:979
Datum cube_dim(PG_FUNCTION_ARGS)
Definition: cube.c:1428
#define RTOldContainsStrategyNumber
Definition: stratnum.h:56
Datum distance_chebyshev(PG_FUNCTION_ARGS)
Definition: cube.c:1278
Datum cube_c_f8(PG_FUNCTION_ARGS)
Definition: cube.c:1650
#define RTOldContainedByStrategyNumber
Definition: stratnum.h:57
char * float8out_internal(double num)
Definition: float.c:596
#define CubeKNNDistanceTaxicab
Definition: cubedata.h:58
#define VARSIZE(PTR)
Definition: postgres.h:304
Datum g_cube_distance(PG_FUNCTION_ARGS)
Definition: cube.c:1330
bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy)
Definition: cube.c:603
#define PointerGetDatum(X)
Definition: postgres.h:562
#define DIM(cube)
Definition: cubedata.h:42
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:233
#define CubeKNNDistanceEuclid
Definition: cubedata.h:59
Datum cube_cmp(PG_FUNCTION_ARGS)
Definition: cube.c:949
Datum cube_a_f8_f8(PG_FUNCTION_ARGS)
Definition: cube.c:137
Datum cube_subset(PG_FUNCTION_ARGS)
Definition: cube.c:228
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:326
#define Min(x, y)
Definition: c.h:807
OffsetNumber * spl_left
Definition: gist.h:105
Datum spl_rdatum
Definition: gist.h:112
#define PG_RETURN_INT32(x)
Definition: fmgr.h:314
int32 n
Definition: gist.h:160
PG_FUNCTION_INFO_V1(cube_in)
uint16 StrategyNumber
Definition: stratnum.h:22
int errcode(int sqlerrcode)
Definition: elog.c:575
bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy)
Definition: cube.c:632
void cube_scanner_init(const char *str)
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:264
return result
Definition: formatting.c:1633
#define RTContainedByStrategyNumber
Definition: stratnum.h:51
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:241
int spl_nleft
Definition: gist.h:106
bool cube_overlap_v0(NDBOX *a, NDBOX *b)
Definition: cube.c:1126
Datum cube_f8(PG_FUNCTION_ARGS)
Definition: cube.c:1600
Datum g_cube_compress(PG_FUNCTION_ARGS)
Definition: cube.c:382
Datum cube_enlarge(PG_FUNCTION_ARGS)
Definition: cube.c:1535
Datum cube_ll_coord(PG_FUNCTION_ARGS)
Definition: cube.c:1439
char bool
Definition: c.h:202
signed int int32
Definition: c.h:256
uint16 OffsetNumber
Definition: off.h:24
Page page
Definition: gist.h:125
#define Abs(x)
Definition: c.h:813
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:161
#define CUBE_MAX_DIM
Definition: cubedata.h:7
Datum distance_taxicab(PG_FUNCTION_ARGS)
Definition: cube.c:1234
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:244
static double distance_1D(double a1, double a2, double b1, double b2)
Definition: cube.c:1377
Datum cube_size(PG_FUNCTION_ARGS)
Definition: cube.c:831
#define CubeKNNDistanceChebyshev
Definition: cubedata.h:60
#define ERROR
Definition: elog.h:43
#define FALSE
Definition: c.h:221
int spl_nright
Definition: gist.h:111
void cube_scanner_finish(void)
#define LL_COORD(cube, i)
Definition: cubedata.h:45
#define PG_GETARG_NDBOX(x)
Definition: cubedata.h:53
Datum cube_contains(PG_FUNCTION_ARGS)
Definition: cube.c:1094
Datum g_cube_penalty(PG_FUNCTION_ARGS)
Definition: cube.c:411
void cube_yyerror(NDBOX **result, const char *message) pg_attribute_noreturn()
Datum cube_union(PG_FUNCTION_ARGS)
Definition: cube.c:736
Datum key
Definition: gist.h:123
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
#define ARR_DATA_PTR(a)
Definition: array.h:303
Datum g_cube_picksplit(PG_FUNCTION_ARGS)
Definition: cube.c:436
Datum cube_inter(PG_FUNCTION_ARGS)
Definition: cube.c:751
char * c
static char * buf
Definition: pg_test_fsync.c:66
#define FirstOffsetNumber
Definition: off.h:27
#define RTSameStrategyNumber
Definition: stratnum.h:49
#define IS_POINT(cube)
Definition: cubedata.h:40
Datum cube_coord(PG_FUNCTION_ARGS)
Definition: cube.c:1477
#define ereport(elevel, rest)
Definition: elog.h:122
Datum cube_a_f8(PG_FUNCTION_ARGS)
Definition: cube.c:197
Datum g_cube_same(PG_FUNCTION_ARGS)
Definition: cube.c:585
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
NDBOX * g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
Definition: cube.c:659
void * palloc0(Size size)
Definition: mcxt.c:878
Datum cube_f8_f8(PG_FUNCTION_ARGS)
Definition: cube.c:1618
void rt_cube_size(NDBOX *a, double *sz)
Definition: cube.c:842
#define DatumGetFloat8(X)
Definition: postgres.h:734
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:319
uintptr_t Datum
Definition: postgres.h:372
#define DatumGetNDBOX(x)
Definition: cubedata.h:52
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:313
Datum g_cube_decompress(PG_FUNCTION_ARGS)
Definition: cube.c:388
Datum cube_in(PG_FUNCTION_ARGS)
Definition: cube.c:117
Datum cube_is_point(PG_FUNCTION_ARGS)
Definition: cube.c:1393
static FormData_pg_attribute a1
Definition: heap.c:144
#define Max(x, y)
Definition: c.h:801
Datum cube_contained(PG_FUNCTION_ARGS)
Definition: cube.c:1110
Definition: cubedata.h:9
Datum spl_ldatum
Definition: gist.h:107
#define NULL
Definition: c.h:229
Datum cube_out(PG_FUNCTION_ARGS)
Definition: cube.c:270
Datum cube_c_f8_f8(PG_FUNCTION_ARGS)
Definition: cube.c:1690
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:169
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:322
#define PG_RETURN_NDBOX(x)
Definition: cubedata.h:54
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
double x[FLEXIBLE_ARRAY_MEMBER]
Definition: cubedata.h:33
OffsetNumber * spl_right
Definition: gist.h:110
#define POINT_SIZE(_dim)
Definition: cubedata.h:48
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:225
#define RTContainsStrategyNumber
Definition: stratnum.h:50
#define ARRNELEMS(x)
Definition: cube.c:27
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:963
Datum cube_le(PG_FUNCTION_ARGS)
Definition: cube.c:1024
#define PG_GETARG_UINT16(n)
Definition: fmgr.h:237
NDBOX * cube_union_v0(NDBOX *a, NDBOX *b)
Definition: cube.c:672
int cube_yyparse(NDBOX **result)
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define SET_POINT_BIT(cube)
Definition: cubedata.h:41
int i
#define SET_DIM(cube, _dim)
Definition: cubedata.h:43
Datum cube_overlap(PG_FUNCTION_ARGS)
Definition: cube.c:1165
PG_MODULE_MAGIC
Definition: cube.c:21
Datum cube_ge(PG_FUNCTION_ARGS)
Definition: cube.c:1039
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:242
#define CUBE_SIZE(_dim)
Definition: cubedata.h:49
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:205
#define RTOverlapStrategyNumber
Definition: stratnum.h:46
#define PG_FUNCTION_ARGS
Definition: fmgr.h:158
#define TRUE
Definition: c.h:217
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:328
#define ARRPTR(x)
Definition: cube.c:26
#define elog
Definition: elog.h:219
#define CubeKNNDistanceCoord
Definition: cubedata.h:57
static bool cube_is_point_internal(NDBOX *cube)
Definition: cube.c:1404
Datum cube_coord_llur(PG_FUNCTION_ARGS)
Definition: cube.c:1505
#define UR_COORD(cube, i)
Definition: cubedata.h:46
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3542
OffsetNumber offset
Definition: gist.h:126
bool cube_contains_v0(NDBOX *a, NDBOX *b)
Definition: cube.c:1056
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:586
Datum cube_eq(PG_FUNCTION_ARGS)
Definition: cube.c:964
Datum cube_gt(PG_FUNCTION_ARGS)
Definition: cube.c:1009
Datum g_cube_union(PG_FUNCTION_ARGS)
Definition: cube.c:350
static FormData_pg_attribute a2
Definition: heap.c:150
Datum cube_ur_coord(PG_FUNCTION_ARGS)
Definition: cube.c:1456
Datum g_cube_consistent(PG_FUNCTION_ARGS)
Definition: cube.c:316