LCOV - differential code coverage report
Current view: top level - contrib/cube - cube.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 88.1 % 817 720 22 40 35 7 375 3 335 55 361 2
Current Date: 2023-04-08 17:13:01 Functions: 93.7 % 95 89 6 45 1 43 6 45
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (120,180] days: 100.0 % 1 1 1
Legend: Lines: hit not hit (180,240] days: 100.0 % 2 2 2
(240..) days: 88.1 % 814 717 22 40 35 7 375 335 55 361
Function coverage date bins:
(240..) days: 61.0 % 146 89 6 45 1 43 6 45

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

Generated by: LCOV version v1.16-55-g56c0a2a