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