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 : }
|