Age Owner Branch data 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 : :
6529 tgl@sss.pgh.pa.us 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 : : */
6473 bruce@momjian.us 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);
1135 tgl@sss.pgh.pa.us 35 : 3 : PG_FUNCTION_INFO_V1(cube_send);
36 : 3 : PG_FUNCTION_INFO_V1(cube_recv);
6473 bruce@momjian.us 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);
3040 teodor@sigaev.ru 44 : 4 : PG_FUNCTION_INFO_V1(cube_coord);
45 : 4 : PG_FUNCTION_INFO_V1(cube_coord_llur);
6473 bruce@momjian.us 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);
3040 teodor@sigaev.ru 59 : 4 : PG_FUNCTION_INFO_V1(g_cube_distance);
60 : :
61 : : /*
62 : : ** B-tree support functions
63 : : */
6473 bruce@momjian.us 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 : : */
3040 teodor@sigaev.ru 86 : 4 : PG_FUNCTION_INFO_V1(distance_taxicab);
6473 bruce@momjian.us 87 : 5 : PG_FUNCTION_INFO_V1(cube_distance);
3040 teodor@sigaev.ru 88 : 4 : PG_FUNCTION_INFO_V1(distance_chebyshev);
6473 bruce@momjian.us 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 : : {
5799 tgl@sss.pgh.pa.us 120 : 3435 : char *str = PG_GETARG_CSTRING(0);
121 : : NDBOX *result;
122 : : Size scanbuflen;
123 : :
588 john.naylor@postgres 124 : 3435 : cube_scanner_init(str, &scanbuflen);
125 : :
492 tgl@sss.pgh.pa.us 126 : 3435 : cube_yyparse(&result, scanbuflen, fcinfo->context);
127 : :
128 : : /* We might as well run this even on failure. */
7518 129 : 3405 : cube_scanner_finish();
130 : :
2400 131 : 3405 : PG_RETURN_NDBOX_P(result);
132 : : }
133 : :
134 : :
135 : : /*
136 : : ** Allows the construction of a cube from 2 float[]'s
137 : : */
138 : : Datum
6473 bruce@momjian.us 139 : 22 : cube_a_f8_f8(PG_FUNCTION_ARGS)
140 : : {
5799 tgl@sss.pgh.pa.us 141 : 22 : ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0);
142 : 22 : ArrayType *ll = PG_GETARG_ARRAYTYPE_P(1);
143 : : NDBOX *result;
144 : : int i;
145 : : int dim;
146 : : int size;
147 : : bool point;
148 : : double *dur,
149 : : *dll;
150 : :
4844 151 [ + - - + ]: 22 : if (array_contains_nulls(ur) || array_contains_nulls(ll))
6473 bruce@momjian.us 152 [ # # ]:UBC 0 : ereport(ERROR,
153 : : (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
154 : : errmsg("cannot work with arrays containing NULLs")));
155 : :
6473 bruce@momjian.us 156 :CBC 22 : dim = ARRNELEMS(ur);
2054 akorotkov@postgresql 157 [ + + ]: 22 : if (dim > CUBE_MAX_DIM)
158 [ + - ]: 1 : ereport(ERROR,
159 : : (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 : :
6473 bruce@momjian.us 164 [ + + ]: 21 : if (ARRNELEMS(ll) != dim)
165 [ + - ]: 1 : ereport(ERROR,
166 : : (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
167 : : errmsg("UR and LL arrays must be of same length")));
168 : :
169 [ - + ]: 20 : dur = ARRPTR(ur);
170 [ - + ]: 20 : dll = ARRPTR(ll);
171 : :
172 : : /* Check if it's a point */
3828 heikki.linnakangas@i 173 : 20 : point = true;
174 [ + + ]: 223 : for (i = 0; i < dim; i++)
175 : : {
176 [ + + ]: 220 : if (dur[i] != dll[i])
177 : : {
178 : 17 : point = false;
179 : 17 : break;
180 : : }
181 : : }
182 : :
183 [ + + ]: 20 : size = point ? POINT_SIZE(dim) : CUBE_SIZE(dim);
6256 tgl@sss.pgh.pa.us 184 : 20 : result = (NDBOX *) palloc0(size);
185 : 20 : SET_VARSIZE(result, size);
3828 heikki.linnakangas@i 186 : 20 : SET_DIM(result, dim);
187 : :
6402 bruce@momjian.us 188 [ + + ]: 274 : for (i = 0; i < dim; i++)
6473 189 : 254 : result->x[i] = dur[i];
190 : :
3828 heikki.linnakangas@i 191 [ + + ]: 20 : if (!point)
192 : : {
193 [ + + ]: 68 : for (i = 0; i < dim; i++)
194 : 51 : result->x[i + dim] = dll[i];
195 : : }
196 : : else
197 : 3 : SET_POINT_BIT(result);
198 : :
2400 tgl@sss.pgh.pa.us 199 : 20 : PG_RETURN_NDBOX_P(result);
200 : : }
201 : :
202 : : /*
203 : : ** Allows the construction of a zero-volume cube from a float[]
204 : : */
205 : : Datum
6473 bruce@momjian.us 206 : 8 : cube_a_f8(PG_FUNCTION_ARGS)
207 : : {
5799 tgl@sss.pgh.pa.us 208 : 8 : ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0);
209 : : NDBOX *result;
210 : : int i;
211 : : int dim;
212 : : int size;
213 : : double *dur;
214 : :
4844 215 [ - + ]: 8 : if (array_contains_nulls(ur))
6473 bruce@momjian.us 216 [ # # ]:UBC 0 : ereport(ERROR,
217 : : (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
218 : : errmsg("cannot work with arrays containing NULLs")));
219 : :
6473 bruce@momjian.us 220 :CBC 8 : dim = ARRNELEMS(ur);
2054 akorotkov@postgresql 221 [ + + ]: 8 : if (dim > CUBE_MAX_DIM)
222 [ + - ]: 1 : ereport(ERROR,
223 : : (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 : :
6473 bruce@momjian.us 228 [ - + ]: 7 : dur = ARRPTR(ur);
229 : :
3828 heikki.linnakangas@i 230 : 7 : size = POINT_SIZE(dim);
6256 tgl@sss.pgh.pa.us 231 : 7 : result = (NDBOX *) palloc0(size);
232 : 7 : SET_VARSIZE(result, size);
3828 heikki.linnakangas@i 233 : 7 : SET_DIM(result, dim);
234 : 7 : SET_POINT_BIT(result);
235 : :
6402 bruce@momjian.us 236 [ + + ]: 223 : for (i = 0; i < dim; i++)
6473 237 : 216 : result->x[i] = dur[i];
238 : :
2400 tgl@sss.pgh.pa.us 239 : 7 : PG_RETURN_NDBOX_P(result);
240 : : }
241 : :
242 : : Datum
6473 bruce@momjian.us 243 : 6 : cube_subset(PG_FUNCTION_ARGS)
244 : : {
2400 tgl@sss.pgh.pa.us 245 : 6 : NDBOX *c = PG_GETARG_NDBOX_P(0);
5799 246 : 6 : ArrayType *idx = PG_GETARG_ARRAYTYPE_P(1);
247 : : NDBOX *result;
248 : : int size,
249 : : dim,
250 : : i;
251 : : int *dx;
252 : :
4844 253 [ - + ]: 6 : if (array_contains_nulls(idx))
6473 bruce@momjian.us 254 [ # # ]:UBC 0 : ereport(ERROR,
255 : : (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
256 : : errmsg("cannot work with arrays containing NULLs")));
257 : :
4311 peter_e@gmx.net 258 [ - + ]:CBC 6 : dx = (int32 *) ARR_DATA_PTR(idx);
259 : :
6473 bruce@momjian.us 260 : 6 : dim = ARRNELEMS(idx);
2054 akorotkov@postgresql 261 [ + + ]: 6 : if (dim > CUBE_MAX_DIM)
262 [ + - ]: 1 : ereport(ERROR,
263 : : (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 : :
3828 heikki.linnakangas@i 268 [ + + ]: 5 : size = IS_POINT(c) ? POINT_SIZE(dim) : CUBE_SIZE(dim);
6256 tgl@sss.pgh.pa.us 269 : 5 : result = (NDBOX *) palloc0(size);
270 : 5 : SET_VARSIZE(result, size);
3828 heikki.linnakangas@i 271 : 5 : SET_DIM(result, dim);
272 : :
273 [ + + ]: 5 : if (IS_POINT(c))
274 : 3 : SET_POINT_BIT(result);
275 : :
6402 bruce@momjian.us 276 [ + + ]: 113 : for (i = 0; i < dim; i++)
277 : : {
3828 heikki.linnakangas@i 278 [ + - + + ]: 110 : if ((dx[i] <= 0) || (dx[i] > DIM(c)))
6473 bruce@momjian.us 279 [ + - ]: 2 : ereport(ERROR,
280 : : (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
281 : : errmsg("Index out of bounds")));
6402 282 : 108 : result->x[i] = c->x[dx[i] - 1];
3828 heikki.linnakangas@i 283 [ + + ]: 108 : if (!IS_POINT(c))
284 : 4 : result->x[i + dim] = c->x[dx[i] + DIM(c) - 1];
285 : : }
286 : :
5995 bruce@momjian.us 287 [ - + ]: 3 : PG_FREE_IF_COPY(c, 0);
2400 tgl@sss.pgh.pa.us 288 : 3 : PG_RETURN_NDBOX_P(result);
289 : : }
290 : :
291 : : Datum
6473 bruce@momjian.us 292 : 389 : cube_out(PG_FUNCTION_ARGS)
293 : : {
2400 tgl@sss.pgh.pa.us 294 : 389 : NDBOX *cube = PG_GETARG_NDBOX_P(0);
295 : : StringInfoData buf;
3828 heikki.linnakangas@i 296 : 389 : int dim = DIM(cube);
297 : : int i;
298 : :
7910 tgl@sss.pgh.pa.us 299 : 389 : initStringInfo(&buf);
300 : :
301 : 389 : appendStringInfoChar(&buf, '(');
8424 bruce@momjian.us 302 [ + + ]: 1435 : for (i = 0; i < dim; i++)
303 : : {
7910 tgl@sss.pgh.pa.us 304 [ + + ]: 1046 : if (i > 0)
3818 rhaas@postgresql.org 305 : 659 : appendStringInfoString(&buf, ", ");
2756 tgl@sss.pgh.pa.us 306 : 1046 : appendStringInfoString(&buf, float8out_internal(LL_COORD(cube, i)));
307 : : }
7910 308 : 389 : appendStringInfoChar(&buf, ')');
309 : :
3828 heikki.linnakangas@i 310 [ + + ]: 389 : if (!cube_is_point_internal(cube))
311 : : {
3818 rhaas@postgresql.org 312 : 290 : appendStringInfoString(&buf, ",(");
7910 tgl@sss.pgh.pa.us 313 [ + + ]: 880 : for (i = 0; i < dim; i++)
314 : : {
315 [ + + ]: 590 : if (i > 0)
3818 rhaas@postgresql.org 316 : 300 : appendStringInfoString(&buf, ", ");
2756 tgl@sss.pgh.pa.us 317 [ - + ]: 590 : appendStringInfoString(&buf, float8out_internal(UR_COORD(cube, i)));
318 : : }
7910 319 : 290 : appendStringInfoChar(&buf, ')');
320 : : }
321 : :
5995 bruce@momjian.us 322 [ - + ]: 389 : PG_FREE_IF_COPY(cube, 0);
6402 323 : 389 : PG_RETURN_CSTRING(buf.data);
324 : : }
325 : :
326 : : /*
327 : : * cube_send - a binary output handler for cube type
328 : : */
329 : : Datum
1135 tgl@sss.pgh.pa.us 330 :UBC 0 : cube_send(PG_FUNCTION_ARGS)
331 : : {
332 : 0 : NDBOX *cube = PG_GETARG_NDBOX_P(0);
333 : : StringInfoData buf;
334 : : int32 i,
335 : 0 : nitems = DIM(cube);
336 : :
337 : 0 : pq_begintypsend(&buf);
338 : 0 : pq_sendint32(&buf, cube->header);
339 [ # # ]: 0 : if (!IS_POINT(cube))
340 : 0 : nitems += nitems;
341 : : /* for symmetry with cube_recv, we don't use LL_COORD/UR_COORD here */
342 [ # # ]: 0 : for (i = 0; i < nitems; i++)
343 : 0 : pq_sendfloat8(&buf, cube->x[i]);
344 : :
345 : 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
346 : : }
347 : :
348 : : /*
349 : : * cube_recv - a binary input handler for cube type
350 : : */
351 : : Datum
352 : 0 : cube_recv(PG_FUNCTION_ARGS)
353 : : {
354 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
355 : : int32 header;
356 : : int32 i,
357 : : nitems;
358 : : NDBOX *cube;
359 : :
360 : 0 : header = pq_getmsgint(buf, sizeof(int32));
361 : 0 : nitems = (header & DIM_MASK);
362 [ # # ]: 0 : if (nitems > CUBE_MAX_DIM)
363 [ # # ]: 0 : ereport(ERROR,
364 : : (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)));
368 [ # # ]: 0 : if ((header & POINT_BIT) == 0)
369 : 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);
375 : :
376 : 0 : PG_RETURN_NDBOX_P(cube);
377 : : }
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
6473 bruce@momjian.us 391 :CBC 249 : g_cube_consistent(PG_FUNCTION_ARGS)
392 : : {
6402 393 : 249 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
2400 tgl@sss.pgh.pa.us 394 : 249 : NDBOX *query = PG_GETARG_NDBOX_P(1);
6473 bruce@momjian.us 395 : 249 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
396 : :
397 : : /* Oid subtype = PG_GETARG_OID(3); */
5844 tgl@sss.pgh.pa.us 398 : 249 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
399 : : bool res;
400 : :
401 : : /* All cases served by this function are exact */
402 : 249 : *recheck = false;
403 : :
404 : : /*
405 : : * if entry is not leaf, use g_cube_internal_consistent, else use
406 : : * g_cube_leaf_consistent
407 : : */
8424 bruce@momjian.us 408 [ + + ]: 249 : if (GIST_LEAF(entry))
2400 tgl@sss.pgh.pa.us 409 : 144 : res = g_cube_leaf_consistent(DatumGetNDBOXP(entry->key),
410 : : query, strategy);
411 : : else
412 : 105 : res = g_cube_internal_consistent(DatumGetNDBOXP(entry->key),
413 : : query, strategy);
414 : :
5995 bruce@momjian.us 415 [ - + ]: 249 : PG_FREE_IF_COPY(query, 1);
6248 teodor@sigaev.ru 416 : 249 : PG_RETURN_BOOL(res);
417 : : }
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
6473 bruce@momjian.us 425 : 2962 : g_cube_union(PG_FUNCTION_ARGS)
426 : : {
5799 tgl@sss.pgh.pa.us 427 : 2962 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
428 : 2962 : int *sizep = (int *) PG_GETARG_POINTER(1);
8424 bruce@momjian.us 429 : 2962 : NDBOX *out = (NDBOX *) NULL;
430 : : NDBOX *tmp;
431 : : int i;
432 : :
2400 tgl@sss.pgh.pa.us 433 : 2962 : tmp = DatumGetNDBOXP(entryvec->vector[0].key);
434 : :
435 : : /*
436 : : * sizep = sizeof(NDBOX); -- NDBOX has variable size
437 : : */
6256 438 : 2962 : *sizep = VARSIZE(tmp);
439 : :
7320 teodor@sigaev.ru 440 [ + + ]: 5924 : for (i = 1; i < entryvec->n; i++)
441 : : {
6248 442 : 2962 : out = g_cube_binary_union(tmp,
2400 tgl@sss.pgh.pa.us 443 : 2962 : DatumGetNDBOXP(entryvec->vector[i].key),
444 : : sizep);
8424 bruce@momjian.us 445 : 2962 : tmp = out;
446 : : }
447 : :
6473 448 : 2962 : PG_RETURN_POINTER(out);
449 : : }
450 : :
451 : : /*
452 : : ** GiST Compress and Decompress methods for boxes
453 : : ** do not do anything.
454 : : */
455 : :
456 : : Datum
6402 bruce@momjian.us 457 :UBC 0 : g_cube_compress(PG_FUNCTION_ARGS)
458 : : {
459 : 0 : PG_RETURN_DATUM(PG_GETARG_DATUM(0));
460 : : }
461 : :
462 : : Datum
463 : 0 : g_cube_decompress(PG_FUNCTION_ARGS)
464 : : {
6248 teodor@sigaev.ru 465 : 0 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
2400 tgl@sss.pgh.pa.us 466 : 0 : NDBOX *key = DatumGetNDBOXP(entry->key);
467 : :
468 [ # # ]: 0 : if (key != DatumGetNDBOXP(entry->key))
469 : : {
6248 teodor@sigaev.ru 470 : 0 : GISTENTRY *retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
471 : :
472 : 0 : gistentryinit(*retval, PointerGetDatum(key),
473 : : entry->rel, entry->page,
474 : : entry->offset, false);
475 : 0 : PG_RETURN_POINTER(retval);
476 : : }
477 : 0 : PG_RETURN_POINTER(entry);
478 : : }
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
6402 bruce@momjian.us 486 :CBC 42985 : g_cube_penalty(PG_FUNCTION_ARGS)
487 : : {
488 : 42985 : GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
489 : 42985 : GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
490 : 42985 : float *result = (float *) PG_GETARG_POINTER(2);
491 : : NDBOX *ud;
492 : : double tmp1,
493 : : tmp2;
494 : :
2400 tgl@sss.pgh.pa.us 495 : 42985 : ud = cube_union_v0(DatumGetNDBOXP(origentry->key),
496 : 42985 : DatumGetNDBOXP(newentry->key));
8354 497 : 42985 : rt_cube_size(ud, &tmp1);
2400 498 : 42985 : rt_cube_size(DatumGetNDBOXP(origentry->key), &tmp2);
7899 bruce@momjian.us 499 : 42985 : *result = (float) (tmp1 - tmp2);
500 : :
6402 501 : 42985 : PG_RETURN_FLOAT8(*result);
502 : : }
503 : :
504 : :
505 : :
506 : : /*
507 : : ** The GiST PickSplit method for boxes
508 : : ** We use Guttman's poly time split algorithm
509 : : */
510 : : Datum
6473 511 : 34 : g_cube_picksplit(PG_FUNCTION_ARGS)
512 : : {
5799 tgl@sss.pgh.pa.us 513 : 34 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
514 : 34 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
515 : : 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;
6500 teodor@sigaev.ru 535 : 34 : OffsetNumber seed_1 = 1,
536 : 34 : seed_2 = 2;
537 : : OffsetNumber *left,
538 : : *right;
539 : : OffsetNumber maxoff;
540 : :
7320 541 : 34 : maxoff = entryvec->n - 2;
8424 bruce@momjian.us 542 : 34 : nbytes = (maxoff + 2) * sizeof(OffsetNumber);
543 : 34 : v->spl_left = (OffsetNumber *) palloc(nbytes);
544 : 34 : v->spl_right = (OffsetNumber *) palloc(nbytes);
545 : :
546 : 34 : firsttime = true;
547 : 34 : waste = 0.0;
548 : :
549 [ + + ]: 4760 : for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
550 : : {
2400 tgl@sss.pgh.pa.us 551 : 4726 : datum_alpha = DatumGetNDBOXP(entryvec->vector[i].key);
8424 bruce@momjian.us 552 [ + + ]: 335546 : for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
553 : : {
2400 tgl@sss.pgh.pa.us 554 : 330820 : datum_beta = DatumGetNDBOXP(entryvec->vector[j].key);
555 : :
556 : : /* compute the wasted space by unioning these guys */
557 : : /* size_waste = size_union - size_inter; */
6473 bruce@momjian.us 558 : 330820 : union_d = cube_union_v0(datum_alpha, datum_beta);
8424 559 : 330820 : rt_cube_size(union_d, &size_union);
2400 tgl@sss.pgh.pa.us 560 : 330820 : inter_d = DatumGetNDBOXP(DirectFunctionCall2(cube_inter,
561 : : entryvec->vector[i].key,
562 : : entryvec->vector[j].key));
8424 bruce@momjian.us 563 : 330820 : rt_cube_size(inter_d, &size_inter);
564 : 330820 : size_waste = size_union - size_inter;
565 : :
566 : : /*
567 : : * are these a more promising split than what we've already seen?
568 : : */
569 : :
570 [ + + - + ]: 330820 : if (size_waste > waste || firsttime)
571 : : {
572 : 458 : waste = size_waste;
573 : 458 : seed_1 = i;
574 : 458 : seed_2 = j;
575 : 458 : firsttime = false;
576 : : }
577 : : }
578 : : }
579 : :
580 : 34 : left = v->spl_left;
581 : 34 : v->spl_nleft = 0;
582 : 34 : right = v->spl_right;
583 : 34 : v->spl_nright = 0;
584 : :
2400 tgl@sss.pgh.pa.us 585 : 34 : datum_alpha = DatumGetNDBOXP(entryvec->vector[seed_1].key);
6473 bruce@momjian.us 586 : 34 : datum_l = cube_union_v0(datum_alpha, datum_alpha);
8354 tgl@sss.pgh.pa.us 587 : 34 : rt_cube_size(datum_l, &size_l);
2400 588 : 34 : datum_beta = DatumGetNDBOXP(entryvec->vector[seed_2].key);
6473 bruce@momjian.us 589 : 34 : datum_r = cube_union_v0(datum_beta, datum_beta);
8354 tgl@sss.pgh.pa.us 590 : 34 : rt_cube_size(datum_r, &size_r);
591 : :
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 : :
8424 bruce@momjian.us 604 : 34 : maxoff = OffsetNumberNext(maxoff);
605 [ + + ]: 4828 : for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
606 : : {
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 : :
613 [ + + ]: 4794 : if (i == seed_1)
614 : : {
615 : 34 : *left++ = i;
616 : 34 : v->spl_nleft++;
617 : 34 : continue;
618 : : }
619 [ + + ]: 4760 : else if (i == seed_2)
620 : : {
621 : 34 : *right++ = i;
622 : 34 : v->spl_nright++;
623 : 34 : continue;
624 : : }
625 : :
626 : : /* okay, which page needs least enlargement? */
2400 tgl@sss.pgh.pa.us 627 : 4726 : datum_alpha = DatumGetNDBOXP(entryvec->vector[i].key);
6473 bruce@momjian.us 628 : 4726 : union_dl = cube_union_v0(datum_l, datum_alpha);
629 : 4726 : union_dr = cube_union_v0(datum_r, datum_alpha);
8354 tgl@sss.pgh.pa.us 630 : 4726 : rt_cube_size(union_dl, &size_alpha);
631 : 4726 : rt_cube_size(union_dr, &size_beta);
632 : :
633 : : /* pick which page to add it to */
8424 bruce@momjian.us 634 [ + + ]: 4726 : if (size_alpha - size_l < size_beta - size_r)
635 : : {
636 : 2275 : datum_l = union_dl;
637 : 2275 : size_l = size_alpha;
638 : 2275 : *left++ = i;
639 : 2275 : v->spl_nleft++;
640 : : }
641 : : else
642 : : {
643 : 2451 : datum_r = union_dr;
4900 rhaas@postgresql.org 644 : 2451 : size_r = size_beta;
8424 bruce@momjian.us 645 : 2451 : *right++ = i;
646 : 2451 : v->spl_nright++;
647 : : }
648 : : }
1742 michael@paquier.xyz 649 : 34 : *left = *right = FirstOffsetNumber; /* sentinel value */
650 : :
8354 tgl@sss.pgh.pa.us 651 : 34 : v->spl_ldatum = PointerGetDatum(datum_l);
652 : 34 : v->spl_rdatum = PointerGetDatum(datum_r);
653 : :
6473 bruce@momjian.us 654 : 34 : PG_RETURN_POINTER(v);
655 : : }
656 : :
657 : : /*
658 : : ** Equality method
659 : : */
660 : : Datum
661 : 2962 : g_cube_same(PG_FUNCTION_ARGS)
662 : : {
2400 tgl@sss.pgh.pa.us 663 : 2962 : NDBOX *b1 = PG_GETARG_NDBOX_P(0);
664 : 2962 : NDBOX *b2 = PG_GETARG_NDBOX_P(1);
5799 665 : 2962 : bool *result = (bool *) PG_GETARG_POINTER(2);
666 : :
6473 bruce@momjian.us 667 [ + + ]: 2962 : if (cube_cmp_v0(b1, b2) == 0)
2433 peter_e@gmx.net 668 : 2807 : *result = true;
669 : : else
670 : 155 : *result = false;
671 : :
2400 tgl@sss.pgh.pa.us 672 : 2962 : PG_RETURN_NDBOX_P(result);
673 : : }
674 : :
675 : : /*
676 : : ** SUPPORT ROUTINES
677 : : */
678 : : bool
5421 bruce@momjian.us 679 : 144 : g_cube_leaf_consistent(NDBOX *key,
680 : : NDBOX *query,
681 : : StrategyNumber strategy)
682 : : {
683 : : bool retval;
684 : :
8424 685 [ + - - + : 144 : switch (strategy)
- ]
686 : : {
687 : 96 : case RTOverlapStrategyNumber:
2432 peter_e@gmx.net 688 : 96 : retval = cube_overlap_v0(key, query);
8424 bruce@momjian.us 689 : 96 : break;
8424 bruce@momjian.us 690 :UBC 0 : case RTSameStrategyNumber:
2432 peter_e@gmx.net 691 : 0 : retval = (cube_cmp_v0(key, query) == 0);
8424 bruce@momjian.us 692 : 0 : break;
693 : 0 : case RTContainsStrategyNumber:
694 : : case RTOldContainsStrategyNumber:
2432 peter_e@gmx.net 695 : 0 : retval = cube_contains_v0(key, query);
8424 bruce@momjian.us 696 : 0 : break;
8424 bruce@momjian.us 697 :CBC 48 : case RTContainedByStrategyNumber:
698 : : case RTOldContainedByStrategyNumber:
2432 peter_e@gmx.net 699 : 48 : retval = cube_contains_v0(query, key);
8424 bruce@momjian.us 700 : 48 : break;
8424 bruce@momjian.us 701 :UBC 0 : default:
2433 peter_e@gmx.net 702 : 0 : retval = false;
703 : : }
2432 peter_e@gmx.net 704 :CBC 144 : return retval;
705 : : }
706 : :
707 : : bool
5421 bruce@momjian.us 708 : 105 : g_cube_internal_consistent(NDBOX *key,
709 : : NDBOX *query,
710 : : StrategyNumber strategy)
711 : : {
712 : : bool retval;
713 : :
8424 714 [ + - + - ]: 105 : switch (strategy)
715 : : {
716 : 70 : case RTOverlapStrategyNumber:
6473 717 : 70 : retval = (bool) cube_overlap_v0(key, query);
8424 718 : 70 : break;
8424 bruce@momjian.us 719 :UBC 0 : case RTSameStrategyNumber:
720 : : case RTContainsStrategyNumber:
721 : : case RTOldContainsStrategyNumber:
6473 722 : 0 : retval = (bool) cube_contains_v0(key, query);
8424 723 : 0 : break;
8424 bruce@momjian.us 724 :CBC 35 : case RTContainedByStrategyNumber:
725 : : case RTOldContainedByStrategyNumber:
6473 726 : 35 : retval = (bool) cube_overlap_v0(key, query);
8424 727 : 35 : break;
8424 bruce@momjian.us 728 :UBC 0 : default:
2433 peter_e@gmx.net 729 : 0 : retval = false;
730 : : }
2432 peter_e@gmx.net 731 :CBC 105 : return retval;
732 : : }
733 : :
734 : : NDBOX *
5421 bruce@momjian.us 735 : 2962 : g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
736 : : {
737 : : NDBOX *retval;
738 : :
6473 739 : 2962 : retval = cube_union_v0(r1, r2);
6256 tgl@sss.pgh.pa.us 740 : 2962 : *sizep = VARSIZE(retval);
741 : :
2432 peter_e@gmx.net 742 : 2962 : return retval;
743 : : }
744 : :
745 : :
746 : : /* cube_union_v0 */
747 : : NDBOX *
5421 bruce@momjian.us 748 : 386292 : cube_union_v0(NDBOX *a, NDBOX *b)
749 : : {
750 : : int i;
751 : : NDBOX *result;
752 : : int dim;
753 : : int size;
754 : :
755 : : /* trivial case */
3828 heikki.linnakangas@i 756 [ + + ]: 386292 : if (a == b)
757 : 68 : return a;
758 : :
759 : : /* swap the arguments if needed, so that 'a' is always larger than 'b' */
760 [ + + ]: 386224 : if (DIM(a) < DIM(b))
761 : : {
8424 bruce@momjian.us 762 : 3 : NDBOX *tmp = b;
763 : :
764 : 3 : b = a;
765 : 3 : a = tmp;
766 : : }
3828 heikki.linnakangas@i 767 : 386224 : dim = DIM(a);
768 : :
769 : 386224 : size = CUBE_SIZE(dim);
770 : 386224 : result = palloc0(size);
771 : 386224 : SET_VARSIZE(result, size);
772 : 386224 : SET_DIM(result, dim);
773 : :
774 : : /* First compute the union of the dimensions present in both args */
775 [ + + ]: 1158636 : for (i = 0; i < DIM(b); i++)
776 : : {
1536 alvherre@alvh.no-ip. 777 [ + + + + : 772412 : result->x[i] = Min(Min(LL_COORD(a, i), UR_COORD(a, i)),
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + ]
778 : : Min(LL_COORD(b, i), UR_COORD(b, i)));
779 [ + + + + : 772412 : result->x[i + DIM(a)] = Max(Max(LL_COORD(a, i), UR_COORD(a, i)),
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + ]
780 : : Max(LL_COORD(b, i), UR_COORD(b, i)));
781 : : }
782 : : /* continue on the higher dimensions only present in 'a' */
3828 heikki.linnakangas@i 783 [ + + ]: 386264 : for (; i < DIM(a); i++)
784 : : {
785 [ + + + - : 40 : result->x[i] = Min(0,
+ - + + -
+ - - +
- ]
786 : : Min(LL_COORD(a, i), UR_COORD(a, i))
787 : : );
788 [ + + - + : 40 : result->x[i + dim] = Max(0,
+ + - + +
+ - + +
+ ]
789 : : 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 : : */
797 [ + + ]: 386224 : if (cube_is_point_internal(result))
798 : : {
799 : 2 : size = POINT_SIZE(dim);
800 : 2 : SET_VARSIZE(result, size);
801 : 2 : SET_POINT_BIT(result);
802 : : }
803 : :
2432 peter_e@gmx.net 804 : 386224 : return result;
805 : : }
806 : :
807 : : Datum
6402 bruce@momjian.us 808 : 5 : cube_union(PG_FUNCTION_ARGS)
809 : : {
2400 tgl@sss.pgh.pa.us 810 : 5 : NDBOX *a = PG_GETARG_NDBOX_P(0);
811 : 5 : NDBOX *b = PG_GETARG_NDBOX_P(1);
812 : : NDBOX *res;
813 : :
6248 teodor@sigaev.ru 814 : 5 : res = cube_union_v0(a, b);
815 : :
5995 bruce@momjian.us 816 [ - + ]: 5 : PG_FREE_IF_COPY(a, 0);
817 [ - + ]: 5 : PG_FREE_IF_COPY(b, 1);
2400 tgl@sss.pgh.pa.us 818 : 5 : PG_RETURN_NDBOX_P(res);
819 : : }
820 : :
821 : : /* cube_inter */
822 : : Datum
6473 bruce@momjian.us 823 : 330827 : cube_inter(PG_FUNCTION_ARGS)
824 : : {
2400 tgl@sss.pgh.pa.us 825 : 330827 : NDBOX *a = PG_GETARG_NDBOX_P(0);
826 : 330827 : NDBOX *b = PG_GETARG_NDBOX_P(1);
827 : : NDBOX *result;
5799 828 : 330827 : bool swapped = false;
829 : : int i;
830 : : int dim;
831 : : int size;
832 : :
833 : : /* swap the arguments if needed, so that 'a' is always larger than 'b' */
3828 heikki.linnakangas@i 834 [ - + ]: 330827 : if (DIM(a) < DIM(b))
835 : : {
8424 bruce@momjian.us 836 :UBC 0 : NDBOX *tmp = b;
837 : :
838 : 0 : b = a;
839 : 0 : a = tmp;
5799 tgl@sss.pgh.pa.us 840 : 0 : swapped = true;
841 : : }
3828 heikki.linnakangas@i 842 :CBC 330827 : dim = DIM(a);
843 : :
844 : 330827 : size = CUBE_SIZE(dim);
845 : 330827 : result = (NDBOX *) palloc0(size);
846 : 330827 : SET_VARSIZE(result, size);
847 : 330827 : SET_DIM(result, dim);
848 : :
849 : : /* First compute intersection of the dimensions present in both args */
850 [ + + ]: 992483 : for (i = 0; i < DIM(b); i++)
851 : : {
1536 alvherre@alvh.no-ip. 852 [ + + + + : 661656 : result->x[i] = Max(Min(LL_COORD(a, i), UR_COORD(a, i)),
+ + + + +
+ + + + +
+ - - + -
+ + + + +
+ + ]
853 : : Min(LL_COORD(b, i), UR_COORD(b, i)));
854 [ + + + + : 661656 : result->x[i + DIM(a)] = Min(Max(LL_COORD(a, i), UR_COORD(a, i)),
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + ]
855 : : Max(LL_COORD(b, i), UR_COORD(b, i)));
856 : : }
857 : : /* continue on the higher dimensions only present in 'a' */
3828 heikki.linnakangas@i 858 [ - + ]: 330827 : for (; i < DIM(a); i++)
859 : : {
3828 heikki.linnakangas@i 860 [ # # # # :UBC 0 : result->x[i] = Max(0,
# # # # #
# # # #
# ]
861 : : Min(LL_COORD(a, i), UR_COORD(a, i))
862 : : );
863 [ # # # # : 0 : result->x[i + DIM(a)] = Min(0,
# # # # #
# # # #
# ]
864 : : 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 : : */
3828 heikki.linnakangas@i 872 [ + + ]:CBC 330827 : if (cube_is_point_internal(result))
873 : : {
874 : 2 : size = POINT_SIZE(dim);
875 : 2 : result = repalloc(result, size);
876 : 2 : SET_VARSIZE(result, size);
877 : 2 : SET_POINT_BIT(result);
878 : : }
879 : :
5799 tgl@sss.pgh.pa.us 880 [ - + ]: 330827 : if (swapped)
881 : : {
5799 tgl@sss.pgh.pa.us 882 [ # # ]:UBC 0 : PG_FREE_IF_COPY(b, 0);
883 [ # # ]: 0 : PG_FREE_IF_COPY(a, 1);
884 : : }
885 : : else
886 : : {
5799 tgl@sss.pgh.pa.us 887 [ - + ]:CBC 330827 : PG_FREE_IF_COPY(a, 0);
888 [ - + ]: 330827 : PG_FREE_IF_COPY(b, 1);
889 : : }
890 : :
891 : : /*
892 : : * Is it OK to return a non-null intersection for non-overlapping boxes?
893 : : */
2400 894 : 330827 : PG_RETURN_NDBOX_P(result);
895 : : }
896 : :
897 : : /* cube_size */
898 : : Datum
6473 bruce@momjian.us 899 : 2 : cube_size(PG_FUNCTION_ARGS)
900 : : {
2400 tgl@sss.pgh.pa.us 901 : 2 : NDBOX *a = PG_GETARG_NDBOX_P(0);
902 : : double result;
903 : :
2756 904 : 2 : rt_cube_size(a, &result);
5995 bruce@momjian.us 905 [ - + ]: 2 : PG_FREE_IF_COPY(a, 0);
6402 906 : 2 : PG_RETURN_FLOAT8(result);
907 : : }
908 : :
909 : : void
5421 910 : 757132 : rt_cube_size(NDBOX *a, double *size)
911 : : {
912 : : double result;
913 : : int i;
914 : :
8424 915 [ - + ]: 757132 : if (a == (NDBOX *) NULL)
916 : : {
917 : : /* special case for GiST */
2756 tgl@sss.pgh.pa.us 918 :UBC 0 : result = 0.0;
919 : : }
2756 tgl@sss.pgh.pa.us 920 [ + + - + ]:CBC 757132 : else if (IS_POINT(a) || DIM(a) == 0)
921 : : {
922 : : /* necessarily has zero size */
923 : 1 : result = 0.0;
924 : : }
925 : : else
926 : : {
927 : 757131 : result = 1.0;
3828 heikki.linnakangas@i 928 [ + + ]: 2271393 : for (i = 0; i < DIM(a); i++)
555 peter@eisentraut.org 929 [ - + ]: 1514262 : result *= fabs(UR_COORD(a, i) - LL_COORD(a, i));
930 : : }
2756 tgl@sss.pgh.pa.us 931 : 757132 : *size = result;
8525 932 : 757132 : }
933 : :
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
5421 bruce@momjian.us 937 : 3010 : cube_cmp_v0(NDBOX *a, NDBOX *b)
938 : : {
939 : : int i;
940 : : int dim;
941 : :
3828 heikki.linnakangas@i 942 : 3010 : dim = Min(DIM(a), DIM(b));
943 : :
944 : : /* compare the common dimensions */
8424 bruce@momjian.us 945 [ + + ]: 8859 : for (i = 0; i < dim; i++)
946 : : {
3828 heikki.linnakangas@i 947 [ + + + + : 11912 : if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
+ + + + ]
948 [ + + + + : 5956 : Min(LL_COORD(b, i), UR_COORD(b, i)))
+ + ]
7518 tgl@sss.pgh.pa.us 949 : 92 : return 1;
3828 heikki.linnakangas@i 950 [ + + + + : 11728 : if (Min(LL_COORD(a, i), UR_COORD(a, i)) <
+ + + + ]
951 [ + + + + : 5864 : Min(LL_COORD(b, i), UR_COORD(b, i)))
+ + ]
7518 tgl@sss.pgh.pa.us 952 : 15 : return -1;
953 : : }
8424 bruce@momjian.us 954 [ + + ]: 8589 : for (i = 0; i < dim; i++)
955 : : {
3828 heikki.linnakangas@i 956 [ + + - + : 11532 : if (Max(LL_COORD(a, i), UR_COORD(a, i)) >
+ + - + ]
957 [ + + - + : 5766 : Max(LL_COORD(b, i), UR_COORD(b, i)))
+ + ]
7518 tgl@sss.pgh.pa.us 958 :UBC 0 : return 1;
3828 heikki.linnakangas@i 959 [ + + - + :CBC 11532 : if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
+ + + + ]
960 [ + + - + : 5766 : Max(LL_COORD(b, i), UR_COORD(b, i)))
+ + ]
7518 tgl@sss.pgh.pa.us 961 : 80 : return -1;
962 : : }
963 : :
964 : : /* compare extra dimensions to zero */
3828 heikki.linnakangas@i 965 [ + + ]: 2823 : if (DIM(a) > DIM(b))
966 : : {
967 [ + + ]: 24 : for (i = dim; i < DIM(a); i++)
968 : : {
969 [ + - + + : 18 : if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
- + - + ]
7518 tgl@sss.pgh.pa.us 970 :UBC 0 : return 1;
3828 heikki.linnakangas@i 971 [ + - + + :CBC 18 : if (Min(LL_COORD(a, i), UR_COORD(a, i)) < 0)
- + - + ]
7518 tgl@sss.pgh.pa.us 972 :UBC 0 : return -1;
973 : : }
3828 heikki.linnakangas@i 974 [ + + ]:CBC 20 : for (i = dim; i < DIM(a); i++)
975 : : {
976 [ + - + + : 18 : if (Max(LL_COORD(a, i), UR_COORD(a, i)) > 0)
- + + + ]
7518 tgl@sss.pgh.pa.us 977 : 4 : return 1;
3828 heikki.linnakangas@i 978 [ + - - + : 14 : if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
- + - + ]
7518 tgl@sss.pgh.pa.us 979 :UBC 0 : return -1;
980 : : }
981 : :
982 : : /*
983 : : * if all common dimensions are equal, the cube with more dimensions
984 : : * wins
985 : : */
7518 tgl@sss.pgh.pa.us 986 :CBC 2 : return 1;
987 : : }
3828 heikki.linnakangas@i 988 [ + + ]: 2817 : if (DIM(a) < DIM(b))
989 : : {
990 [ + + ]: 32 : for (i = dim; i < DIM(b); i++)
991 : : {
992 [ + - + + : 24 : if (Min(LL_COORD(b, i), UR_COORD(b, i)) > 0)
- + - + ]
7518 tgl@sss.pgh.pa.us 993 :UBC 0 : return -1;
3828 heikki.linnakangas@i 994 [ + - + + :CBC 24 : if (Min(LL_COORD(b, i), UR_COORD(b, i)) < 0)
- + - + ]
7518 tgl@sss.pgh.pa.us 995 :UBC 0 : return 1;
996 : : }
3828 heikki.linnakangas@i 997 [ + + ]:CBC 27 : for (i = dim; i < DIM(b); i++)
998 : : {
999 [ + - + + : 24 : if (Max(LL_COORD(b, i), UR_COORD(b, i)) > 0)
- + + + ]
7518 tgl@sss.pgh.pa.us 1000 : 5 : return -1;
3828 heikki.linnakangas@i 1001 [ + - - + : 19 : if (Max(LL_COORD(b, i), UR_COORD(b, i)) < 0)
- + - + ]
7518 tgl@sss.pgh.pa.us 1002 :UBC 0 : return 1;
1003 : : }
1004 : :
1005 : : /*
1006 : : * if all common dimensions are equal, the cube with more dimensions
1007 : : * wins
1008 : : */
7518 tgl@sss.pgh.pa.us 1009 :CBC 3 : return -1;
1010 : : }
1011 : :
1012 : : /* They're really equal */
1013 : 2809 : return 0;
1014 : : }
1015 : :
1016 : : Datum
6473 bruce@momjian.us 1017 : 22 : cube_cmp(PG_FUNCTION_ARGS)
1018 : : {
2400 tgl@sss.pgh.pa.us 1019 : 22 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1020 : 22 : *b = PG_GETARG_NDBOX_P(1);
1021 : : int32 res;
1022 : :
6248 teodor@sigaev.ru 1023 : 22 : res = cube_cmp_v0(a, b);
1024 : :
5995 bruce@momjian.us 1025 [ - + ]: 22 : PG_FREE_IF_COPY(a, 0);
1026 [ - + ]: 22 : PG_FREE_IF_COPY(b, 1);
6248 teodor@sigaev.ru 1027 : 22 : PG_RETURN_INT32(res);
1028 : : }
1029 : :
1030 : :
1031 : : Datum
6473 bruce@momjian.us 1032 : 8 : cube_eq(PG_FUNCTION_ARGS)
1033 : : {
2400 tgl@sss.pgh.pa.us 1034 : 8 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1035 : 8 : *b = PG_GETARG_NDBOX_P(1);
1036 : : int32 res;
1037 : :
6248 teodor@sigaev.ru 1038 : 8 : res = cube_cmp_v0(a, b);
1039 : :
5995 bruce@momjian.us 1040 [ - + ]: 8 : PG_FREE_IF_COPY(a, 0);
1041 [ - + ]: 8 : PG_FREE_IF_COPY(b, 1);
6248 teodor@sigaev.ru 1042 : 8 : PG_RETURN_BOOL(res == 0);
1043 : : }
1044 : :
1045 : :
1046 : : Datum
6473 bruce@momjian.us 1047 : 2 : cube_ne(PG_FUNCTION_ARGS)
1048 : : {
2400 tgl@sss.pgh.pa.us 1049 : 2 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1050 : 2 : *b = PG_GETARG_NDBOX_P(1);
1051 : : int32 res;
1052 : :
6248 teodor@sigaev.ru 1053 : 2 : res = cube_cmp_v0(a, b);
1054 : :
5995 bruce@momjian.us 1055 [ - + ]: 2 : PG_FREE_IF_COPY(a, 0);
1056 [ - + ]: 2 : PG_FREE_IF_COPY(b, 1);
6248 teodor@sigaev.ru 1057 : 2 : PG_RETURN_BOOL(res != 0);
1058 : : }
1059 : :
1060 : :
1061 : : Datum
6473 bruce@momjian.us 1062 : 8 : cube_lt(PG_FUNCTION_ARGS)
1063 : : {
2400 tgl@sss.pgh.pa.us 1064 : 8 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1065 : 8 : *b = PG_GETARG_NDBOX_P(1);
1066 : : int32 res;
1067 : :
6248 teodor@sigaev.ru 1068 : 8 : res = cube_cmp_v0(a, b);
1069 : :
5995 bruce@momjian.us 1070 [ - + ]: 8 : PG_FREE_IF_COPY(a, 0);
1071 [ - + ]: 8 : PG_FREE_IF_COPY(b, 1);
6248 teodor@sigaev.ru 1072 : 8 : PG_RETURN_BOOL(res < 0);
1073 : : }
1074 : :
1075 : :
1076 : : Datum
6473 bruce@momjian.us 1077 : 8 : cube_gt(PG_FUNCTION_ARGS)
1078 : : {
2400 tgl@sss.pgh.pa.us 1079 : 8 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1080 : 8 : *b = PG_GETARG_NDBOX_P(1);
1081 : : int32 res;
1082 : :
6248 teodor@sigaev.ru 1083 : 8 : res = cube_cmp_v0(a, b);
1084 : :
5995 bruce@momjian.us 1085 [ - + ]: 8 : PG_FREE_IF_COPY(a, 0);
1086 [ - + ]: 8 : PG_FREE_IF_COPY(b, 1);
6248 teodor@sigaev.ru 1087 : 8 : PG_RETURN_BOOL(res > 0);
1088 : : }
1089 : :
1090 : :
1091 : : Datum
6473 bruce@momjian.us 1092 :UBC 0 : cube_le(PG_FUNCTION_ARGS)
1093 : : {
2400 tgl@sss.pgh.pa.us 1094 : 0 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1095 : 0 : *b = PG_GETARG_NDBOX_P(1);
1096 : : int32 res;
1097 : :
6248 teodor@sigaev.ru 1098 : 0 : res = cube_cmp_v0(a, b);
1099 : :
5995 bruce@momjian.us 1100 [ # # ]: 0 : PG_FREE_IF_COPY(a, 0);
1101 [ # # ]: 0 : PG_FREE_IF_COPY(b, 1);
6248 teodor@sigaev.ru 1102 : 0 : PG_RETURN_BOOL(res <= 0);
1103 : : }
1104 : :
1105 : :
1106 : : Datum
6473 bruce@momjian.us 1107 : 0 : cube_ge(PG_FUNCTION_ARGS)
1108 : : {
2400 tgl@sss.pgh.pa.us 1109 : 0 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1110 : 0 : *b = PG_GETARG_NDBOX_P(1);
1111 : : int32 res;
1112 : :
6248 teodor@sigaev.ru 1113 : 0 : res = cube_cmp_v0(a, b);
1114 : :
5995 bruce@momjian.us 1115 [ # # ]: 0 : PG_FREE_IF_COPY(a, 0);
1116 [ # # ]: 0 : PG_FREE_IF_COPY(b, 1);
6248 teodor@sigaev.ru 1117 : 0 : PG_RETURN_BOOL(res >= 0);
1118 : : }
1119 : :
1120 : :
1121 : : /* Contains */
1122 : : /* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */
1123 : : bool
5421 bruce@momjian.us 1124 :CBC 94 : cube_contains_v0(NDBOX *a, NDBOX *b)
1125 : : {
1126 : : int i;
1127 : :
7899 1128 [ + - - + ]: 94 : if ((a == NULL) || (b == NULL))
2433 peter_e@gmx.net 1129 :UBC 0 : return false;
1130 : :
3828 heikki.linnakangas@i 1131 [ - + ]:CBC 94 : if (DIM(a) < DIM(b))
1132 : : {
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 : : */
3828 heikki.linnakangas@i 1138 [ # # ]:UBC 0 : for (i = DIM(a); i < DIM(b); i++)
1139 : : {
1140 [ # # ]: 0 : if (LL_COORD(b, i) != 0)
2433 peter_e@gmx.net 1141 : 0 : return false;
3828 heikki.linnakangas@i 1142 [ # # # # ]: 0 : if (UR_COORD(b, i) != 0)
2433 peter_e@gmx.net 1143 : 0 : return false;
1144 : : }
1145 : : }
1146 : :
1147 : : /* Can't care less about the excess dimensions of (a), if any */
3828 heikki.linnakangas@i 1148 [ + + ]:CBC 190 : for (i = 0; i < Min(DIM(a), DIM(b)); i++)
1149 : : {
1150 [ + + + + : 312 : if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
+ + + + ]
1151 [ + + + + : 156 : Min(LL_COORD(b, i), UR_COORD(b, i)))
+ + ]
2433 peter_e@gmx.net 1152 : 7 : return false;
3828 heikki.linnakangas@i 1153 [ + + + + : 298 : if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
+ + + + ]
1154 [ + + + + : 149 : Max(LL_COORD(b, i), UR_COORD(b, i)))
+ + ]
2433 peter_e@gmx.net 1155 : 53 : return false;
1156 : : }
1157 : :
1158 : 34 : return true;
1159 : : }
1160 : :
1161 : : Datum
6473 bruce@momjian.us 1162 : 31 : cube_contains(PG_FUNCTION_ARGS)
1163 : : {
2400 tgl@sss.pgh.pa.us 1164 : 31 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1165 : 31 : *b = PG_GETARG_NDBOX_P(1);
1166 : : bool res;
1167 : :
6248 teodor@sigaev.ru 1168 : 31 : res = cube_contains_v0(a, b);
1169 : :
5995 bruce@momjian.us 1170 [ - + ]: 31 : PG_FREE_IF_COPY(a, 0);
1171 [ - + ]: 31 : PG_FREE_IF_COPY(b, 1);
6248 teodor@sigaev.ru 1172 : 31 : PG_RETURN_BOOL(res);
1173 : : }
1174 : :
1175 : : /* Contained */
1176 : : /* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */
1177 : : Datum
6473 bruce@momjian.us 1178 : 15 : cube_contained(PG_FUNCTION_ARGS)
1179 : : {
2400 tgl@sss.pgh.pa.us 1180 : 15 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1181 : 15 : *b = PG_GETARG_NDBOX_P(1);
1182 : : bool res;
1183 : :
6248 teodor@sigaev.ru 1184 : 15 : res = cube_contains_v0(b, a);
1185 : :
5995 bruce@momjian.us 1186 [ - + ]: 15 : PG_FREE_IF_COPY(a, 0);
1187 [ - + ]: 15 : PG_FREE_IF_COPY(b, 1);
6248 teodor@sigaev.ru 1188 : 15 : PG_RETURN_BOOL(res);
1189 : : }
1190 : :
1191 : : /* Overlap */
1192 : : /* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */
1193 : : bool
5421 bruce@momjian.us 1194 : 209 : cube_overlap_v0(NDBOX *a, NDBOX *b)
1195 : : {
1196 : : int i;
1197 : :
7899 1198 [ + - - + ]: 209 : if ((a == NULL) || (b == NULL))
2433 peter_e@gmx.net 1199 :UBC 0 : return false;
1200 : :
1201 : : /* swap the box pointers if needed */
3828 heikki.linnakangas@i 1202 [ - + ]:CBC 209 : if (DIM(a) < DIM(b))
1203 : : {
8424 bruce@momjian.us 1204 :UBC 0 : NDBOX *tmp = b;
1205 : :
1206 : 0 : b = a;
1207 : 0 : a = tmp;
1208 : : }
1209 : :
1210 : : /* compare within the dimensions of (b) */
3828 heikki.linnakangas@i 1211 [ + + ]:CBC 287 : for (i = 0; i < DIM(b); i++)
1212 : : {
1213 [ + + + + : 268 : if (Min(LL_COORD(a, i), UR_COORD(a, i)) > Max(LL_COORD(b, i), UR_COORD(b, i)))
+ + + + +
+ + + +
+ ]
2433 peter_e@gmx.net 1214 : 188 : return false;
3828 heikki.linnakangas@i 1215 [ + + + + : 80 : if (Max(LL_COORD(a, i), UR_COORD(a, i)) < Min(LL_COORD(b, i), UR_COORD(b, i)))
+ + + + +
+ + + +
+ ]
2433 peter_e@gmx.net 1216 : 2 : return false;
1217 : : }
1218 : :
1219 : : /* compare to zero those dimensions in (a) absent in (b) */
3828 heikki.linnakangas@i 1220 [ + + ]: 24 : for (i = DIM(b); i < DIM(a); i++)
1221 : : {
1222 [ + - + - : 5 : if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
- - - + ]
2433 peter_e@gmx.net 1223 :UBC 0 : return false;
3828 heikki.linnakangas@i 1224 [ + - - + :CBC 5 : if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
- + - + ]
2433 peter_e@gmx.net 1225 :UBC 0 : return false;
1226 : : }
1227 : :
2433 peter_e@gmx.net 1228 :CBC 19 : return true;
1229 : : }
1230 : :
1231 : :
1232 : : Datum
6473 bruce@momjian.us 1233 : 8 : cube_overlap(PG_FUNCTION_ARGS)
1234 : : {
2400 tgl@sss.pgh.pa.us 1235 : 8 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1236 : 8 : *b = PG_GETARG_NDBOX_P(1);
1237 : : bool res;
1238 : :
6248 teodor@sigaev.ru 1239 : 8 : res = cube_overlap_v0(a, b);
1240 : :
5995 bruce@momjian.us 1241 [ - + ]: 8 : PG_FREE_IF_COPY(a, 0);
1242 [ - + ]: 8 : PG_FREE_IF_COPY(b, 1);
6248 teodor@sigaev.ru 1243 : 8 : PG_RETURN_BOOL(res);
1244 : : }
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
6473 bruce@momjian.us 1253 : 3423 : cube_distance(PG_FUNCTION_ARGS)
1254 : : {
2400 tgl@sss.pgh.pa.us 1255 : 3423 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1256 : 3423 : *b = PG_GETARG_NDBOX_P(1);
5799 1257 : 3423 : bool swapped = false;
1258 : : double d,
1259 : : distance;
1260 : : int i;
1261 : :
1262 : : /* swap the box pointers if needed */
3828 heikki.linnakangas@i 1263 [ + + ]: 3423 : if (DIM(a) < DIM(b))
1264 : : {
8424 bruce@momjian.us 1265 : 3 : NDBOX *tmp = b;
1266 : :
1267 : 3 : b = a;
1268 : 3 : a = tmp;
5799 tgl@sss.pgh.pa.us 1269 : 3 : swapped = true;
1270 : : }
1271 : :
8424 bruce@momjian.us 1272 : 3423 : distance = 0.0;
1273 : : /* compute within the dimensions of (b) */
3828 heikki.linnakangas@i 1274 [ + + ]: 10102 : for (i = 0; i < DIM(b); i++)
1275 : : {
3631 bruce@momjian.us 1276 [ + + + + ]: 6679 : d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), LL_COORD(b, i), UR_COORD(b, i));
8424 1277 : 6679 : distance += d * d;
1278 : : }
1279 : :
1280 : : /* compute distance to zero for those dimensions in (a) absent in (b) */
3828 heikki.linnakangas@i 1281 [ + + ]: 3819 : for (i = DIM(b); i < DIM(a); i++)
1282 : : {
3631 bruce@momjian.us 1283 [ + + ]: 396 : d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0);
8424 1284 : 396 : distance += d * d;
1285 : : }
1286 : :
5799 tgl@sss.pgh.pa.us 1287 [ + + ]: 3423 : if (swapped)
1288 : : {
1289 [ - + ]: 3 : PG_FREE_IF_COPY(b, 0);
1290 [ - + ]: 3 : PG_FREE_IF_COPY(a, 1);
1291 : : }
1292 : : else
1293 : : {
1294 [ - + ]: 3420 : PG_FREE_IF_COPY(a, 0);
1295 [ - + ]: 3420 : PG_FREE_IF_COPY(b, 1);
1296 : : }
1297 : :
6473 bruce@momjian.us 1298 : 3423 : PG_RETURN_FLOAT8(sqrt(distance));
1299 : : }
1300 : :
1301 : : Datum
3040 teodor@sigaev.ru 1302 : 3195 : distance_taxicab(PG_FUNCTION_ARGS)
1303 : : {
2400 tgl@sss.pgh.pa.us 1304 : 3195 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1305 : 3195 : *b = PG_GETARG_NDBOX_P(1);
3040 teodor@sigaev.ru 1306 : 3195 : bool swapped = false;
1307 : : double distance;
1308 : : int i;
1309 : :
1310 : : /* swap the box pointers if needed */
1311 [ + + ]: 3195 : if (DIM(a) < DIM(b))
1312 : : {
1313 : 1 : NDBOX *tmp = b;
1314 : :
1315 : 1 : b = a;
1316 : 1 : a = tmp;
1317 : 1 : swapped = true;
1318 : : }
1319 : :
1320 : 3195 : distance = 0.0;
1321 : : /* compute within the dimensions of (b) */
1322 [ + + ]: 9584 : for (i = 0; i < DIM(b); i++)
3030 tgl@sss.pgh.pa.us 1323 [ + + ]: 6389 : distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1324 [ + + ]: 6389 : LL_COORD(b, i), UR_COORD(b, i)));
1325 : :
1326 : : /* compute distance to zero for those dimensions in (a) absent in (b) */
3040 teodor@sigaev.ru 1327 [ + + ]: 3196 : for (i = DIM(b); i < DIM(a); i++)
3030 tgl@sss.pgh.pa.us 1328 [ - + ]: 1 : distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1329 : : 0.0, 0.0));
1330 : :
3040 teodor@sigaev.ru 1331 [ + + ]: 3195 : if (swapped)
1332 : : {
1333 [ - + ]: 1 : PG_FREE_IF_COPY(b, 0);
1334 [ - + ]: 1 : PG_FREE_IF_COPY(a, 1);
1335 : : }
1336 : : else
1337 : : {
1338 [ - + ]: 3194 : PG_FREE_IF_COPY(a, 0);
1339 [ - + ]: 3194 : PG_FREE_IF_COPY(b, 1);
1340 : : }
1341 : :
1342 : 3195 : PG_RETURN_FLOAT8(distance);
1343 : : }
1344 : :
1345 : : Datum
1346 : 3195 : distance_chebyshev(PG_FUNCTION_ARGS)
1347 : : {
2400 tgl@sss.pgh.pa.us 1348 : 3195 : NDBOX *a = PG_GETARG_NDBOX_P(0),
1349 : 3195 : *b = PG_GETARG_NDBOX_P(1);
3040 teodor@sigaev.ru 1350 : 3195 : bool swapped = false;
1351 : : double d,
1352 : : distance;
1353 : : int i;
1354 : :
1355 : : /* swap the box pointers if needed */
1356 [ + + ]: 3195 : if (DIM(a) < DIM(b))
1357 : : {
1358 : 1 : NDBOX *tmp = b;
1359 : :
1360 : 1 : b = a;
1361 : 1 : a = tmp;
1362 : 1 : swapped = true;
1363 : : }
1364 : :
1365 : 3195 : distance = 0.0;
1366 : : /* compute within the dimensions of (b) */
1367 [ + + ]: 9584 : for (i = 0; i < DIM(b); i++)
1368 : : {
3030 tgl@sss.pgh.pa.us 1369 [ + + ]: 6389 : d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
1370 [ + + ]: 6389 : LL_COORD(b, i), UR_COORD(b, i)));
3040 teodor@sigaev.ru 1371 [ + + ]: 6389 : if (d > distance)
1372 : 4720 : distance = d;
1373 : : }
1374 : :
1375 : : /* compute distance to zero for those dimensions in (a) absent in (b) */
1376 [ + + ]: 3196 : for (i = DIM(b); i < DIM(a); i++)
1377 : : {
3030 tgl@sss.pgh.pa.us 1378 [ - + ]: 1 : d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0));
3040 teodor@sigaev.ru 1379 [ - + ]: 1 : if (d > distance)
3040 teodor@sigaev.ru 1380 :UBC 0 : distance = d;
1381 : : }
1382 : :
3040 teodor@sigaev.ru 1383 [ + + ]:CBC 3195 : if (swapped)
1384 : : {
1385 [ - + ]: 1 : PG_FREE_IF_COPY(b, 0);
1386 [ - + ]: 1 : PG_FREE_IF_COPY(a, 1);
1387 : : }
1388 : : else
1389 : : {
1390 [ - + ]: 3194 : PG_FREE_IF_COPY(a, 0);
1391 [ - + ]: 3194 : PG_FREE_IF_COPY(b, 1);
1392 : : }
1393 : :
1394 : 3195 : PG_RETURN_FLOAT8(distance);
1395 : : }
1396 : :
1397 : : Datum
1398 : 4121 : g_cube_distance(PG_FUNCTION_ARGS)
1399 : : {
1400 : 4121 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1401 : 4121 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
2400 tgl@sss.pgh.pa.us 1402 : 4121 : NDBOX *cube = DatumGetNDBOXP(entry->key);
1403 : : double retval;
1404 : :
3040 teodor@sigaev.ru 1405 [ + + ]: 4121 : if (strategy == CubeKNNDistanceCoord)
1406 : : {
1407 : : /*
1408 : : * Handle ordering by ~> operator. See comments of cube_coord_llur()
1409 : : * for details
1410 : : */
3030 tgl@sss.pgh.pa.us 1411 : 3869 : int coord = PG_GETARG_INT32(1);
2285 teodor@sigaev.ru 1412 : 3869 : bool isLeaf = GistPageIsLeaf(entry->page);
1413 : 3869 : bool inverse = false;
1414 : :
1415 : : /* 0 is the only unsupported coordinate value */
1416 [ - + ]: 3869 : if (coord == 0)
2285 teodor@sigaev.ru 1417 [ # # ]:UBC 0 : ereport(ERROR,
1418 : : (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
1419 : : errmsg("zero cube index is not defined")));
1420 : :
1421 : : /* Return inversed value for negative coordinate */
2285 teodor@sigaev.ru 1422 [ + + ]:CBC 3869 : if (coord < 0)
1423 : : {
1424 : 2377 : coord = -coord;
1425 : 2377 : inverse = true;
1426 : : }
1427 : :
1428 [ + + ]: 3869 : if (coord <= 2 * DIM(cube))
1429 : : {
1430 : : /* dimension index */
2180 tgl@sss.pgh.pa.us 1431 : 3867 : int index = (coord - 1) / 2;
1432 : :
1433 : : /* whether this is upper bound (lower bound otherwise) */
1434 : 3867 : bool upper = ((coord - 1) % 2 == 1);
1435 : :
2285 teodor@sigaev.ru 1436 [ + + ]: 3867 : if (IS_POINT(cube))
1437 : : {
1438 : 10 : retval = cube->x[index];
1439 : : }
1440 : : else
1441 : : {
1442 [ + + ]: 3857 : if (isLeaf)
1443 : : {
1444 : : /* For leaf just return required upper/lower bound */
1445 [ + + ]: 3577 : if (upper)
1446 [ + + ]: 1722 : retval = Max(cube->x[index], cube->x[index + DIM(cube)]);
1447 : : else
1448 [ - + ]: 1855 : retval = Min(cube->x[index], cube->x[index + DIM(cube)]);
1449 : : }
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 : : */
1459 [ + + ]: 280 : if (!inverse)
1460 [ + - ]: 140 : retval = Min(cube->x[index], cube->x[index + DIM(cube)]);
1461 : : else
1462 [ - + ]: 140 : retval = Max(cube->x[index], cube->x[index + DIM(cube)]);
1463 : : }
1464 : : }
1465 : : }
1466 : : else
1467 : : {
1468 : 2 : retval = 0.0;
1469 : : }
1470 : :
1471 : : /* Inverse return value if needed */
1472 [ + + ]: 3869 : if (inverse)
1473 : 2377 : retval = -retval;
1474 : : }
1475 : : else
1476 : : {
2400 tgl@sss.pgh.pa.us 1477 : 252 : NDBOX *query = PG_GETARG_NDBOX_P(1);
1478 : :
3030 1479 [ + + + - ]: 252 : switch (strategy)
1480 : : {
1481 : 84 : case CubeKNNDistanceTaxicab:
1482 : 84 : retval = DatumGetFloat8(DirectFunctionCall2(distance_taxicab,
1483 : : PointerGetDatum(cube), PointerGetDatum(query)));
1484 : 84 : break;
1485 : 84 : case CubeKNNDistanceEuclid:
1486 : 84 : retval = DatumGetFloat8(DirectFunctionCall2(cube_distance,
1487 : : PointerGetDatum(cube), PointerGetDatum(query)));
1488 : 84 : break;
1489 : 84 : case CubeKNNDistanceChebyshev:
1490 : 84 : retval = DatumGetFloat8(DirectFunctionCall2(distance_chebyshev,
1491 : : PointerGetDatum(cube), PointerGetDatum(query)));
1492 : 84 : break;
3030 tgl@sss.pgh.pa.us 1493 :UBC 0 : default:
1494 [ # # ]: 0 : elog(ERROR, "unrecognized cube strategy number: %d", strategy);
1495 : : retval = 0; /* keep compiler quiet */
1496 : : break;
1497 : : }
1498 : : }
3040 teodor@sigaev.ru 1499 :CBC 4121 : PG_RETURN_FLOAT8(retval);
1500 : : }
1501 : :
1502 : : static double
7899 bruce@momjian.us 1503 : 19855 : distance_1D(double a1, double a2, double b1, double b2)
1504 : : {
1505 : : /* interval (a) is entirely on the left of (b) */
8424 1506 [ + + + + : 19855 : if ((a1 <= b1) && (a2 <= b1) && (a1 <= b2) && (a2 <= b2))
+ - + - ]
7152 tgl@sss.pgh.pa.us 1507 [ + + + + ]: 376 : return (Min(b1, b2) - Max(a1, a2));
1508 : :
1509 : : /* interval (a) is entirely on the right of (b) */
8424 bruce@momjian.us 1510 [ + + + + : 19479 : if ((a1 > b1) && (a2 > b1) && (a1 > b2) && (a2 > b2))
+ + + + ]
7152 tgl@sss.pgh.pa.us 1511 [ + + - + ]: 19244 : return (Min(a1, a2) - Max(b1, b2));
1512 : :
1513 : : /* the rest are all sorts of intersections */
2432 peter_e@gmx.net 1514 : 235 : return 0.0;
1515 : : }
1516 : :
1517 : : /* Test if a box is also a point */
1518 : : Datum
6473 bruce@momjian.us 1519 : 201 : cube_is_point(PG_FUNCTION_ARGS)
1520 : : {
2400 tgl@sss.pgh.pa.us 1521 : 201 : NDBOX *cube = PG_GETARG_NDBOX_P(0);
1522 : : bool result;
1523 : :
3828 heikki.linnakangas@i 1524 : 201 : result = cube_is_point_internal(cube);
1525 [ - + ]: 201 : PG_FREE_IF_COPY(cube, 0);
1526 : 201 : PG_RETURN_BOOL(result);
1527 : : }
1528 : :
1529 : : static bool
1530 : 717695 : cube_is_point_internal(NDBOX *cube)
1531 : : {
1532 : : int i;
1533 : :
1534 [ + + ]: 717695 : if (IS_POINT(cube))
1535 : 297 : return true;
1536 : :
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 : : */
1544 [ + + ]: 717534 : for (i = 0; i < DIM(cube); i++)
1545 : : {
1546 [ - + + + ]: 717522 : if (LL_COORD(cube, i) != UR_COORD(cube, i))
1547 : 717386 : return false;
1548 : : }
1549 : 12 : return true;
1550 : : }
1551 : :
1552 : : /* Return dimensions in use in the data structure */
1553 : : Datum
6473 bruce@momjian.us 1554 : 200 : cube_dim(PG_FUNCTION_ARGS)
1555 : : {
2400 tgl@sss.pgh.pa.us 1556 : 200 : NDBOX *c = PG_GETARG_NDBOX_P(0);
3828 heikki.linnakangas@i 1557 : 200 : int dim = DIM(c);
1558 : :
5995 bruce@momjian.us 1559 [ - + ]: 200 : PG_FREE_IF_COPY(c, 0);
5799 tgl@sss.pgh.pa.us 1560 : 200 : PG_RETURN_INT32(dim);
1561 : : }
1562 : :
1563 : : /* Return a specific normalized LL coordinate */
1564 : : Datum
6473 bruce@momjian.us 1565 : 151 : cube_ll_coord(PG_FUNCTION_ARGS)
1566 : : {
2400 tgl@sss.pgh.pa.us 1567 : 151 : NDBOX *c = PG_GETARG_NDBOX_P(0);
3030 1568 : 151 : int n = PG_GETARG_INT32(1);
1569 : : double result;
1570 : :
3828 heikki.linnakangas@i 1571 [ + + + - ]: 151 : if (DIM(c) >= n && n > 0)
3631 bruce@momjian.us 1572 [ + + + + : 148 : result = Min(LL_COORD(c, n - 1), UR_COORD(c, n - 1));
+ + ]
1573 : : else
5799 tgl@sss.pgh.pa.us 1574 : 3 : result = 0;
1575 : :
5995 bruce@momjian.us 1576 [ - + ]: 151 : PG_FREE_IF_COPY(c, 0);
6473 1577 : 151 : PG_RETURN_FLOAT8(result);
1578 : : }
1579 : :
1580 : : /* Return a specific normalized UR coordinate */
1581 : : Datum
1582 : 18 : cube_ur_coord(PG_FUNCTION_ARGS)
1583 : : {
2400 tgl@sss.pgh.pa.us 1584 : 18 : NDBOX *c = PG_GETARG_NDBOX_P(0);
3030 1585 : 18 : int n = PG_GETARG_INT32(1);
1586 : : double result;
1587 : :
3828 heikki.linnakangas@i 1588 [ + + + - ]: 18 : if (DIM(c) >= n && n > 0)
3631 bruce@momjian.us 1589 [ + + + + : 15 : result = Max(LL_COORD(c, n - 1), UR_COORD(c, n - 1));
+ + ]
1590 : : else
5799 tgl@sss.pgh.pa.us 1591 : 3 : result = 0;
1592 : :
5995 bruce@momjian.us 1593 [ - + ]: 18 : PG_FREE_IF_COPY(c, 0);
6473 1594 : 18 : PG_RETURN_FLOAT8(result);
1595 : : }
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
3040 teodor@sigaev.ru 1603 : 10 : cube_coord(PG_FUNCTION_ARGS)
1604 : : {
2400 tgl@sss.pgh.pa.us 1605 : 10 : NDBOX *cube = PG_GETARG_NDBOX_P(0);
3030 1606 : 10 : int coord = PG_GETARG_INT32(1);
1607 : :
1608 [ + + + + ]: 10 : if (coord <= 0 || coord > 2 * DIM(cube))
3040 teodor@sigaev.ru 1609 [ + - ]: 5 : ereport(ERROR,
1610 : : (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
1611 : : errmsg("cube index %d is out of bounds", coord)));
1612 : :
3030 tgl@sss.pgh.pa.us 1613 [ + + ]: 5 : if (IS_POINT(cube))
1614 : 2 : PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]);
1615 : : else
1616 : 3 : PG_RETURN_FLOAT8(cube->x[coord - 1]);
1617 : : }
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
3040 teodor@sigaev.ru 1644 : 24953 : cube_coord_llur(PG_FUNCTION_ARGS)
1645 : : {
2400 tgl@sss.pgh.pa.us 1646 : 24953 : NDBOX *cube = PG_GETARG_NDBOX_P(0);
3030 1647 : 24953 : int coord = PG_GETARG_INT32(1);
2285 teodor@sigaev.ru 1648 : 24953 : bool inverse = false;
1649 : : float8 result;
1650 : :
1651 : : /* 0 is the only unsupported coordinate value */
1652 [ + + ]: 24953 : if (coord == 0)
3030 tgl@sss.pgh.pa.us 1653 [ + - ]: 1 : ereport(ERROR,
1654 : : (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
1655 : : errmsg("zero cube index is not defined")));
1656 : :
1657 : : /* Return inversed value for negative coordinate */
2285 teodor@sigaev.ru 1658 [ + + ]: 24952 : if (coord < 0)
1659 : : {
1660 : 12473 : coord = -coord;
1661 : 12473 : inverse = true;
1662 : : }
1663 : :
1664 [ + + ]: 24952 : if (coord <= 2 * DIM(cube))
1665 : : {
1666 : : /* dimension index */
2180 tgl@sss.pgh.pa.us 1667 : 24946 : int index = (coord - 1) / 2;
1668 : :
1669 : : /* whether this is upper bound (lower bound otherwise) */
1670 : 24946 : bool upper = ((coord - 1) % 2 == 1);
1671 : :
3030 1672 [ + + ]: 24946 : if (IS_POINT(cube))
1673 : : {
2285 teodor@sigaev.ru 1674 : 30 : result = cube->x[index];
1675 : : }
1676 : : else
1677 : : {
1678 [ + + ]: 24916 : if (upper)
1679 [ + + ]: 12457 : result = Max(cube->x[index], cube->x[index + DIM(cube)]);
1680 : : else
1681 [ + + ]: 12459 : result = Min(cube->x[index], cube->x[index + DIM(cube)]);
1682 : : }
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 : : */
1691 : 6 : result = 0.0;
1692 : : }
1693 : :
1694 : : /* Inverse value if needed */
1695 [ + + ]: 24952 : if (inverse)
1696 : 12473 : result = -result;
1697 : :
1698 : 24952 : PG_RETURN_FLOAT8(result);
1699 : : }
1700 : :
1701 : : /* Increase or decrease box size by a radius in at least n dimensions. */
1702 : : Datum
6473 bruce@momjian.us 1703 : 54 : cube_enlarge(PG_FUNCTION_ARGS)
1704 : : {
2400 tgl@sss.pgh.pa.us 1705 : 54 : NDBOX *a = PG_GETARG_NDBOX_P(0);
5799 1706 : 54 : double r = PG_GETARG_FLOAT8(1);
4311 peter_e@gmx.net 1707 : 54 : int32 n = PG_GETARG_INT32(2);
1708 : : NDBOX *result;
7893 bruce@momjian.us 1709 : 54 : int dim = 0;
1710 : : int size;
1711 : : int i,
1712 : : j;
1713 : :
7559 1714 [ - + ]: 54 : if (n > CUBE_MAX_DIM)
7559 bruce@momjian.us 1715 :UBC 0 : n = CUBE_MAX_DIM;
6248 teodor@sigaev.ru 1716 [ + + + + ]:CBC 54 : if (r > 0 && n > 0)
7893 bruce@momjian.us 1717 : 40 : dim = n;
3828 heikki.linnakangas@i 1718 [ + + ]: 54 : if (DIM(a) > dim)
1719 : 15 : dim = DIM(a);
1720 : :
1721 : 54 : size = CUBE_SIZE(dim);
6256 tgl@sss.pgh.pa.us 1722 : 54 : result = (NDBOX *) palloc0(size);
1723 : 54 : SET_VARSIZE(result, size);
3828 heikki.linnakangas@i 1724 : 54 : SET_DIM(result, dim);
1725 : :
1726 [ + + ]: 188 : for (i = 0, j = dim; i < DIM(a); i++, j++)
1727 : : {
3631 bruce@momjian.us 1728 [ + + + + ]: 134 : if (LL_COORD(a, i) >= UR_COORD(a, i))
1729 : : {
1730 [ + + ]: 126 : result->x[i] = UR_COORD(a, i) - r;
1731 : 126 : result->x[j] = LL_COORD(a, i) + r;
1732 : : }
1733 : : else
1734 : : {
1735 : 8 : result->x[i] = LL_COORD(a, i) - r;
1736 [ - + ]: 8 : result->x[j] = UR_COORD(a, i) + r;
1737 : : }
7893 1738 [ + + ]: 134 : if (result->x[i] > result->x[j])
1739 : : {
1740 : 8 : result->x[i] = (result->x[i] + result->x[j]) / 2;
1741 : 8 : result->x[j] = result->x[i];
1742 : : }
1743 : : }
1744 : : /* dim > a->dim only if r > 0 */
7899 1745 [ + + ]: 58 : for (; i < dim; i++, j++)
1746 : : {
6248 teodor@sigaev.ru 1747 : 4 : result->x[i] = -r;
1748 : 4 : result->x[j] = r;
1749 : : }
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 : : */
3828 heikki.linnakangas@i 1755 [ + + ]: 54 : if (cube_is_point_internal(result))
1756 : : {
1757 : 8 : size = POINT_SIZE(dim);
1758 : 8 : SET_VARSIZE(result, size);
1759 : 8 : SET_POINT_BIT(result);
1760 : : }
1761 : :
5995 bruce@momjian.us 1762 [ - + ]: 54 : PG_FREE_IF_COPY(a, 0);
2400 tgl@sss.pgh.pa.us 1763 : 54 : PG_RETURN_NDBOX_P(result);
1764 : : }
1765 : :
1766 : : /* Create a one dimensional box with identical upper and lower coordinates */
1767 : : Datum
6473 bruce@momjian.us 1768 : 194 : cube_f8(PG_FUNCTION_ARGS)
1769 : : {
5799 tgl@sss.pgh.pa.us 1770 : 194 : double x = PG_GETARG_FLOAT8(0);
1771 : : NDBOX *result;
1772 : : int size;
1773 : :
3828 heikki.linnakangas@i 1774 : 194 : size = POINT_SIZE(1);
6256 tgl@sss.pgh.pa.us 1775 : 194 : result = (NDBOX *) palloc0(size);
1776 : 194 : SET_VARSIZE(result, size);
3828 heikki.linnakangas@i 1777 : 194 : SET_DIM(result, 1);
1778 : 194 : SET_POINT_BIT(result);
1779 : 194 : result->x[0] = x;
1780 : :
2400 tgl@sss.pgh.pa.us 1781 : 194 : PG_RETURN_NDBOX_P(result);
1782 : : }
1783 : :
1784 : : /* Create a one dimensional box */
1785 : : Datum
6473 bruce@momjian.us 1786 : 12 : cube_f8_f8(PG_FUNCTION_ARGS)
1787 : : {
5799 tgl@sss.pgh.pa.us 1788 : 12 : double x0 = PG_GETARG_FLOAT8(0);
1789 : 12 : double x1 = PG_GETARG_FLOAT8(1);
1790 : : NDBOX *result;
1791 : : int size;
1792 : :
3828 heikki.linnakangas@i 1793 [ + + ]: 12 : if (x0 == x1)
1794 : : {
1795 : 4 : size = POINT_SIZE(1);
1796 : 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;
1801 : : }
1802 : : else
1803 : : {
1804 : 8 : size = CUBE_SIZE(1);
1805 : 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;
1810 : : }
1811 : :
2400 tgl@sss.pgh.pa.us 1812 : 12 : PG_RETURN_NDBOX_P(result);
1813 : : }
1814 : :
1815 : : /* Add a dimension to an existing cube with the same values for the new
1816 : : coordinate */
1817 : : Datum
6473 bruce@momjian.us 1818 : 387 : cube_c_f8(PG_FUNCTION_ARGS)
1819 : : {
2400 tgl@sss.pgh.pa.us 1820 : 387 : NDBOX *cube = PG_GETARG_NDBOX_P(0);
5799 1821 : 387 : double x = PG_GETARG_FLOAT8(1);
1822 : : NDBOX *result;
1823 : : int size;
1824 : : int i;
1825 : :
2054 akorotkov@postgresql 1826 [ + + ]: 387 : if (DIM(cube) + 1 > CUBE_MAX_DIM)
1827 [ + - ]: 1 : ereport(ERROR,
1828 : : (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 : :
3828 heikki.linnakangas@i 1833 [ + + ]: 386 : if (IS_POINT(cube))
1834 : : {
1835 : 383 : size = POINT_SIZE((DIM(cube) + 1));
1836 : 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;
1843 : : }
1844 : : else
1845 : : {
1846 : 3 : size = CUBE_SIZE((DIM(cube) + 1));
1847 : 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++)
1851 : : {
1852 : 4 : result->x[i] = cube->x[i];
1853 : 4 : result->x[DIM(result) + i] = cube->x[DIM(cube) + i];
1854 : : }
1855 : 3 : result->x[DIM(result) - 1] = x;
3631 bruce@momjian.us 1856 : 3 : result->x[2 * DIM(result) - 1] = x;
1857 : : }
1858 : :
3828 heikki.linnakangas@i 1859 [ - + ]: 386 : PG_FREE_IF_COPY(cube, 0);
2400 tgl@sss.pgh.pa.us 1860 : 386 : PG_RETURN_NDBOX_P(result);
1861 : : }
1862 : :
1863 : : /* Add a dimension to an existing cube */
1864 : : Datum
6473 bruce@momjian.us 1865 : 9 : cube_c_f8_f8(PG_FUNCTION_ARGS)
1866 : : {
2400 tgl@sss.pgh.pa.us 1867 : 9 : NDBOX *cube = PG_GETARG_NDBOX_P(0);
5799 1868 : 9 : double x1 = PG_GETARG_FLOAT8(1);
1869 : 9 : double x2 = PG_GETARG_FLOAT8(2);
1870 : : NDBOX *result;
1871 : : int size;
1872 : : int i;
1873 : :
2054 akorotkov@postgresql 1874 [ + + ]: 9 : if (DIM(cube) + 1 > CUBE_MAX_DIM)
1875 [ + - ]: 1 : ereport(ERROR,
1876 : : (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 : :
3631 bruce@momjian.us 1881 [ + + + + ]: 8 : if (IS_POINT(cube) && (x1 == x2))
1882 : : {
3828 heikki.linnakangas@i 1883 : 1 : size = POINT_SIZE((DIM(cube) + 1));
1884 : 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;
1891 : : }
1892 : : else
1893 : : {
1894 : 7 : size = CUBE_SIZE((DIM(cube) + 1));
1895 : 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++)
1899 : : {
1900 : 8 : result->x[i] = LL_COORD(cube, i);
1901 [ + + ]: 8 : result->x[DIM(result) + i] = UR_COORD(cube, i);
1902 : : }
1903 : 7 : result->x[DIM(result) - 1] = x1;
1904 : 7 : result->x[2 * DIM(result) - 1] = x2;
1905 : : }
1906 : :
1907 [ - + ]: 8 : PG_FREE_IF_COPY(cube, 0);
2400 tgl@sss.pgh.pa.us 1908 : 8 : PG_RETURN_NDBOX_P(result);
1909 : : }
|