diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c index dab0e6e..853acbe 100644 --- a/contrib/cube/cube.c +++ b/contrib/cube/cube.c @@ -144,6 +144,7 @@ bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strate ** Auxiliary funxtions */ static double distance_1D(double a1, double a2, double b1, double b2); +static bool cube_is_point_internal(NDBOX *cube); /***************************************************************************** @@ -181,6 +182,7 @@ cube_a_f8_f8(PG_FUNCTION_ARGS) int i; int dim; int size; + bool point; double *dur, *dll; @@ -198,16 +200,32 @@ cube_a_f8_f8(PG_FUNCTION_ARGS) dur = ARRPTR(ur); dll = ARRPTR(ll); - size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim; + /* Check if it's a point */ + point = true; + for (i = 0; i < dim; i++) + { + if (dur[i] != dll[i]) + { + point = false; + break; + } + } + + size = point ? POINT_SIZE(dim) : CUBE_SIZE(dim); result = (NDBOX *) palloc0(size); SET_VARSIZE(result, size); - result->dim = dim; + SET_DIM(result, dim); for (i = 0; i < dim; i++) - { result->x[i] = dur[i]; - result->x[i + dim] = dll[i]; + + if (!point) + { + for (i = 0; i < dim; i++) + result->x[i + dim] = dll[i]; } + else + SET_POINT_BIT(result); PG_RETURN_NDBOX(result); } @@ -234,16 +252,14 @@ cube_a_f8(PG_FUNCTION_ARGS) dur = ARRPTR(ur); - size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim; + size = POINT_SIZE(dim); result = (NDBOX *) palloc0(size); SET_VARSIZE(result, size); - result->dim = dim; + SET_DIM(result, dim); + SET_POINT_BIT(result); for (i = 0; i < dim; i++) - { result->x[i] = dur[i]; - result->x[i + dim] = dur[i]; - } PG_RETURN_NDBOX(result); } @@ -267,14 +283,17 @@ cube_subset(PG_FUNCTION_ARGS) dx = (int32 *) ARR_DATA_PTR(idx); dim = ARRNELEMS(idx); - size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim; + size = IS_POINT(c) ? POINT_SIZE(dim) : CUBE_SIZE(dim); result = (NDBOX *) palloc0(size); SET_VARSIZE(result, size); - result->dim = dim; + SET_DIM(result, dim); + + if (IS_POINT(c)) + SET_POINT_BIT(result); for (i = 0; i < dim; i++) { - if ((dx[i] <= 0) || (dx[i] > c->dim)) + if ((dx[i] <= 0) || (dx[i] > DIM(c))) { pfree(result); ereport(ERROR, @@ -282,7 +301,8 @@ cube_subset(PG_FUNCTION_ARGS) errmsg("Index out of bounds"))); } result->x[i] = c->x[dx[i] - 1]; - result->x[i + dim] = c->x[dx[i] + c->dim - 1]; + if (!IS_POINT(c)) + result->x[i + dim] = c->x[dx[i] + DIM(c) - 1]; } PG_FREE_IF_COPY(c, 0); @@ -294,8 +314,7 @@ cube_out(PG_FUNCTION_ARGS) { NDBOX *cube = PG_GETARG_NDBOX(0); StringInfoData buf; - int dim = cube->dim; - bool equal = true; + int dim = DIM(cube); int i; int ndig; @@ -317,20 +336,18 @@ cube_out(PG_FUNCTION_ARGS) { if (i > 0) appendStringInfo(&buf, ", "); - appendStringInfo(&buf, "%.*g", ndig, cube->x[i]); - if (cube->x[i] != cube->x[i + dim]) - equal = false; + appendStringInfo(&buf, "%.*g", ndig, LL_COORD(cube, i)); } appendStringInfoChar(&buf, ')'); - if (!equal) + if (!cube_is_point_internal(cube)) { appendStringInfo(&buf, ",("); for (i = 0; i < dim; i++) { if (i > 0) appendStringInfo(&buf, ", "); - appendStringInfo(&buf, "%.*g", ndig, cube->x[i + dim]); + appendStringInfo(&buf, "%.*g", ndig, UR_COORD(cube, i)); } appendStringInfoChar(&buf, ')'); } @@ -422,24 +439,14 @@ g_cube_union(PG_FUNCTION_ARGS) Datum g_cube_compress(PG_FUNCTION_ARGS) { - PG_RETURN_DATUM(PG_GETARG_DATUM(0)); + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + PG_RETURN_POINTER(entry); } Datum g_cube_decompress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); - NDBOX *key = DatumGetNDBOX(PG_DETOAST_DATUM(entry->key)); - - if (key != DatumGetNDBOX(entry->key)) - { - GISTENTRY *retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); - - gistentryinit(*retval, PointerGetDatum(key), - entry->rel, entry->page, - entry->offset, FALSE); - PG_RETURN_POINTER(retval); - } PG_RETURN_POINTER(entry); } @@ -729,51 +736,60 @@ cube_union_v0(NDBOX *a, NDBOX *b) { int i; NDBOX *result; + int dim; + int size; - if (a->dim >= b->dim) - { - result = palloc0(VARSIZE(a)); - SET_VARSIZE(result, VARSIZE(a)); - result->dim = a->dim; - } - else - { - result = palloc0(VARSIZE(b)); - SET_VARSIZE(result, VARSIZE(b)); - result->dim = b->dim; - } + /* trivial case */ + if (a == b) + return a; - /* swap the box pointers if needed */ - if (a->dim < b->dim) + /* swap the arguments if needed, so that 'a' is always larger than 'b' */ + if (DIM(a) < DIM(b)) { NDBOX *tmp = b; b = a; a = tmp; } + dim = DIM(a); - /* - * use the potentially smaller of the two boxes (b) to fill in the result, - * padding absent dimensions with zeroes - */ - for (i = 0; i < b->dim; i++) + size = CUBE_SIZE(dim); + result = palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, dim); + + /* First compute the union of the dimensions present in both args */ + for (i = 0; i < DIM(b); i++) { - result->x[i] = Min(b->x[i], b->x[i + b->dim]); - result->x[i + a->dim] = Max(b->x[i], b->x[i + b->dim]); + result->x[i] = Min( + Min(LL_COORD(a, i), UR_COORD(a, i)), + Min(LL_COORD(b, i), UR_COORD(b, i)) + ); + result->x[i + DIM(a)] = Max( + Max(LL_COORD(a, i), UR_COORD(a, i)), + Max(LL_COORD(b, i), UR_COORD(b, i)) + ); } - for (i = b->dim; i < a->dim; i++) + /* continue on the higher dimensions only present in 'a' */ + for (; i < DIM(a); i++) { - result->x[i] = 0; - result->x[i + a->dim] = 0; + result->x[i] = Min(0, + Min(LL_COORD(a, i), UR_COORD(a, i)) + ); + result->x[i + dim] = Max(0, + Max(LL_COORD(a, i), UR_COORD(a, i)) + ); } - /* compute the union */ - for (i = 0; i < a->dim; i++) + /* + * Check if the result was in fact a point, and set the flag in the datum + * accordingly. (we don't bother to repalloc it smaller) + */ + if (cube_is_point_internal(result)) { - result->x[i] = - Min(Min(a->x[i], a->x[i + a->dim]), result->x[i]); - result->x[i + a->dim] = Max(Max(a->x[i], - a->x[i + a->dim]), result->x[i + a->dim]); + size = POINT_SIZE(dim); + SET_VARSIZE(result, size); + SET_POINT_BIT(result); } return (result); @@ -802,52 +818,57 @@ cube_inter(PG_FUNCTION_ARGS) NDBOX *result; bool swapped = false; int i; + int dim; + int size; - if (a->dim >= b->dim) - { - result = palloc0(VARSIZE(a)); - SET_VARSIZE(result, VARSIZE(a)); - result->dim = a->dim; - } - else - { - result = palloc0(VARSIZE(b)); - SET_VARSIZE(result, VARSIZE(b)); - result->dim = b->dim; - } - - /* swap the box pointers if needed */ - if (a->dim < b->dim) + /* swap the arguments if needed, so that 'a' is always larger than 'b' */ + if (DIM(a) < DIM(b)) { NDBOX *tmp = b; - b = a; a = tmp; swapped = true; } + dim = DIM(a); - /* - * use the potentially smaller of the two boxes (b) to fill in the - * result, padding absent dimensions with zeroes - */ - for (i = 0; i < b->dim; i++) + size = CUBE_SIZE(dim); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, dim); + + /* First compute intersection of the dimensions present in both args */ + for (i = 0; i < DIM(b); i++) { - result->x[i] = Min(b->x[i], b->x[i + b->dim]); - result->x[i + a->dim] = Max(b->x[i], b->x[i + b->dim]); + result->x[i] = Max( + Min(LL_COORD(a, i), UR_COORD(a, i)), + Min(LL_COORD(b, i), UR_COORD(b, i)) + ); + result->x[i + DIM(a)] = Min( + Max(LL_COORD(a, i), UR_COORD(a, i)), + Max(LL_COORD(b, i), UR_COORD(b, i)) + ); } - for (i = b->dim; i < a->dim; i++) + /* continue on the higher dimemsions only present in 'a' */ + for (; i < DIM(a); i++) { - result->x[i] = 0; - result->x[i + a->dim] = 0; + result->x[i] = Max(0, + Min(LL_COORD(a, i), UR_COORD(a, i)) + ); + result->x[i + DIM(a)] = Min(0, + Max(LL_COORD(a, i), UR_COORD(a, i)) + ); } - /* compute the intersection */ - for (i = 0; i < a->dim; i++) + /* + * Check if the result was in fact a point, and set the flag in the datum + * accordingly. (we don't bother to repalloc it smaller) + */ + if (cube_is_point_internal(result)) { - result->x[i] = - Max(Min(a->x[i], a->x[i + a->dim]), result->x[i]); - result->x[i + a->dim] = Min(Max(a->x[i], - a->x[i + a->dim]), result->x[i + a->dim]); + size = POINT_SIZE(dim); + result = repalloc(result, size); + SET_VARSIZE(result, size); + SET_POINT_BIT(result); } if (swapped) @@ -873,12 +894,11 @@ cube_size(PG_FUNCTION_ARGS) { NDBOX *a = PG_GETARG_NDBOX(0); double result; - int i, - j; + int i; result = 1.0; - for (i = 0, j = a->dim; i < a->dim; i++, j++) - result = result * Abs((a->x[j] - a->x[i])); + for (i = 0; i < DIM(a); i++) + result = result * Abs((LL_COORD(a, i) - UR_COORD(a, i))); PG_FREE_IF_COPY(a, 0); PG_RETURN_FLOAT8(result); @@ -887,16 +907,15 @@ cube_size(PG_FUNCTION_ARGS) void rt_cube_size(NDBOX *a, double *size) { - int i, - j; + int i; if (a == (NDBOX *) NULL) *size = 0.0; else { *size = 1.0; - for (i = 0, j = a->dim; i < a->dim; i++, j++) - *size = (*size) * Abs((a->x[j] - a->x[i])); + for (i = 0; i < DIM(a); i++) + *size = (*size) * Abs(UR_COORD(a, i) - LL_COORD(a, i)); } return; } @@ -909,43 +928,43 @@ cube_cmp_v0(NDBOX *a, NDBOX *b) int i; int dim; - dim = Min(a->dim, b->dim); + dim = Min(DIM(a), DIM(b)); /* compare the common dimensions */ for (i = 0; i < dim; i++) { - if (Min(a->x[i], a->x[a->dim + i]) > - Min(b->x[i], b->x[b->dim + i])) + if (Min(LL_COORD(a, i), UR_COORD(a, i)) > + Min(LL_COORD(b, i), UR_COORD(b, i))) return 1; - if (Min(a->x[i], a->x[a->dim + i]) < - Min(b->x[i], b->x[b->dim + i])) + if (Min(LL_COORD(a, i), UR_COORD(a, i)) < + Min(LL_COORD(b, i), UR_COORD(b, i))) return -1; } for (i = 0; i < dim; i++) { - if (Max(a->x[i], a->x[a->dim + i]) > - Max(b->x[i], b->x[b->dim + i])) + if (Max(LL_COORD(a, i), UR_COORD(a, i)) > + Max(LL_COORD(b, i), UR_COORD(b, i))) return 1; - if (Max(a->x[i], a->x[a->dim + i]) < - Max(b->x[i], b->x[b->dim + i])) + if (Max(LL_COORD(a, i), UR_COORD(a, i)) < + Max(LL_COORD(b, i), UR_COORD(b, i))) return -1; } /* compare extra dimensions to zero */ - if (a->dim > b->dim) + if (DIM(a) > DIM(b)) { - for (i = dim; i < a->dim; i++) + for (i = dim; i < DIM(a); i++) { - if (Min(a->x[i], a->x[a->dim + i]) > 0) + if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0) return 1; - if (Min(a->x[i], a->x[a->dim + i]) < 0) + if (Min(LL_COORD(a, i), UR_COORD(a, i)) < 0) return -1; } - for (i = dim; i < a->dim; i++) + for (i = dim; i < DIM(a); i++) { - if (Max(a->x[i], a->x[a->dim + i]) > 0) + if (Max(LL_COORD(a, i), UR_COORD(a, i)) > 0) return 1; - if (Max(a->x[i], a->x[a->dim + i]) < 0) + if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0) return -1; } @@ -955,20 +974,20 @@ cube_cmp_v0(NDBOX *a, NDBOX *b) */ return 1; } - if (a->dim < b->dim) + if (DIM(a) < DIM(b)) { - for (i = dim; i < b->dim; i++) + for (i = dim; i < DIM(b); i++) { - if (Min(b->x[i], b->x[b->dim + i]) > 0) + if (Min(LL_COORD(b, i), UR_COORD(b, i)) > 0) return -1; - if (Min(b->x[i], b->x[b->dim + i]) < 0) + if (Min(LL_COORD(b, i), UR_COORD(b, i)) < 0) return 1; } - for (i = dim; i < b->dim; i++) + for (i = dim; i < DIM(b); i++) { - if (Max(b->x[i], b->x[b->dim + i]) > 0) + if (Max(LL_COORD(b, i), UR_COORD(b, i)) > 0) return -1; - if (Max(b->x[i], b->x[b->dim + i]) < 0) + if (Max(LL_COORD(b, i), UR_COORD(b, i)) < 0) return 1; } @@ -1098,30 +1117,30 @@ cube_contains_v0(NDBOX *a, NDBOX *b) if ((a == NULL) || (b == NULL)) return (FALSE); - if (a->dim < b->dim) + if (DIM(a) < DIM(b)) { /* * the further comparisons will make sense if the excess dimensions of * (b) were zeroes Since both UL and UR coordinates must be zero, we * can check them all without worrying about which is which. */ - for (i = a->dim; i < b->dim; i++) + for (i = DIM(a); i < DIM(b); i++) { - if (b->x[i] != 0) + if (LL_COORD(b, i) != 0) return (FALSE); - if (b->x[i + b->dim] != 0) + if (UR_COORD(b, i) != 0) return (FALSE); } } /* Can't care less about the excess dimensions of (a), if any */ - for (i = 0; i < Min(a->dim, b->dim); i++) + for (i = 0; i < Min(DIM(a), DIM(b)); i++) { - if (Min(a->x[i], a->x[a->dim + i]) > - Min(b->x[i], b->x[b->dim + i])) + if (Min(LL_COORD(a, i), UR_COORD(a, i)) > + Min(LL_COORD(b, i), UR_COORD(b, i))) return (FALSE); - if (Max(a->x[i], a->x[a->dim + i]) < - Max(b->x[i], b->x[b->dim + i])) + if (Max(LL_COORD(a, i), UR_COORD(a, i)) < + Max(LL_COORD(b, i), UR_COORD(b, i))) return (FALSE); } @@ -1173,7 +1192,7 @@ cube_overlap_v0(NDBOX *a, NDBOX *b) return (FALSE); /* swap the box pointers if needed */ - if (a->dim < b->dim) + if (DIM(a) < DIM(b)) { NDBOX *tmp = b; @@ -1182,22 +1201,20 @@ cube_overlap_v0(NDBOX *a, NDBOX *b) } /* compare within the dimensions of (b) */ - for (i = 0; i < b->dim; i++) + for (i = 0; i < DIM(b); i++) { - if (Min(a->x[i], a->x[a->dim + i]) > - Max(b->x[i], b->x[b->dim + i])) + if (Min(LL_COORD(a, i), UR_COORD(a, i)) > Max(LL_COORD(b, i), UR_COORD(b, i))) return (FALSE); - if (Max(a->x[i], a->x[a->dim + i]) < - Min(b->x[i], b->x[b->dim + i])) + if (Max(LL_COORD(a, i), UR_COORD(a, i)) < Min(LL_COORD(b, i), UR_COORD(b, i))) return (FALSE); } /* compare to zero those dimensions in (a) absent in (b) */ - for (i = b->dim; i < a->dim; i++) + for (i = DIM(b); i < DIM(a); i++) { - if (Min(a->x[i], a->x[a->dim + i]) > 0) + if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0) return (FALSE); - if (Max(a->x[i], a->x[a->dim + i]) < 0) + if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0) return (FALSE); } @@ -1236,7 +1253,7 @@ cube_distance(PG_FUNCTION_ARGS) int i; /* swap the box pointers if needed */ - if (a->dim < b->dim) + if (DIM(a) < DIM(b)) { NDBOX *tmp = b; @@ -1247,16 +1264,16 @@ cube_distance(PG_FUNCTION_ARGS) distance = 0.0; /* compute within the dimensions of (b) */ - for (i = 0; i < b->dim; i++) + for (i = 0; i < DIM(b); i++) { - d = distance_1D(a->x[i], a->x[i + a->dim], b->x[i], b->x[i + b->dim]); + d = distance_1D(LL_COORD(a,i), UR_COORD(a,i), LL_COORD(b,i), UR_COORD(b,i)); distance += d * d; } /* compute distance to zero for those dimensions in (a) absent in (b) */ - for (i = b->dim; i < a->dim; i++) + for (i = DIM(b); i < DIM(a); i++) { - d = distance_1D(a->x[i], a->x[i + a->dim], 0.0, 0.0); + d = distance_1D(LL_COORD(a,i), UR_COORD(a,i), 0.0, 0.0); distance += d * d; } @@ -1293,18 +1310,35 @@ distance_1D(double a1, double a2, double b1, double b2) Datum cube_is_point(PG_FUNCTION_ARGS) { - NDBOX *a = PG_GETARG_NDBOX(0); - int i, - j; + NDBOX *cube = PG_GETARG_NDBOX(0); + bool result; + + result = cube_is_point_internal(cube); + PG_FREE_IF_COPY(cube, 0); + PG_RETURN_BOOL(result); +} + +static bool +cube_is_point_internal(NDBOX *cube) +{ + int i; + + if (IS_POINT(cube)) + return true; - for (i = 0, j = a->dim; i < a->dim; i++, j++) + /* + * Even if the point-flag is not set, all the lower-left coordinates + * might match the upper-right coordinates, so that the value is in + * fact a point. Such values don't arise with current code - the point + * flag is always set if appropriate - but they might be present on-disk + * in clusters upgraded from pre-9.4 versions. + */ + for (i = 0; i < DIM(cube); i++) { - if (a->x[i] != a->x[j]) - PG_RETURN_BOOL(FALSE); + if (LL_COORD(cube, i) != UR_COORD(cube, i)) + return false; } - - PG_FREE_IF_COPY(a, 0); - PG_RETURN_BOOL(TRUE); + return true; } /* Return dimensions in use in the data structure */ @@ -1312,8 +1346,7 @@ Datum cube_dim(PG_FUNCTION_ARGS) { NDBOX *c = PG_GETARG_NDBOX(0); - int dim = c->dim; - + int dim = DIM(c); PG_FREE_IF_COPY(c, 0); PG_RETURN_INT32(dim); } @@ -1326,8 +1359,8 @@ cube_ll_coord(PG_FUNCTION_ARGS) int n = PG_GETARG_INT16(1); double result; - if (c->dim >= n && n > 0) - result = Min(c->x[n - 1], c->x[c->dim + n - 1]); + if (DIM(c) >= n && n > 0) + result = Min(LL_COORD(c, n-1), UR_COORD(c, n-1)); else result = 0; @@ -1343,8 +1376,8 @@ cube_ur_coord(PG_FUNCTION_ARGS) int n = PG_GETARG_INT16(1); double result; - if (c->dim >= n && n > 0) - result = Max(c->x[n - 1], c->x[c->dim + n - 1]); + if (DIM(c) >= n && n > 0) + result = Max(LL_COORD(c, n-1), UR_COORD(c, n-1)); else result = 0; @@ -1363,30 +1396,31 @@ cube_enlarge(PG_FUNCTION_ARGS) int dim = 0; int size; int i, - j, - k; + j; if (n > CUBE_MAX_DIM) n = CUBE_MAX_DIM; if (r > 0 && n > 0) dim = n; - if (a->dim > dim) - dim = a->dim; - size = offsetof(NDBOX, x[0]) +sizeof(double) * dim * 2; + if (DIM(a) > dim) + dim = DIM(a); + + size = CUBE_SIZE(dim); result = (NDBOX *) palloc0(size); SET_VARSIZE(result, size); - result->dim = dim; - for (i = 0, j = dim, k = a->dim; i < a->dim; i++, j++, k++) + SET_DIM(result, dim); + + for (i = 0, j = dim; i < DIM(a); i++, j++) { - if (a->x[i] >= a->x[k]) + if (LL_COORD(a,i) >= UR_COORD(a,i)) { - result->x[i] = a->x[k] - r; - result->x[j] = a->x[i] + r; + result->x[i] = UR_COORD(a,i) - r; + result->x[j] = LL_COORD(a,i) + r; } else { - result->x[i] = a->x[i] - r; - result->x[j] = a->x[k] + r; + result->x[i] = LL_COORD(a,i) - r; + result->x[j] = UR_COORD(a,i) + r; } if (result->x[i] > result->x[j]) { @@ -1401,6 +1435,17 @@ cube_enlarge(PG_FUNCTION_ARGS) result->x[j] = r; } + /* + * Check if the result was in fact a point, and set the flag in the datum + * accordingly. (we don't bother to repalloc it smaller) + */ + if (cube_is_point_internal(result)) + { + size = POINT_SIZE(dim); + SET_VARSIZE(result, size); + SET_POINT_BIT(result); + } + PG_FREE_IF_COPY(a, 0); PG_RETURN_NDBOX(result); } @@ -1413,11 +1458,12 @@ cube_f8(PG_FUNCTION_ARGS) NDBOX *result; int size; - size = offsetof(NDBOX, x[0]) +sizeof(double) * 2; + size = POINT_SIZE(1); result = (NDBOX *) palloc0(size); SET_VARSIZE(result, size); - result->dim = 1; - result->x[0] = result->x[1] = x; + SET_DIM(result, 1); + SET_POINT_BIT(result); + result->x[0] = x; PG_RETURN_NDBOX(result); } @@ -1431,12 +1477,24 @@ cube_f8_f8(PG_FUNCTION_ARGS) NDBOX *result; int size; - size = offsetof(NDBOX, x[0]) +sizeof(double) * 2; - result = (NDBOX *) palloc0(size); - SET_VARSIZE(result, size); - result->dim = 1; - result->x[0] = x0; - result->x[1] = x1; + if (x0 == x1) + { + size = POINT_SIZE(1); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, 1); + SET_POINT_BIT(result); + result->x[0] = x0; + } + else + { + size = CUBE_SIZE(1); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, 1); + result->x[0] = x0; + result->x[1] = x1; + } PG_RETURN_NDBOX(result); } @@ -1446,25 +1504,39 @@ cube_f8_f8(PG_FUNCTION_ARGS) Datum cube_c_f8(PG_FUNCTION_ARGS) { - NDBOX *c = PG_GETARG_NDBOX(0); + NDBOX *cube = PG_GETARG_NDBOX(0); double x = PG_GETARG_FLOAT8(1); NDBOX *result; int size; int i; - size = offsetof(NDBOX, x[0]) +sizeof(double) * (c->dim + 1) *2; - result = (NDBOX *) palloc0(size); - SET_VARSIZE(result, size); - result->dim = c->dim + 1; - for (i = 0; i < c->dim; i++) + if (IS_POINT(cube)) { - result->x[i] = c->x[i]; - result->x[result->dim + i] = c->x[c->dim + i]; + size = POINT_SIZE((DIM(cube) + 1)); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, DIM(cube) + 1); + SET_POINT_BIT(result); + for (i = 0; i < DIM(cube); i++) + result->x[i] = cube->x[i]; + result->x[DIM(result) - 1] = x; + } + else + { + size = CUBE_SIZE((DIM(cube) + 1)); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, DIM(cube) + 1); + for (i = 0; i < DIM(cube); i++) + { + result->x[i] = cube->x[i]; + result->x[DIM(result) + i] = cube->x[DIM(cube) + i]; + } + result->x[DIM(result) - 1] = x; + result->x[2*DIM(result) - 1] = x; } - result->x[result->dim - 1] = x; - result->x[2 * result->dim - 1] = x; - PG_FREE_IF_COPY(c, 0); + PG_FREE_IF_COPY(cube, 0); PG_RETURN_NDBOX(result); } @@ -1472,25 +1544,38 @@ cube_c_f8(PG_FUNCTION_ARGS) Datum cube_c_f8_f8(PG_FUNCTION_ARGS) { - NDBOX *c = PG_GETARG_NDBOX(0); + NDBOX *cube = PG_GETARG_NDBOX(0); double x1 = PG_GETARG_FLOAT8(1); double x2 = PG_GETARG_FLOAT8(2); NDBOX *result; int size; int i; - size = offsetof(NDBOX, x[0]) +sizeof(double) * (c->dim + 1) *2; - result = (NDBOX *) palloc0(size); - SET_VARSIZE(result, size); - result->dim = c->dim + 1; - for (i = 0; i < c->dim; i++) + if (IS_POINT(cube) && (x1 == x2)){ + size = POINT_SIZE((DIM(cube) + 1)); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, DIM(cube) + 1); + SET_POINT_BIT(result); + for (i = 0; i < DIM(cube); i++) + result->x[i] = cube->x[i]; + result->x[DIM(result) - 1] = x1; + } + else { - result->x[i] = c->x[i]; - result->x[result->dim + i] = c->x[c->dim + i]; + size = CUBE_SIZE((DIM(cube) + 1)); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, DIM(cube) + 1); + for (i = 0; i < DIM(cube); i++) + { + result->x[i] = LL_COORD(cube, i); + result->x[DIM(result) + i] = UR_COORD(cube, i); + } + result->x[DIM(result) - 1] = x1; + result->x[2 * DIM(result) - 1] = x2; } - result->x[result->dim - 1] = x1; - result->x[2 * result->dim - 1] = x2; - PG_FREE_IF_COPY(c, 0); + PG_FREE_IF_COPY(cube, 0); PG_RETURN_NDBOX(result); } diff --git a/contrib/cube/cubedata.h b/contrib/cube/cubedata.h index fd0c26a..7903c8b 100644 --- a/contrib/cube/cubedata.h +++ b/contrib/cube/cubedata.h @@ -4,11 +4,36 @@ typedef struct NDBOX { - int32 vl_len_; /* varlena header (do not touch directly!) */ - unsigned int dim; + /* varlena header (do not touch directly!) */ + int32 vl_len_; + + /*---------- + * Header contains info about NDBOX. For binary compatibility with old + * versions, it is defined as "unsigned int". + * + * Following information is stored: + * + * bits 0-7 : number of cube dimensions; + * bits 8-30 : not used; + * bit 31 : point flag. If set, then NDBOX stores + * n dimensions instead of 2*n; + *---------- + */ + unsigned int header; double x[1]; } NDBOX; #define DatumGetNDBOX(x) ((NDBOX*)DatumGetPointer(x)) #define PG_GETARG_NDBOX(x) DatumGetNDBOX( PG_DETOAST_DATUM(PG_GETARG_DATUM(x)) ) #define PG_RETURN_NDBOX(x) PG_RETURN_POINTER(x) + +#define IS_POINT(cube) ( (cube)->header >> 31 ) +#define SET_POINT_BIT(cube) ( (cube)->header |= 0x80000000 ) +#define DIM(cube) ( (cube)->header & 0x7fffffff ) +#define SET_DIM(cube, _dim) ( (cube)->header = _dim ) + +#define LL_COORD(cube, i) ( (cube)->x[i] ) +#define UR_COORD(cube, i) ( IS_POINT(cube) ? (cube)->x[i] : (cube)->x[i + DIM(cube)] ) + +#define POINT_SIZE(_dim) (offsetof(NDBOX, x[0]) + sizeof(double)*(_dim)) +#define CUBE_SIZE(_dim) (offsetof(NDBOX, x[0]) + sizeof(double)*(_dim)*2) diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y index d7205b8..0baee8e 100644 --- a/contrib/cube/cubeparse.y +++ b/contrib/cube/cubeparse.y @@ -175,11 +175,12 @@ write_box(unsigned int dim, char *str1, char *str2) NDBOX *bp; char *s; int i; - int size = offsetof(NDBOX, x[0]) + sizeof(double) * dim * 2; + int size = CUBE_SIZE(dim); + bool point = true; bp = palloc0(size); SET_VARSIZE(bp, size); - bp->dim = dim; + SET_DIM(bp, dim); s = str1; bp->x[i=0] = strtod(s, NULL); @@ -191,10 +192,28 @@ write_box(unsigned int dim, char *str1, char *str2) s = str2; bp->x[i=dim] = strtod(s, NULL); + if (bp->x[dim] != bp->x[0]) + point = false; while ((s = strchr(s, ',')) != NULL) { s++; i++; bp->x[i] = strtod(s, NULL); + if (bp->x[i] != bp->x[i-dim]) + point = false; + } + + if (point) + { + /* + * The value turned out to be a point, ie. all the upper-right + * coordinates were equal to the lower-left coordinates. Resize the + * the cube we constructed. Note: we don't bother to repalloc() it + * smaller, it's unlikely that the tiny amount of memory free'd that + * way would be useful. + */ + size = POINT_SIZE(dim); + SET_VARSIZE(bp, size); + SET_POINT_BIT(bp); } return(bp); @@ -203,31 +222,29 @@ write_box(unsigned int dim, char *str1, char *str2) static NDBOX * write_point_as_box(char *str, int dim) { - NDBOX *bp; - int i, + NDBOX *bp; + int i, size; - double x; - char *s = str; - - size = offsetof(NDBOX, x[0]) + sizeof(double) * dim * 2; - - bp = palloc0(size); - SET_VARSIZE(bp, size); - bp->dim = dim; - - i = 0; - x = strtod(s, NULL); - bp->x[0] = x; - bp->x[dim] = x; - while ((s = strchr(s, ',')) != NULL) - { - s++; i++; - x = strtod(s, NULL); - bp->x[i] = x; - bp->x[i+dim] = x; - } - - return(bp); + double x; + char *s = str; + + size = POINT_SIZE(dim); + bp = palloc0(size); + SET_VARSIZE(bp, size); + SET_DIM(bp, dim); + SET_POINT_BIT(bp); + + i = 0; + x = strtod(s, NULL); + bp->x[0] = x; + while ((s = strchr(s, ',')) != NULL) + { + s++; i++; + x = strtod(s, NULL); + bp->x[i] = x; + } + + return(bp); } #include "cubescan.c" diff --git a/contrib/cube/expected/cube_1.out b/contrib/cube/expected/cube_1.out index fefebf5..c07d61d 100644 --- a/contrib/cube/expected/cube_1.out +++ b/contrib/cube/expected/cube_1.out @@ -473,8 +473,85 @@ SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]); (5, 3, 1, 1),(8, 7, 6, 6) (1 row) +SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]); + cube_subset +-------------- + (5, 3, 1, 1) +(1 row) + SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]); ERROR: Index out of bounds +SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]); +ERROR: Index out of bounds +-- +-- Test point processing +-- +SELECT cube('(1,2),(1,2)'); -- cube_in + cube +-------- + (1, 2) +(1 row) + +SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8 + cube +----------- + (0, 1, 2) +(1 row) + +SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8 + cube +-------------- + (5, 6, 7, 8) +(1 row) + +SELECT cube(1.37); -- cube_f8 + cube +-------- + (1.37) +(1 row) + +SELECT cube(1.37, 1.37); -- cube_f8_f8 + cube +-------- + (1.37) +(1 row) + +SELECT cube(cube(1,1), 42); -- cube_c_f8 + cube +--------- + (1, 42) +(1 row) + +SELECT cube(cube(1,2), 42); -- cube_c_f8 + cube +----------------- + (1, 42),(2, 42) +(1 row) + +SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8 + cube +--------- + (1, 42) +(1 row) + +SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8 + cube +----------------- + (1, 42),(1, 24) +(1 row) + +SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8 + cube +----------------- + (1, 42),(2, 42) +(1 row) + +SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8 + cube +----------------- + (1, 42),(2, 24) +(1 row) + -- -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in. -- @@ -878,6 +955,24 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); 0.5 (1 row) +SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube); + cube_distance +--------------- + 0 +(1 row) + +SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube); + cube_distance +--------------- + 190 +(1 row) + +SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube); + cube_distance +------------------ + 140.762210837994 +(1 row) + -- Test of cube function (text to cube) -- SELECT cube('(1,1.2)'::text); @@ -912,6 +1007,18 @@ SELECT cube_dim('(0,0,0)'::cube); 3 (1 row) +SELECT cube_dim('(42,42,42),(42,42,42)'::cube); + cube_dim +---------- + 3 +(1 row) + +SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube); + cube_dim +---------- + 5 +(1 row) + -- Test of cube_ll_coord function (retrieves LL coodinate values) -- SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1); @@ -932,6 +1039,42 @@ SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3); 0 (1 row) +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1); + cube_ll_coord +--------------- + 1 +(1 row) + +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2); + cube_ll_coord +--------------- + 2 +(1 row) + +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3); + cube_ll_coord +--------------- + 0 +(1 row) + +SELECT cube_ll_coord('(42,137)'::cube, 1); + cube_ll_coord +--------------- + 42 +(1 row) + +SELECT cube_ll_coord('(42,137)'::cube, 2); + cube_ll_coord +--------------- + 137 +(1 row) + +SELECT cube_ll_coord('(42,137)'::cube, 3); + cube_ll_coord +--------------- + 0 +(1 row) + -- Test of cube_ur_coord function (retrieves UR coodinate values) -- SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1); @@ -952,6 +1095,42 @@ SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3); 0 (1 row) +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1); + cube_ur_coord +--------------- + 1 +(1 row) + +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2); + cube_ur_coord +--------------- + 2 +(1 row) + +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3); + cube_ur_coord +--------------- + 0 +(1 row) + +SELECT cube_ur_coord('(42,137)'::cube, 1); + cube_ur_coord +--------------- + 42 +(1 row) + +SELECT cube_ur_coord('(42,137)'::cube, 2); + cube_ur_coord +--------------- + 137 +(1 row) + +SELECT cube_ur_coord('(42,137)'::cube, 3); + cube_ur_coord +--------------- + 0 +(1 row) + -- Test of cube_is_point -- SELECT cube_is_point('(0)'::cube); @@ -1100,6 +1279,108 @@ SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2); (-0.5, 1),(-0.5, 4) (1 row) +SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5); + cube_enlarge +-------------- + (42, 0, 0) +(1 row) + +SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5); + cube_enlarge +-------------- + (42, 0, 0) +(1 row) + +-- Test of cube_union (MBR for two cubes) +-- +SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube); + cube_union +---------------------- + (1, 2, 0),(8, 9, 10) +(1 row) + +SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube); + cube_union +--------------------------- + (1, 2, 0, 0),(4, 2, 0, 0) +(1 row) + +SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube); + cube_union +--------------- + (1, 2),(4, 2) +(1 row) + +SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube); + cube_union +------------ + (1, 2) +(1 row) + +SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube); + cube_union +------------ + (1, 2, 0) +(1 row) + +-- Test of cube_inter +-- +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects + cube_inter +----------------- + (3, 4),(10, 11) +(1 row) + +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes + cube_inter +--------------- + (3, 4),(6, 5) +(1 row) + +SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection + cube_inter +------------------- + (13, 14),(10, 11) +(1 row) + +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects + cube_inter +------------------ + (3, 14),(10, 11) +(1 row) + +SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection + cube_inter +------------ + (10, 11) +(1 row) + +SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args + cube_inter +------------ + (1, 2, 3) +(1 row) + +SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args + cube_inter +--------------------- + (5, 6, 3),(1, 2, 3) +(1 row) + +-- Test of cube_size +-- +SELECT cube_size('(4,8),(15,16)'::cube); + cube_size +----------- + 88 +(1 row) + +SELECT cube_size('(42,137)'::cube); + cube_size +----------- + 0 +(1 row) + -- Load some example data and build the index -- CREATE TABLE test_cube (c cube); diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql index 02e068e..d58974c 100644 --- a/contrib/cube/sql/cube.sql +++ b/contrib/cube/sql/cube.sql @@ -112,7 +112,24 @@ SELECT cube('{0,1,2}'::float[], '{3}'::float[]); SELECT cube(NULL::float[], '{3}'::float[]); SELECT cube('{0,1,2}'::float[]); SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]); +SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]); SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]); +SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]); + +-- +-- Test point processing +-- +SELECT cube('(1,2),(1,2)'); -- cube_in +SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8 +SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8 +SELECT cube(1.37); -- cube_f8 +SELECT cube(1.37, 1.37); -- cube_f8_f8 +SELECT cube(cube(1,1), 42); -- cube_c_f8 +SELECT cube(cube(1,2), 42); -- cube_c_f8 +SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8 +SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8 +SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8 +SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8 -- -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in. @@ -212,6 +229,9 @@ SELECT '(-1,-1),(1,1)'::cube @> '(-2),(1)'::cube AS bool; -- SELECT cube_distance('(0)'::cube,'(2,2,2,2)'::cube); SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); +SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube); +SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube); +SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube); -- Test of cube function (text to cube) -- @@ -223,18 +243,32 @@ SELECT cube(NULL); SELECT cube_dim('(0)'::cube); SELECT cube_dim('(0,0)'::cube); SELECT cube_dim('(0,0,0)'::cube); +SELECT cube_dim('(42,42,42),(42,42,42)'::cube); +SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube); -- Test of cube_ll_coord function (retrieves LL coodinate values) -- SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1); SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 2); SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3); +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1); +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2); +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3); +SELECT cube_ll_coord('(42,137)'::cube, 1); +SELECT cube_ll_coord('(42,137)'::cube, 2); +SELECT cube_ll_coord('(42,137)'::cube, 3); -- Test of cube_ur_coord function (retrieves UR coodinate values) -- SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1); SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 2); SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3); +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1); +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2); +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3); +SELECT cube_ur_coord('(42,137)'::cube, 1); +SELECT cube_ur_coord('(42,137)'::cube, 2); +SELECT cube_ur_coord('(42,137)'::cube, 3); -- Test of cube_is_point -- @@ -265,6 +299,31 @@ SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 1, 2); SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 3, 2); SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -1, 2); SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2); +SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5); +SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5); + +-- Test of cube_union (MBR for two cubes) +-- +SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube); +SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube); +SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube); +SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube); +SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube); + +-- Test of cube_inter +-- +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes +SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects +SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection +SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args +SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args + +-- Test of cube_size +-- +SELECT cube_size('(4,8),(15,16)'::cube); +SELECT cube_size('(42,137)'::cube); -- Load some example data and build the index --