/* We might as well run this even on failure. */
cube_scanner_finish(scanner);
PG_RETURN_NDBOX_P(result);
}
/* **Allowstheconstructionofacubefrom2float[]'s
*/
Datum
cube_a_f8_f8(PG_FUNCTION_ARGS)
{
ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *ll = PG_GETARG_ARRAYTYPE_P(1);
NDBOX *result; int i; int dim; int size; bool point; double *dur,
*dll;
if (array_contains_nulls(ur) || array_contains_nulls(ll))
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("cannot work with arrays containing NULLs")));
dim = ARRNELEMS(ur); if (dim > 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 (ARRNELEMS(ll) != dim)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("UR and LL arrays must be of same length")));
dur = ARRPTR(ur);
dll = ARRPTR(ll);
/* 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);
SET_DIM(result, dim);
for (i = 0; i < dim; i++)
result->x[i] = dur[i];
if (!point)
{ for (i = 0; i < dim; i++)
result->x[i + dim] = dll[i];
} else
SET_POINT_BIT(result);
PG_RETURN_NDBOX_P(result);
}
/* **Allowstheconstructionofazero-volumecubefromafloat[]
*/
Datum
cube_a_f8(PG_FUNCTION_ARGS)
{
ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0);
NDBOX *result; int i; int dim; int size; double *dur;
if (array_contains_nulls(ur))
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("cannot work with arrays containing NULLs")));
dim = ARRNELEMS(ur); 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)));
Datum
cube_subset(PG_FUNCTION_ARGS)
{
NDBOX *c = PG_GETARG_NDBOX_P(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)));
Datum
cube_out(PG_FUNCTION_ARGS)
{
NDBOX *cube = PG_GETARG_NDBOX_P(0);
StringInfoData buf; int dim = DIM(cube); int i;
initStringInfo(&buf);
appendStringInfoChar(&buf, '('); for (i = 0; i < dim; i++)
{ if (i > 0)
appendStringInfoString(&buf, ", ");
appendStringInfoString(&buf, float8out_internal(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, ", ");
appendStringInfoString(&buf, float8out_internal(UR_COORD(cube, i)));
}
appendStringInfoChar(&buf, ')');
}
/* *cube_send-abinaryoutputhandlerforcubetype
*/
Datum
cube_send(PG_FUNCTION_ARGS)
{
NDBOX *cube = PG_GETARG_NDBOX_P(0);
StringInfoData buf;
int32 i,
nitems = DIM(cube);
pq_begintypsend(&buf);
pq_sendint32(&buf, cube->header); if (!IS_POINT(cube))
nitems += nitems; /* for symmetry with cube_recv, we don't use LL_COORD/UR_COORD here */ for (i = 0; i < nitems; i++)
pq_sendfloat8(&buf, cube->x[i]);
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
/* *cube_recv-abinaryinputhandlerforcubetype
*/
Datum
cube_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
int32 header;
int32 i,
nitems;
NDBOX *cube;
header = pq_getmsgint(buf, sizeof(int32));
nitems = (header & DIM_MASK); if (nitems > CUBE_MAX_DIM)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("cube dimension is too large"),
errdetail("A cube cannot have more than %d dimensions.",
CUBE_MAX_DIM))); if ((header & POINT_BIT) == 0)
nitems += nitems;
cube = palloc(offsetof(NDBOX, x) + sizeof(double) * nitems);
SET_VARSIZE(cube, offsetof(NDBOX, x) + sizeof(double) * nitems);
cube->header = header; for (i = 0; i < nitems; i++)
cube->x[i] = pq_getmsgfloat8(buf);
maxoff = OffsetNumberNext(maxoff); for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
{ /* *Ifwe'vealreadydecidedwheretoplacethisitem,justputiton *therightlist.Otherwise,weneedtofigureoutwhichpageneeds *theleastenlargementinordertostoretheitem.
*/
if (i == seed_1)
{
*left++ = i;
v->spl_nleft++; continue;
} elseif (i == seed_2)
{
*right++ = i;
v->spl_nright++; continue;
}
void
rt_cube_size(NDBOX *a, double *size)
{ double result; int i;
if (a == (NDBOX *) NULL)
{ /* special case for GiST */
result = 0.0;
} elseif (IS_POINT(a) || DIM(a) == 0)
{ /* necessarily has zero size */
result = 0.0;
} else
{
result = 1.0; for (i = 0; i < DIM(a); i++)
result *= fabs(UR_COORD(a, i) - LL_COORD(a, i));
}
*size = result;
}
/* make up a metric in which one box will be 'lower' than the other
-- this can be useful for sorting and to determine uniqueness */
int32
cube_cmp_v0(NDBOX *a, NDBOX *b)
{ int i; int dim;
dim = Min(DIM(a), DIM(b));
/* compare the common dimensions */ for (i = 0; i < dim; i++)
{ if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
Min(LL_COORD(b, i), UR_COORD(b, i))) return1; 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(LL_COORD(a, i), UR_COORD(a, i)) >
Max(LL_COORD(b, i), UR_COORD(b, i))) return1; 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 (DIM(a) > DIM(b))
{ for (i = dim; i < DIM(a); i++)
{ if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0) return1; if (Min(LL_COORD(a, i), UR_COORD(a, i)) < 0) return -1;
} for (i = dim; i < DIM(a); i++)
{ if (Max(LL_COORD(a, i), UR_COORD(a, i)) > 0) return1; if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0) return -1;
}
/* *ifallcommondimensionsareequal,thecubewithmoredimensions *wins
*/ return1;
} if (DIM(a) < DIM(b))
{ for (i = dim; i < DIM(b); i++)
{ if (Min(LL_COORD(b, i), UR_COORD(b, i)) > 0) return -1; if (Min(LL_COORD(b, i), UR_COORD(b, i)) < 0) return1;
} for (i = dim; i < DIM(b); i++)
{ if (Max(LL_COORD(b, i), UR_COORD(b, i)) > 0) return -1; if (Max(LL_COORD(b, i), UR_COORD(b, i)) < 0) return1;
}
if (DIM(a) < DIM(b))
{ /* *thefurthercomparisonswillmakesenseiftheexcessdimensionsof *(b)werezeroesSincebothULandURcoordinatesmustbezero,we *cancheckthemallwithoutworryingaboutwhichiswhich.
*/ for (i = DIM(a); i < DIM(b); i++)
{ if (LL_COORD(b, i) != 0) returnfalse; if (UR_COORD(b, i) != 0) returnfalse;
}
}
/* Can't care less about the excess dimensions of (a), if any */ for (i = 0; i < Min(DIM(a), DIM(b)); i++)
{ if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
Min(LL_COORD(b, i), UR_COORD(b, i))) returnfalse; if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
Max(LL_COORD(b, i), UR_COORD(b, i))) returnfalse;
}
/* swap the box pointers if needed */ if (DIM(a) < DIM(b))
{
NDBOX *tmp = b;
b = a;
a = tmp;
}
/* compare within the dimensions of (b) */ for (i = 0; i < DIM(b); i++)
{ if (Min(LL_COORD(a, i), UR_COORD(a, i)) > Max(LL_COORD(b, i), UR_COORD(b, i))) returnfalse; if (Max(LL_COORD(a, i), UR_COORD(a, i)) < Min(LL_COORD(b, i), UR_COORD(b, i))) returnfalse;
}
/* compare to zero those dimensions in (a) absent in (b) */ for (i = DIM(b); i < DIM(a); i++)
{ if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0) returnfalse; if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0) returnfalse;
}
/* Distance */ /* The distance is computed as a per axis sum of the squared distances between1DprojectionsoftheboxesontoCartesianaxes.Assumingzero distancebetweenoverlappingprojections,thismetriccoincideswiththe
"common sense" geometric distance */
Datum
cube_distance(PG_FUNCTION_ARGS)
{
NDBOX *a = PG_GETARG_NDBOX_P(0),
*b = PG_GETARG_NDBOX_P(1); bool swapped = false; double d,
distance; int i;
/* swap the box pointers if needed */ if (DIM(a) < DIM(b))
{
NDBOX *tmp = b;
b = a;
a = tmp;
swapped = true;
}
distance = 0.0; /* compute within the dimensions of (b) */ for (i = 0; i < DIM(b); i++)
{
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 = DIM(b); i < DIM(a); i++)
{
d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0);
distance += d * d;
}
Datum
distance_taxicab(PG_FUNCTION_ARGS)
{
NDBOX *a = PG_GETARG_NDBOX_P(0),
*b = PG_GETARG_NDBOX_P(1); bool swapped = false; double distance; int i;
/* swap the box pointers if needed */ if (DIM(a) < DIM(b))
{
NDBOX *tmp = b;
b = a;
a = tmp;
swapped = true;
}
distance = 0.0; /* compute within the dimensions of (b) */ for (i = 0; i < DIM(b); i++)
distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
LL_COORD(b, i), UR_COORD(b, i)));
/* compute distance to zero for those dimensions in (a) absent in (b) */ for (i = DIM(b); i < DIM(a); i++)
distance += fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0));
Datum
distance_chebyshev(PG_FUNCTION_ARGS)
{
NDBOX *a = PG_GETARG_NDBOX_P(0),
*b = PG_GETARG_NDBOX_P(1); bool swapped = false; double d,
distance; int i;
/* swap the box pointers if needed */ if (DIM(a) < DIM(b))
{
NDBOX *tmp = b;
b = a;
a = tmp;
swapped = true;
}
distance = 0.0; /* compute within the dimensions of (b) */ for (i = 0; i < DIM(b); i++)
{
d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i),
LL_COORD(b, i), UR_COORD(b, i))); if (d > distance)
distance = d;
}
/* compute distance to zero for those dimensions in (a) absent in (b) */ for (i = DIM(b); i < DIM(a); i++)
{
d = fabs(distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0)); if (d > distance)
distance = d;
}
/* 0 is the only unsupported coordinate value */ if (coord == 0)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("zero cube index is not defined")));
/* Return inversed value for negative coordinate */ if (coord < 0)
{
coord = -coord;
inverse = true;
}
if (coord <= 2 * DIM(cube))
{ /* dimension index */ int index = (coord - 1) / 2;
/* whether this is upper bound (lower bound otherwise) */ bool upper = ((coord - 1) % 2 == 1);
staticdouble
distance_1D(double a1, double a2, double b1, double b2)
{ /* interval (a) is entirely on the left of (b) */ if ((a1 <= b1) && (a2 <= b1) && (a1 <= b2) && (a2 <= b2)) return (Min(b1, b2) - Max(a1, a2));
/* interval (a) is entirely on the right of (b) */ if ((a1 > b1) && (a2 > b1) && (a1 > b2) && (a2 > b2)) return (Min(a1, a2) - Max(b1, b2));
/* the rest are all sorts of intersections */ return0.0;
}
/* Test if a box is also a point */
Datum
cube_is_point(PG_FUNCTION_ARGS)
{
NDBOX *cube = PG_GETARG_NDBOX_P(0); bool result;
result = cube_is_point_internal(cube);
PG_FREE_IF_COPY(cube, 0);
PG_RETURN_BOOL(result);
}
staticbool
cube_is_point_internal(NDBOX *cube)
{ int i;
if (IS_POINT(cube)) returntrue;
/* *Evenifthepoint-flagisnotset,allthelower-leftcoordinatesmight *matchtheupper-rightcoordinates,sothatthevalueisinfacta *point.Suchvaluesdon'tarisewithcurrentcode-thepointflagis *alwayssetifappropriate-buttheymightbepresenton-diskin *clustersupgradedfrompre-9.4versions.
*/ for (i = 0; i < DIM(cube); i++)
{ if (LL_COORD(cube, i) != UR_COORD(cube, i)) returnfalse;
} returntrue;
}
/* Return dimensions in use in the data structure */
Datum
cube_dim(PG_FUNCTION_ARGS)
{
NDBOX *c = PG_GETARG_NDBOX_P(0); int dim = DIM(c);
PG_FREE_IF_COPY(c, 0);
PG_RETURN_INT32(dim);
}
/* Return a specific normalized LL coordinate */
Datum
cube_ll_coord(PG_FUNCTION_ARGS)
{
NDBOX *c = PG_GETARG_NDBOX_P(0); int n = PG_GETARG_INT32(1); double result;
if (DIM(c) >= n && n > 0)
result = Min(LL_COORD(c, n - 1), UR_COORD(c, n - 1)); else
result = 0;
/* Return a specific normalized UR coordinate */
Datum
cube_ur_coord(PG_FUNCTION_ARGS)
{
NDBOX *c = PG_GETARG_NDBOX_P(0); int n = PG_GETARG_INT32(1); double result;
if (DIM(c) >= n && n > 0)
result = Max(LL_COORD(c, n - 1), UR_COORD(c, n - 1)); else
result = 0;
/* 0 is the only unsupported coordinate value */ if (coord == 0)
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("zero cube index is not defined")));
/* Return inversed value for negative coordinate */ if (coord < 0)
{
coord = -coord;
inverse = true;
}
if (coord <= 2 * DIM(cube))
{ /* dimension index */ int index = (coord - 1) / 2;
/* whether this is upper bound (lower bound otherwise) */ bool upper = ((coord - 1) % 2 == 1);
if (IS_POINT(cube))
{
result = cube->x[index];
} else
{ if (upper)
result = Max(cube->x[index], cube->x[index + DIM(cube)]); else
result = Min(cube->x[index], cube->x[index + DIM(cube)]);
}
} else
{ /* *Returnzeroifcoordinateisoutofbound.Thatreproduceslogic *ofhowcubeswithlowdimensionnumberareexpandedduringGiST *indexing.
*/
result = 0.0;
}
/* Inverse value if needed */ if (inverse)
result = -result;
PG_RETURN_FLOAT8(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_P(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);
/* Create a one dimensional box with identical upper and lower coordinates */
Datum
cube_f8(PG_FUNCTION_ARGS)
{ double x = PG_GETARG_FLOAT8(0);
NDBOX *result; int size;
/* Add a dimension to an existing cube with the same values for the new
coordinate */
Datum
cube_c_f8(PG_FUNCTION_ARGS)
{
NDBOX *cube = PG_GETARG_NDBOX_P(0); double x = PG_GETARG_FLOAT8(1);
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))
{
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;
}
/* Add a dimension to an existing cube */
Datum
cube_c_f8_f8(PG_FUNCTION_ARGS)
{
NDBOX *cube = PG_GETARG_NDBOX_P(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)));