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