/* ** Equality method */ Datum g_cube_same(PG_FUNCTION_ARGS) { NDBOX *b1 = PG_GETARG_NDBOX(0); NDBOX *b2 = PG_GETARG_NDBOX(1); bool *result = (bool *) PG_GETARG_POINTER(2); if (cube_cmp_v0(b1, b2) == 0) *result = TRUE; else *result = FALSE; /* * fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" )); */ PG_RETURN_NDBOX(result); }
/* Return dimensions in use in the data structure */ Datum cube_dim(PG_FUNCTION_ARGS) { NDBOX *c = PG_GETARG_NDBOX(0); int dim = c->dim; PG_FREE_IF_COPY(c, 0); PG_RETURN_INT32(dim); }
/* Increase or decrease box size by a radius in at least n dimensions. */ Datum cube_enlarge(PG_FUNCTION_ARGS) { NDBOX *result; int dim = 0; int size; int i, j, k; NDBOX *a; double r; int4 n; a = PG_GETARG_NDBOX(0); r = PG_GETARG_FLOAT8(1); n = PG_GETARG_INT32(2); 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; result = (NDBOX *) palloc(size); memset(result, 0, size); result->size = size; result->dim = dim; for (i = 0, j = dim, k = a->dim; i < a->dim; i++, j++, k++) { if (a->x[i] >= a->x[k]) { result->x[i] = a->x[k] - r; result->x[j] = a->x[i] + r; } else { result->x[i] = a->x[i] - r; result->x[j] = a->x[k] + r; } if (result->x[i] > result->x[j]) { result->x[i] = (result->x[i] + result->x[j]) / 2; result->x[j] = result->x[i]; } } /* dim > a->dim only if r > 0 */ for (; i < dim; i++, j++) { result->x[i] = -r; result->x[j] = r; } PG_FREE_IF_COPY(a,0); PG_RETURN_NDBOX(result); }
/* Test if a box is also a point */ Datum cube_is_point(PG_FUNCTION_ARGS) { NDBOX *cube = PG_GETARG_NDBOX(0); bool result; result = cube_is_point_internal(cube); PG_FREE_IF_COPY(cube, 0); PG_RETURN_BOOL(result); }
Datum cube_out(PG_FUNCTION_ARGS) { StringInfoData buf; bool equal = true; int dim; int i; int ndig; NDBOX *cube; initStringInfo(&buf); cube = PG_GETARG_NDBOX(0); dim = cube->dim; /* * Get the number of digits to display. */ ndig = DBL_DIG + extra_float_digits; if (ndig < 1) ndig = 1; /* * while printing the first (LL) corner, check if it is equal to the * second one */ appendStringInfoChar(&buf, '('); for (i = 0; i < dim; i++) { if (i > 0) appendStringInfo(&buf, ", "); appendStringInfo(&buf, "%.*g", ndig, cube->x[i]); if (cube->x[i] != cube->x[i + dim]) equal = false; } appendStringInfoChar(&buf, ')'); if (!equal) { appendStringInfo(&buf, ",("); for (i = 0; i < dim; i++) { if (i > 0) appendStringInfo(&buf, ", "); appendStringInfo(&buf, "%.*g", ndig, cube->x[i + dim]); } appendStringInfoChar(&buf, ')'); } PG_FREE_IF_COPY(cube,0); PG_RETURN_CSTRING(buf.data); }
Datum cube_subset(PG_FUNCTION_ARGS) { NDBOX *c = PG_GETARG_NDBOX(0); ArrayType *idx = PG_GETARG_ARRAYTYPE_P(1); NDBOX *result; int size, dim, i; int *dx; if (array_contains_nulls(idx)) ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("cannot work with arrays containing NULLs"))); dx = (int32 *) ARR_DATA_PTR(idx); dim = ARRNELEMS(idx); if (dim > CUBE_MAX_DIM) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("array is too long"), errdetail("A cube cannot have more than %d dimensions.", CUBE_MAX_DIM))); size = IS_POINT(c) ? POINT_SIZE(dim) : CUBE_SIZE(dim); result = (NDBOX *) palloc0(size); SET_VARSIZE(result, size); SET_DIM(result, dim); if (IS_POINT(c)) SET_POINT_BIT(result); for (i = 0; i < dim; i++) { if ((dx[i] <= 0) || (dx[i] > DIM(c))) { pfree(result); ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("Index out of bounds"))); } result->x[i] = c->x[dx[i] - 1]; if (!IS_POINT(c)) result->x[i + dim] = c->x[dx[i] + DIM(c) - 1]; } PG_FREE_IF_COPY(c, 0); PG_RETURN_NDBOX(result); }
/* cube_size */ Datum cube_size(PG_FUNCTION_ARGS) { NDBOX *a = PG_GETARG_NDBOX(0); double result; int i; result = 1.0; 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); }
/* cube_size */ Datum cube_size(PG_FUNCTION_ARGS) { NDBOX *a = PG_GETARG_NDBOX(0); double result; int i, j; result = 1.0; for (i = 0, j = a->dim; i < a->dim; i++, j++) result = result * Abs((a->x[j] - a->x[i])); PG_FREE_IF_COPY(a, 0); PG_RETURN_FLOAT8(result); }
/* Return a specific normalized UR coordinate */ Datum cube_ur_coord(PG_FUNCTION_ARGS) { NDBOX *c = PG_GETARG_NDBOX(0); 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]); else result = 0; PG_FREE_IF_COPY(c, 0); PG_RETURN_FLOAT8(result); }
/* Return a specific normalized UR coordinate */ Datum cube_ur_coord(PG_FUNCTION_ARGS) { NDBOX *c = PG_GETARG_NDBOX(0); int n = PG_GETARG_INT16(1); double result; if (DIM(c) >= n && n > 0) result = Max(LL_COORD(c, n - 1), UR_COORD(c, n - 1)); else result = 0; PG_FREE_IF_COPY(c, 0); PG_RETURN_FLOAT8(result); }
/* Test if a box is also a point */ Datum cube_is_point(PG_FUNCTION_ARGS) { NDBOX *a = PG_GETARG_NDBOX(0); int i, j; for (i = 0, j = a->dim; i < a->dim; i++, j++) { if (a->x[i] != a->x[j]) PG_RETURN_BOOL(FALSE); } PG_FREE_IF_COPY(a, 0); PG_RETURN_BOOL(TRUE); }
Datum cube_subset(PG_FUNCTION_ARGS) { NDBOX *c, *result; ArrayType *idx; int size, dim, i; int *dx; c = PG_GETARG_NDBOX(0); idx = (ArrayType *) PG_GETARG_VARLENA_P(1); if (ARR_HASNULL(idx)) { ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("Cannot work with NULL arrays"))); } dx = (int4 *) ARR_DATA_PTR(idx); dim = ARRNELEMS(idx); size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim; result = (NDBOX *) palloc(size); memset(result, 0, size); result->size = size; result->dim = dim; for (i = 0; i < dim; i++) { if ((dx[i] <= 0) || (dx[i] > c->dim)) { pfree(result); ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("Index out of bounds"))); } result->x[i] = c->x[dx[i] - 1]; result->x[i + dim] = c->x[dx[i] + c->dim - 1]; } PG_FREE_IF_COPY(c,0); PG_RETURN_NDBOX(result); }
/* Add a dimension to an existing cube */ Datum cube_c_f8_f8(PG_FUNCTION_ARGS) { NDBOX *cube = PG_GETARG_NDBOX(0); double x1 = PG_GETARG_FLOAT8(1); double x2 = PG_GETARG_FLOAT8(2); NDBOX *result; int size; int i; if (DIM(cube) + 1 > CUBE_MAX_DIM) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("can't extend cube"), errdetail("A cube cannot have more than %d dimensions.", CUBE_MAX_DIM))); 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 { 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; } PG_FREE_IF_COPY(cube, 0); PG_RETURN_NDBOX(result); }
Datum cube_out(PG_FUNCTION_ARGS) { NDBOX *cube = PG_GETARG_NDBOX(0); StringInfoData buf; int dim = DIM(cube); int i; int ndig; initStringInfo(&buf); /* * Get the number of digits to display. */ ndig = DBL_DIG + extra_float_digits; if (ndig < 1) ndig = 1; /* * while printing the first (LL) corner, check if it is equal to the * second one */ appendStringInfoChar(&buf, '('); for (i = 0; i < dim; i++) { if (i > 0) appendStringInfoString(&buf, ", "); appendStringInfo(&buf, "%.*g", ndig, LL_COORD(cube, i)); } appendStringInfoChar(&buf, ')'); if (!cube_is_point_internal(cube)) { appendStringInfoString(&buf, ",("); for (i = 0; i < dim; i++) { if (i > 0) appendStringInfoString(&buf, ", "); appendStringInfo(&buf, "%.*g", ndig, UR_COORD(cube, i)); } appendStringInfoChar(&buf, ')'); } PG_FREE_IF_COPY(cube, 0); PG_RETURN_CSTRING(buf.data); }
Datum cube_subset(PG_FUNCTION_ARGS) { NDBOX *c = PG_GETARG_NDBOX(0); ArrayType *idx = PG_GETARG_ARRAYTYPE_P(1); NDBOX *result; int size, dim, i; int *dx; if (array_contains_nulls(idx)) ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("cannot work with arrays containing NULLs"))); dx = (int32 *) ARR_DATA_PTR(idx); dim = ARRNELEMS(idx); size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim; result = (NDBOX *) palloc0(size); SET_VARSIZE(result, size); result->dim = dim; for (i = 0; i < dim; i++) { if ((dx[i] <= 0) || (dx[i] > c->dim)) { pfree(result); ereport(ERROR, (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("Index out of bounds"))); } result->x[i] = c->x[dx[i] - 1]; result->x[i + dim] = c->x[dx[i] + c->dim - 1]; } PG_FREE_IF_COPY(c, 0); PG_RETURN_NDBOX(result); }
/* ** The GiST Consistent method for boxes ** Should return false if for all data items x below entry, ** the predicate x op query == FALSE, where op is the oper ** corresponding to strategy in the pg_amop table. */ Datum g_cube_consistent(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); NDBOX *query = PG_GETARG_NDBOX(1); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); bool res; /* * if entry is not leaf, use g_cube_internal_consistent, else use * g_cube_leaf_consistent */ if (GIST_LEAF(entry)) res = g_cube_leaf_consistent( DatumGetNDBOX(entry->key), query, strategy); else res = g_cube_internal_consistent( DatumGetNDBOX(entry->key), query, strategy); PG_FREE_IF_COPY(query,1); PG_RETURN_BOOL(res); }
/* Add a dimension to an existing cube with the same values for the new coordinate */ Datum cube_c_f8(PG_FUNCTION_ARGS) { NDBOX *c = 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++) { result->x[i] = c->x[i]; result->x[result->dim + i] = c->x[c->dim + i]; } result->x[result->dim - 1] = x; result->x[2 * result->dim - 1] = x; PG_FREE_IF_COPY(c, 0); PG_RETURN_NDBOX(result); }
/* cube_inter */ Datum cube_inter(PG_FUNCTION_ARGS) { NDBOX *a = PG_GETARG_NDBOX(0); NDBOX *b = PG_GETARG_NDBOX(1); NDBOX *result; bool swapped = false; int i; 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) { NDBOX *tmp = b; b = a; a = tmp; swapped = true; } /* * 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++) { 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]); } for (i = b->dim; i < a->dim; i++) { result->x[i] = 0; result->x[i + a->dim] = 0; } /* compute the intersection */ for (i = 0; i < a->dim; i++) { 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]); } if (swapped) { PG_FREE_IF_COPY(b, 0); PG_FREE_IF_COPY(a, 1); } else { PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(b, 1); } /* * Is it OK to return a non-null intersection for non-overlapping boxes? */ PG_RETURN_NDBOX(result); }
/* Increase or decrease box size by a radius in at least n dimensions. */ Datum cube_enlarge(PG_FUNCTION_ARGS) { NDBOX *a = PG_GETARG_NDBOX(0); double r = PG_GETARG_FLOAT8(1); int32 n = PG_GETARG_INT32(2); NDBOX *result; int dim = 0; int size; int i, j; if (n > CUBE_MAX_DIM) n = CUBE_MAX_DIM; if (r > 0 && n > 0) dim = n; if (DIM(a) > dim) dim = DIM(a); size = CUBE_SIZE(dim); result = (NDBOX *) palloc0(size); SET_VARSIZE(result, size); SET_DIM(result, dim); for (i = 0, j = dim; i < DIM(a); i++, j++) { if (LL_COORD(a, i) >= UR_COORD(a, i)) { result->x[i] = UR_COORD(a, i) - r; result->x[j] = LL_COORD(a, i) + r; } else { result->x[i] = LL_COORD(a, i) - r; result->x[j] = UR_COORD(a, i) + r; } if (result->x[i] > result->x[j]) { result->x[i] = (result->x[i] + result->x[j]) / 2; result->x[j] = result->x[i]; } } /* dim > a->dim only if r > 0 */ for (; i < dim; i++, j++) { result->x[i] = -r; 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); }
/* cube_inter */ Datum cube_inter(PG_FUNCTION_ARGS) { NDBOX *a = PG_GETARG_NDBOX(0); NDBOX *b = PG_GETARG_NDBOX(1); NDBOX *result; bool swapped = false; int i; int dim; int size; /* 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); 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] = 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)) ); } /* continue on the higher dimensions only present in 'a' */ for (; i < DIM(a); i++) { 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)) ); } /* * 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); result = repalloc(result, size); SET_VARSIZE(result, size); SET_POINT_BIT(result); } if (swapped) { PG_FREE_IF_COPY(b, 0); PG_FREE_IF_COPY(a, 1); } else { PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(b, 1); } /* * Is it OK to return a non-null intersection for non-overlapping boxes? */ PG_RETURN_NDBOX(result); }