diff --git a/contrib/cube/cube--1.0.sql b/contrib/cube/cube--1.0.sql index 0307811..27df4f7 100644 --- a/contrib/cube/cube--1.0.sql +++ b/contrib/cube/cube--1.0.sql @@ -10,14 +10,6 @@ RETURNS cube AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; -CREATE FUNCTION cube(float8[], float8[]) RETURNS cube -AS 'MODULE_PATHNAME', 'cube_a_f8_f8' -LANGUAGE C IMMUTABLE STRICT; - -CREATE FUNCTION cube(float8[]) RETURNS cube -AS 'MODULE_PATHNAME', 'cube_a_f8' -LANGUAGE C IMMUTABLE STRICT; - CREATE FUNCTION cube_out(cube) RETURNS cstring AS 'MODULE_PATHNAME' @@ -32,6 +24,53 @@ CREATE TYPE cube ( COMMENT ON TYPE cube IS 'multi-dimensional cube ''(FLOAT-1, FLOAT-2, ..., FLOAT-N), (FLOAT-1, FLOAT-2, ..., FLOAT-N)'''; +-- Cube creation with types + +CREATE FUNCTION cube(float8[]) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_arr_FLOAT8' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube(float8[], float8[]) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_arr_arr_FLOAT8' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube(float8) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_num_FLOAT8' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube(float8, float8) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_num_num_FLOAT8' LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION cube_f4(float8[]) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_arr_FLOAT4' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_f4(float8[], float8[]) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_arr_arr_FLOAT4' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_f4(float8) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_num_FLOAT4' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_f4(float8, float8) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_num_num_FLOAT4' LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION cube_i4(float8[]) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_arr_INT4' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_i4(float8[], float8[]) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_arr_arr_INT4' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_i4(float8) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_num_INT4' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_i4(float8, float8) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_num_num_INT4' LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION cube_i2(float8[]) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_arr_INT2' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_i2(float8[], float8[]) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_arr_arr_INT2' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_i2(float8) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_num_INT2' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_i2(float8, float8) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_num_num_INT2' LANGUAGE C IMMUTABLE STRICT; + +CREATE FUNCTION cube_i1(float8[]) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_arr_INT1' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_i1(float8[], float8[]) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_arr_arr_INT1' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_i1(float8) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_num_INT1' LANGUAGE C IMMUTABLE STRICT; +CREATE FUNCTION cube_i1(float8, float8) + RETURNS cube AS 'MODULE_PATHNAME', 'cube_num_num_INT1' LANGUAGE C IMMUTABLE STRICT; + -- -- External C-functions for R-tree methods -- @@ -157,14 +196,6 @@ RETURNS float8 AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT; -CREATE FUNCTION cube(float8) RETURNS cube -AS 'MODULE_PATHNAME', 'cube_f8' -LANGUAGE C IMMUTABLE STRICT; - -CREATE FUNCTION cube(float8, float8) RETURNS cube -AS 'MODULE_PATHNAME', 'cube_f8_f8' -LANGUAGE C IMMUTABLE STRICT; - CREATE FUNCTION cube(cube, float8) RETURNS cube AS 'MODULE_PATHNAME', 'cube_c_f8' LANGUAGE C IMMUTABLE STRICT; diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c index dab0e6e..9b50d2a 100644 --- a/contrib/cube/cube.c +++ b/contrib/cube/cube.c @@ -38,8 +38,6 @@ PG_FUNCTION_INFO_V1(cube_in); PG_FUNCTION_INFO_V1(cube_a_f8_f8); PG_FUNCTION_INFO_V1(cube_a_f8); PG_FUNCTION_INFO_V1(cube_out); -PG_FUNCTION_INFO_V1(cube_f8); -PG_FUNCTION_INFO_V1(cube_f8_f8); PG_FUNCTION_INFO_V1(cube_c_f8); PG_FUNCTION_INFO_V1(cube_c_f8_f8); PG_FUNCTION_INFO_V1(cube_dim); @@ -51,8 +49,6 @@ Datum cube_in(PG_FUNCTION_ARGS); Datum cube_a_f8_f8(PG_FUNCTION_ARGS); Datum cube_a_f8(PG_FUNCTION_ARGS); Datum cube_out(PG_FUNCTION_ARGS); -Datum cube_f8(PG_FUNCTION_ARGS); -Datum cube_f8_f8(PG_FUNCTION_ARGS); Datum cube_c_f8(PG_FUNCTION_ARGS); Datum cube_c_f8_f8(PG_FUNCTION_ARGS); Datum cube_dim(PG_FUNCTION_ARGS); @@ -61,9 +57,42 @@ Datum cube_ur_coord(PG_FUNCTION_ARGS); Datum cube_subset(PG_FUNCTION_ARGS); /* + * Input/Output for typed cubes + */ + +static NDBOX* cube_arr_arr(Datum ur_datum, Datum ll_datum, int type); +static NDBOX* cube_arr(Datum ur_datum, int type); +static NDBOX* cube_num(Datum x_datum, int type); +static NDBOX* cube_num_num(Datum x0_datum, Datum x1_datum, int type); + +CUBE_TYPE_WRAPPER1(cube_arr, FLOAT8); +CUBE_TYPE_WRAPPER1(cube_num, FLOAT8); +CUBE_TYPE_WRAPPER2(cube_arr_arr, FLOAT8); +CUBE_TYPE_WRAPPER2(cube_num_num, FLOAT8); + +CUBE_TYPE_WRAPPER1(cube_arr, FLOAT4); +CUBE_TYPE_WRAPPER1(cube_num, FLOAT4); +CUBE_TYPE_WRAPPER2(cube_arr_arr, FLOAT4); +CUBE_TYPE_WRAPPER2(cube_num_num, FLOAT4); + +CUBE_TYPE_WRAPPER1(cube_arr, INT4); +CUBE_TYPE_WRAPPER1(cube_num, INT4); +CUBE_TYPE_WRAPPER2(cube_arr_arr, INT4); +CUBE_TYPE_WRAPPER2(cube_num_num, INT4); + +CUBE_TYPE_WRAPPER1(cube_arr, INT2); +CUBE_TYPE_WRAPPER1(cube_num, INT2); +CUBE_TYPE_WRAPPER2(cube_arr_arr, INT2); +CUBE_TYPE_WRAPPER2(cube_num_num, INT2); + +CUBE_TYPE_WRAPPER1(cube_arr, INT1); +CUBE_TYPE_WRAPPER1(cube_num, INT1); +CUBE_TYPE_WRAPPER2(cube_arr_arr, INT1); +CUBE_TYPE_WRAPPER2(cube_num_num, INT1); + +/* ** GiST support methods */ - PG_FUNCTION_INFO_V1(g_cube_consistent); PG_FUNCTION_INFO_V1(g_cube_compress); PG_FUNCTION_INFO_V1(g_cube_decompress); @@ -102,7 +131,6 @@ Datum cube_cmp(PG_FUNCTION_ARGS); /* ** R-tree support functions */ - PG_FUNCTION_INFO_V1(cube_contains); PG_FUNCTION_INFO_V1(cube_contained); PG_FUNCTION_INFO_V1(cube_overlap); @@ -131,6 +159,7 @@ Datum cube_enlarge(PG_FUNCTION_ARGS); /* ** For internal use only */ +void check_coord(double num, int type); int32 cube_cmp_v0(NDBOX *a, NDBOX *b); bool cube_contains_v0(NDBOX *a, NDBOX *b); bool cube_overlap_v0(NDBOX *a, NDBOX *b); @@ -147,6 +176,126 @@ static double distance_1D(double a1, double a2, double b1, double b2); /***************************************************************************** + * Typed cube abstraction layer + *****************************************************************************/ +double get_coord(NDBOX *cube, int i) +{ + switch (TYPE(cube)) + { + case CUBE_FLOAT4: + return cube->coord_f4[i]; + case CUBE_INT4: + return cube->coord_i4[i]; + case CUBE_INT2: + return cube->coord_i2[i]; + case CUBE_INT1: + return cube->coord_i1[i]; + case CUBE_FLOAT8: + default: + return cube->coord_f8[i]; + } +} + +void set_coord(NDBOX *cube, int i, double value) +{ + switch (TYPE(cube)) + { + case CUBE_FLOAT4: + cube->coord_f4[i] = value; + break; + case CUBE_INT4: + cube->coord_i4[i] = value; + break; + case CUBE_INT2: + cube->coord_i2[i] = value; + break; + case CUBE_INT1: + cube->coord_i1[i] = value; + break; + case CUBE_FLOAT8: + default: + cube->coord_f8[i] = value; + break; + } +} + +NDBOX* init_cube(int dim, int point, int type) +{ + NDBOX *cube; + int size; + + switch (type) + { + case CUBE_FLOAT4: + size = offsetof(NDBOX, coord_f8[0]) + dim*(!point + 1)*sizeof(float); + break; + case CUBE_INT4: + size = offsetof(NDBOX, coord_f8[0]) + dim*(!point + 1)*sizeof(int); + break; + case CUBE_INT2: + size = offsetof(NDBOX, coord_f8[0]) + dim*(!point + 1)*sizeof(short); + break; + case CUBE_INT1: + size = offsetof(NDBOX, coord_f8[0]) + dim*(!point + 1)*sizeof(char); + break; + case CUBE_FLOAT8: + default: + size = offsetof(NDBOX, coord_f8[0]) + dim*(!point + 1)*sizeof(double); + break; + } + + cube = (NDBOX *) palloc0(size); + SET_VARSIZE(cube, size); + SET_DIM(cube, dim); + SET_TYPE(cube, type); + if (point) + SET_POINT_BIT(cube); + + return cube; +} + +void cube_to_point(NDBOX *cube) +{ + int new_size; + + new_size = offsetof(NDBOX, coord_f8[0]) + + (VARSIZE(cube) - offsetof(NDBOX, coord_f8[0]))/2; + + cube = repalloc(cube, new_size); + SET_VARSIZE(cube, new_size); + SET_POINT_BIT(cube); +} + +void check_coord(double num, int type) +{ + switch (type) + { + case CUBE_INT4: + if ((num < INT_MIN) || (num > INT_MAX)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("Cube coordinate out of requested type range"), + errdetail("Value (%i) out of signed int4 type", (int)num))); + break; + case CUBE_INT2: + if ((num < SHRT_MIN) || (num > SHRT_MAX)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("Cube coordinate out of requested type range"), + errdetail("Value (%i) out of signed int2 type", (int)num))); + break; + case CUBE_INT1: + if ( (num < SCHAR_MIN) || (num > SCHAR_MAX)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("Cube coordinate out of requested type range"), + errdetail("Value (%i) out of signed int1 type", (int)num))); + break; + } +} + + +/***************************************************************************** * Input/Output functions *****************************************************************************/ @@ -168,21 +317,18 @@ cube_in(PG_FUNCTION_ARGS) PG_RETURN_NDBOX(result); } - /* ** Allows the construction of a cube from 2 float[]'s */ -Datum -cube_a_f8_f8(PG_FUNCTION_ARGS) +static NDBOX* +cube_arr_arr(Datum ur_datum, Datum ll_datum, int type) { - ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0); - ArrayType *ll = PG_GETARG_ARRAYTYPE_P(1); + ArrayType *ur = DatumGetArrayTypeP(ur_datum); + ArrayType *ll = DatumGetArrayTypeP(ll_datum); NDBOX *result; - int i; - int dim; - int size; - double *dur, - *dll; + int i, dim; + bool point = true; + double *dur, *dll; if (array_contains_nulls(ur) || array_contains_nulls(ll)) ereport(ERROR, @@ -197,32 +343,34 @@ cube_a_f8_f8(PG_FUNCTION_ARGS) dur = ARRPTR(ur); dll = ARRPTR(ll); - - size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim; - result = (NDBOX *) palloc0(size); - SET_VARSIZE(result, size); - result->dim = dim; + result = init_cube(dim, 0, type); for (i = 0; i < dim; i++) { - result->x[i] = dur[i]; - result->x[i + dim] = dll[i]; + check_coord(dur[i], type); + set_coord(result, i, dur[i]); + check_coord(dll[i], type); + set_coord(result, i+dim, dll[i]); + if (dur[i] != dll[i]) + point = false; } - PG_RETURN_NDBOX(result); + if (point) + cube_to_point(result); + + return result; } + /* ** Allows the construction of a zero-volume cube from a float[] */ -Datum -cube_a_f8(PG_FUNCTION_ARGS) +static NDBOX* +cube_arr(Datum ur_datum, int type) { - ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0); + ArrayType *ur = DatumGetArrayTypeP(ur_datum); NDBOX *result; - int i; - int dim; - int size; + int i, dim; double *dur; if (array_contains_nulls(ur)) @@ -231,21 +379,56 @@ cube_a_f8(PG_FUNCTION_ARGS) errmsg("cannot work with arrays containing NULLs"))); dim = ARRNELEMS(ur); - dur = ARRPTR(ur); - size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim; - result = (NDBOX *) palloc0(size); - SET_VARSIZE(result, size); - result->dim = dim; + result = init_cube(dim, 1, type); - for (i = 0; i < dim; i++) + for (i = 0; i < dim; i++){ + check_coord(dur[i], type); + set_coord(result, i, dur[i]); + } + + return result; +} + +/* Create a one dimensional box with identical upper and lower coordinates */ +static NDBOX* +cube_num(Datum x_datum, int type) +{ + double x = DatumGetFloat8(x_datum); + NDBOX *result; + + result = init_cube(1, 1, type); + check_coord(x, type); + set_coord(result, 0, x); + + return result; +} + +/* Create a one dimensional box */ +static NDBOX* +cube_num_num(Datum x0_datum, Datum x1_datum, int type) +{ + double x0 = DatumGetFloat8(x0_datum); + double x1 = DatumGetFloat8(x1_datum); + NDBOX *result; + + if (x0 == x1) + { + result = init_cube(1, 1, type); + check_coord(x0, type); + set_coord(result, 0, x0); + } + else { - result->x[i] = dur[i]; - result->x[i + dim] = dur[i]; + result = init_cube(1, 0, type); + check_coord(x0, type); + set_coord(result, 0, x0); + check_coord(x1, type); + set_coord(result, 1, x1); } - PG_RETURN_NDBOX(result); + return result; } Datum @@ -254,9 +437,7 @@ 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 dim, i; int *dx; if (array_contains_nulls(idx)) @@ -267,35 +448,33 @@ cube_subset(PG_FUNCTION_ARGS) 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; + result = init_cube(dim, IS_POINT(c), TYPE(c)); 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, (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]; + set_coord(result, i, LL_COORD(c, dx[i]-1)); + if (!IS_POINT(c)) + set_coord(result, i+dim, UR_COORD(c, dx[i]-1)); } PG_FREE_IF_COPY(c, 0); PG_RETURN_NDBOX(result); } + Datum 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,24 +496,41 @@ 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 (!IS_POINT(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, ')'); } + /* + * print type unless it is float8 + */ + switch (TYPE(cube)) + { + case CUBE_FLOAT4: + appendStringInfo(&buf, ":f4"); + break; + case CUBE_INT4: + appendStringInfo(&buf, ":i4"); + break; + case CUBE_INT2: + appendStringInfo(&buf, ":i2"); + break; + case CUBE_INT1: + appendStringInfo(&buf, ":i1"); + break; + } + PG_FREE_IF_COPY(cube, 0); PG_RETURN_CSTRING(buf.data); } @@ -393,9 +589,6 @@ g_cube_union(PG_FUNCTION_ARGS) NDBOX *tmp; int i; - /* - * fprintf(stderr, "union\n"); - */ tmp = DatumGetNDBOX(entryvec->vector[0].key); /* @@ -414,33 +607,35 @@ g_cube_union(PG_FUNCTION_ARGS) PG_RETURN_POINTER(out); } + /* ** GiST Compress and Decompress methods for boxes ** do not do anything. */ - Datum g_cube_compress(PG_FUNCTION_ARGS) { - PG_RETURN_DATUM(PG_GETARG_DATUM(0)); + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + GISTENTRY *retval; + NDBOX *cube = DatumGetNDBOX(PG_DETOAST_DATUM(entry->key)); + + retval = palloc(sizeof(GISTENTRY)); + gistentryinit(*retval, PointerGetDatum(cube), + entry->rel, entry->page, entry->offset, FALSE); + PG_RETURN_POINTER(retval); } 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); + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + GISTENTRY *retval; + NDBOX *cube = DatumGetNDBOX(PG_DETOAST_DATUM(entry->key)); + + retval = palloc(sizeof(GISTENTRY)); + gistentryinit(*retval, PointerGetDatum(cube), + entry->rel, entry->page, entry->offset, FALSE); + PG_RETURN_POINTER(retval); } @@ -464,14 +659,10 @@ g_cube_penalty(PG_FUNCTION_ARGS) rt_cube_size(DatumGetNDBOX(origentry->key), &tmp2); *result = (float) (tmp1 - tmp2); - /* - * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result); - */ PG_RETURN_FLOAT8(*result); } - /* ** The GiST PickSplit method for boxes ** We use Guttman's poly time split algorithm @@ -506,10 +697,7 @@ g_cube_picksplit(PG_FUNCTION_ARGS) OffsetNumber *left, *right; OffsetNumber maxoff; - - /* - * fprintf(stderr, "picksplit\n"); - */ + maxoff = entryvec->n - 2; nbytes = (maxoff + 2) * sizeof(OffsetNumber); v->spl_left = (OffsetNumber *) palloc(nbytes); @@ -625,6 +813,7 @@ g_cube_picksplit(PG_FUNCTION_ARGS) PG_RETURN_POINTER(v); } + /* ** Equality method */ @@ -640,9 +829,6 @@ g_cube_same(PG_FUNCTION_ARGS) else *result = FALSE; - /* - * fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" )); - */ PG_RETURN_NDBOX(result); } @@ -656,9 +842,6 @@ g_cube_leaf_consistent(NDBOX *key, { bool retval; - /* - * fprintf(stderr, "leaf_consistent, %d\n", strategy); - */ switch (strategy) { case RTOverlapStrategyNumber: @@ -681,6 +864,7 @@ g_cube_leaf_consistent(NDBOX *key, return (retval); } + bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, @@ -688,9 +872,6 @@ g_cube_internal_consistent(NDBOX *key, { bool retval; - /* - * fprintf(stderr, "internal_consistent, %d\n", strategy); - */ switch (strategy) { case RTOverlapStrategyNumber: @@ -728,57 +909,56 @@ NDBOX * cube_union_v0(NDBOX *a, NDBOX *b) { int i; + bool point_result = true; NDBOX *result; - 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; - } + /* let's try to guess result for same pointers */ + if (a == b) + return a; /* swap the box pointers if needed */ - if (a->dim < b->dim) + if (DIM(a) < DIM(b)) { NDBOX *tmp = b; - b = a; a = tmp; } - /* - * 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 = init_cube( DIM(a), 0, Min(TYPE(a), TYPE(b)) ); + + /* compute the union */ + 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]); + set_coord(result, i, Min( + Min(LL_COORD(a,i), UR_COORD(a,i)), + Min(LL_COORD(b,i), UR_COORD(b,i)) + )); + set_coord(result, i + DIM(a), Max( + Max(LL_COORD(a,i), UR_COORD(a,i)), + Max(LL_COORD(b,i), UR_COORD(b,i)) + )); + if (LL_COORD(result,i) != UR_COORD(result,i)) + point_result = false; } - for (i = b->dim; i < a->dim; i++) + for (i = DIM(b); i < DIM(a); i++) { - result->x[i] = 0; - result->x[i + a->dim] = 0; + set_coord(result, i, Min(0, + Min(LL_COORD(a,i), UR_COORD(a,i)) + )); + set_coord(result, i + DIM(a), Max(0, + Max(LL_COORD(a,i), UR_COORD(a,i)) + )); + if (LL_COORD(result,i) != UR_COORD(result,i)) + point_result = false; } - /* compute the union */ - for (i = 0; i < a->dim; i++) - { - 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]); - } + if (point_result) + cube_to_point(result); return (result); } + Datum cube_union(PG_FUNCTION_ARGS) { @@ -793,6 +973,7 @@ cube_union(PG_FUNCTION_ARGS) PG_RETURN_NDBOX(res); } + /* cube_inter */ Datum cube_inter(PG_FUNCTION_ARGS) @@ -800,24 +981,12 @@ cube_inter(PG_FUNCTION_ARGS) NDBOX *a = PG_GETARG_NDBOX(0); NDBOX *b = PG_GETARG_NDBOX(1); NDBOX *result; - bool swapped = false; + bool swapped = false, + point_result = true; 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) + if (DIM(a) < DIM(b)) { NDBOX *tmp = b; @@ -826,29 +995,36 @@ cube_inter(PG_FUNCTION_ARGS) 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 = init_cube( DIM(a), 0, Min(TYPE(a), TYPE(b)) ); + + 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]); + + set_coord(result, i, Max( + Min(LL_COORD(a,i), UR_COORD(a,i)), + Min(LL_COORD(b,i), UR_COORD(b,i)) + )); + set_coord(result, i + DIM(a), Min( + Max(LL_COORD(a,i), UR_COORD(a,i)), + Max(LL_COORD(b,i), UR_COORD(b,i)) + )); + if (LL_COORD(result, i) != UR_COORD(result, i)) + point_result = false; } - for (i = b->dim; i < a->dim; i++) + for (i = DIM(b); i < DIM(a); i++) { - result->x[i] = 0; - result->x[i + a->dim] = 0; + set_coord(result, i, Max(0, + Min(LL_COORD(a,i), UR_COORD(a,i)) + )); + set_coord(result, i + DIM(a), Min(0, + Max(LL_COORD(a,i), UR_COORD(a,i)) + )); + if (LL_COORD(result, i) != UR_COORD(result, i)) + point_result = false; } - /* 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 (point_result) + cube_to_point(result); if (swapped) { @@ -867,40 +1043,41 @@ cube_inter(PG_FUNCTION_ARGS) PG_RETURN_NDBOX(result); } + /* cube_size */ Datum 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); } + 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; } + /* 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 @@ -909,43 +1086,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 +1132,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; } @@ -983,6 +1160,7 @@ cube_cmp_v0(NDBOX *a, NDBOX *b) return 0; } + Datum cube_cmp(PG_FUNCTION_ARGS) { @@ -1098,36 +1276,37 @@ 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); } return (TRUE); } + Datum cube_contains(PG_FUNCTION_ARGS) { @@ -1142,6 +1321,7 @@ cube_contains(PG_FUNCTION_ARGS) PG_RETURN_BOOL(res); } + /* Contained */ /* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */ Datum @@ -1158,6 +1338,7 @@ cube_contained(PG_FUNCTION_ARGS) PG_RETURN_BOOL(res); } + /* Overlap */ /* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */ bool @@ -1173,7 +1354,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 +1363,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 +1415,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 +1426,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; } @@ -1274,6 +1453,7 @@ cube_distance(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(sqrt(distance)); } + static double distance_1D(double a1, double a2, double b1, double b2) { @@ -1289,35 +1469,30 @@ distance_1D(double a1, double a2, double b1, double b2) return (0.0); } + /* 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); + NDBOX *cube = PG_GETARG_NDBOX(0); + if (IS_POINT(cube)) + PG_RETURN_BOOL(TRUE); + else + PG_RETURN_BOOL(FALSE); } + /* Return dimensions in use in the data structure */ 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); } + /* Return a specific normalized LL coordinate */ Datum cube_ll_coord(PG_FUNCTION_ARGS) @@ -1326,8 +1501,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; @@ -1335,6 +1510,7 @@ cube_ll_coord(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(result); } + /* Return a specific normalized UR coordinate */ Datum cube_ur_coord(PG_FUNCTION_ARGS) @@ -1343,8 +1519,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; @@ -1352,6 +1528,7 @@ cube_ur_coord(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(result); } + /* Increase or decrease box size by a radius in at least n dimensions. */ Datum cube_enlarge(PG_FUNCTION_ARGS) @@ -1360,137 +1537,122 @@ cube_enlarge(PG_FUNCTION_ARGS) double r = PG_GETARG_FLOAT8(1); int32 n = PG_GETARG_INT32(2); NDBOX *result; - int dim = 0; - int size; - int i, - j, - k; + int i, j, + dim = 0, + shrunk_coordinates = 0; 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 *) palloc0(size); - SET_VARSIZE(result, size); - result->dim = dim; - for (i = 0, j = dim, k = a->dim; i < a->dim; i++, j++, k++) + if (DIM(a) > dim) + dim = DIM(a); + + result = init_cube( dim, 0, TYPE(a) ); + + 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; + set_coord(result, i, UR_COORD(a,i) - r); + set_coord(result, j, LL_COORD(a,i) + r); } else { - result->x[i] = a->x[i] - r; - result->x[j] = a->x[k] + r; + set_coord(result, i, LL_COORD(a,i) - r); + set_coord(result, j, UR_COORD(a,i) + r); } - if (result->x[i] > result->x[j]) + if (LL_COORD(result, i) > LL_COORD(result, j)) { - result->x[i] = (result->x[i] + result->x[j]) / 2; - result->x[j] = result->x[i]; + set_coord(result, i, + (LL_COORD(result, i) + LL_COORD(result, j)) / 2); + set_coord(result, j, LL_COORD(result, i)); + shrunk_coordinates++; } + else if (LL_COORD(result, i) == LL_COORD(result, j)) + shrunk_coordinates++; } /* dim > a->dim only if r > 0 */ for (; i < dim; i++, j++) { - result->x[i] = -r; - result->x[j] = r; + set_coord(result, i, -r); + set_coord(result, j, r); } + /* Point can arise in two cases: + 1) When argument is point and r == 0 + 2) When all coordinates was set to their averages */ + if ( (IS_POINT(a) && r == 0) || (shrunk_coordinates == dim) ) + cube_to_point(result); + PG_FREE_IF_COPY(a, 0); PG_RETURN_NDBOX(result); } -/* 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; - - size = offsetof(NDBOX, x[0]) +sizeof(double) * 2; - result = (NDBOX *) palloc0(size); - SET_VARSIZE(result, size); - result->dim = 1; - result->x[0] = result->x[1] = x; - - PG_RETURN_NDBOX(result); -} - -/* Create a one dimensional box */ -Datum -cube_f8_f8(PG_FUNCTION_ARGS) -{ - double x0 = PG_GETARG_FLOAT8(0); - double x1 = PG_GETARG_FLOAT8(1); - 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; - - PG_RETURN_NDBOX(result); -} /* 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); + NDBOX *cube = PG_GETARG_NDBOX(0); double x = PG_GETARG_FLOAT8(1); - NDBOX *result; - int size; + NDBOX *result; 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]; + result = init_cube( DIM(cube) + 1, 1, TYPE(cube) ); + for (i = 0; i < DIM(cube); i++) + set_coord(result, i, LL_COORD(cube, i)); + set_coord(result, DIM(result) - 1, x); + } + else + { + result = init_cube( DIM(cube) + 1, 0, TYPE(cube) ); + for (i = 0; i < DIM(cube); i++) + { + set_coord(result, i, LL_COORD(cube, i)); + set_coord(result, DIM(result) + i, UR_COORD(cube, i)); + } + set_coord(result, DIM(result) - 1, x); + set_coord(result, 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); } + /* Add a dimension to an existing cube */ 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)){ + result = init_cube( DIM(cube) + 1, 1, TYPE(cube) ); + for (i = 0; i < DIM(cube); i++) + set_coord(result, i, LL_COORD(cube, i)); + set_coord(result, DIM(result) - 1, x1); + } + else { - result->x[i] = c->x[i]; - result->x[result->dim + i] = c->x[c->dim + i]; + result = init_cube( DIM(cube) + 1, 0, TYPE(cube) ); + for (i = 0; i < DIM(cube); i++) + { + set_coord(result, i, LL_COORD(cube, i)); + set_coord(result, DIM(result) + i, UR_COORD(cube, i)); + } + set_coord(result, DIM(result) - 1, x1); + set_coord(result, 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..ab3414c 100644 --- a/contrib/cube/cubedata.h +++ b/contrib/cube/cubedata.h @@ -1,14 +1,112 @@ /* contrib/cube/cubedata.h */ + +/* Bigger dimensions count requires different memory allocation procedure */ #define CUBE_MAX_DIM (100) + +/* + * Main N-dimensional BOX datatype. + * + * Header contains info about NDBOX. For binary + * compatibility with old versions it is defined + * as uint32. + * Following information is stored: + * bits 0-7 : number of cube dimensions; + * bits 8-27 : not used; + * bits 28-30: cube coord type; + * bit 31 : point flag. If set, then NDBOX stores + * n dimensions instead of 2*n; + * + * Coordinate type choosed based on header info; + */ typedef struct NDBOX -{ - int32 vl_len_; /* varlena header (do not touch directly!) */ - unsigned int dim; - double x[1]; +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + unsigned int header; + union + { + double coord_f8[1]; + float coord_f4[1]; + signed int coord_i4[1]; + signed short coord_i2[1]; + signed char coord_i1[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) + +/* + * Types ordered from bigger size to lower. + * New cubes created from two existing with type = min(type1, type2) + */ +enum cube_types +{ + CUBE_FLOAT8, + CUBE_FLOAT4, + CUBE_INT4, + CUBE_INT2, + CUBE_INT1 +}; + + +/* + * Header access/modification macroses + */ +#define SET_DIM(cube, _dim) ( cube->header = _dim ) // overrides old data (!) +#define DIM(cube) ( cube->header & 0x7f ) +#define SET_TYPE(cube, type) ( cube->header |= (type << 28) ) +#define TYPE(cube) ( (cube->header & 0x70000000) >> 28 ) +#define SET_POINT_BIT(cube) ( cube->header |= 0x80000000 ) +#define IS_POINT(cube) ( (cube->header & 0x80000000) >> 31 ) + + +/* + * Macroses for generating wrappers over cube creation functions. + * That macroses passes type argument to underlying function. + * For example CUBE_TYPE_WRAPPER2(cube_arr_arr, INT4) generates + * function cube_arr_arr_INT4(double[], double[]) that toggles INT4 + * type to created cube. + * + * CUBE_TYPE_WRAPPER1 for single argument functions + * CUBE_TYPE_WRAPPER2 for functions with two arguments + */ +#define CUBE_TYPE_WRAPPER1(func, type) \ + PG_FUNCTION_INFO_V1( func ##_## type ); \ + Datum func ##_## type (PG_FUNCTION_ARGS); \ + Datum func ##_## type (PG_FUNCTION_ARGS) \ + { \ + Datum arg = PG_GETARG_DATUM(0); \ + PG_RETURN_NDBOX(func(arg, CUBE_##type)); \ + } + +#define CUBE_TYPE_WRAPPER2(func, type) \ + PG_FUNCTION_INFO_V1( func ##_## type ); \ + Datum func ##_## type (PG_FUNCTION_ARGS); \ + Datum func ##_## type (PG_FUNCTION_ARGS) \ + { \ + Datum arg1 = PG_GETARG_DATUM(0); \ + Datum arg2 = PG_GETARG_DATUM(1); \ + PG_RETURN_NDBOX(func(arg1, arg2, CUBE_##type)); \ + } + + +/* + * Abstraction layer for coordinate access. + */ +double get_coord(NDBOX *cube, int i); +void set_coord(NDBOX *cube, int i, double value); +NDBOX* init_cube(int dim, int point, int type); +void cube_to_point(NDBOX *cube); + +#define LL_COORD(cube, i) ( get_coord(cube, i) ) +#define UR_COORD(cube, i) ( \ + IS_POINT(cube) ? get_coord(cube, i) : get_coord(cube, i + DIM(cube)) ) + + +/* + * Various definitions + */ +#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) + diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y index d7205b8..757cebc 100644 --- a/contrib/cube/cubeparse.y +++ b/contrib/cube/cubeparse.y @@ -31,8 +31,11 @@ extern int cube_yyparse(NDBOX **result); extern void cube_yyerror(NDBOX **result, const char *message); static int delim_count(char *s, char delim); -static NDBOX * write_box(unsigned int dim, char *str1, char *str2); -static NDBOX * write_point_as_box(char *s, int dim); +static int check_dim(char *str1, char *str2); +static void check_coord(double num, int type); +static bool check_maxdim(int dim, char *str1); +static NDBOX * write_box(int dim, char *str1, char *str2, char *typestr); +static NDBOX * write_point_as_box(char *s, int dim, char *typestr); %} @@ -41,80 +44,71 @@ static NDBOX * write_point_as_box(char *s, int dim); %expect 0 %name-prefix="cube_yy" -%token CUBEFLOAT O_PAREN C_PAREN O_BRACKET C_BRACKET COMMA +%token CUBEFLOAT O_PAREN C_PAREN O_BRACKET C_BRACKET COMMA TYPMOD %start box /* Grammar follows */ %% - box: O_BRACKET paren_list COMMA paren_list C_BRACKET { int dim; - dim = delim_count($2, ',') + 1; - if ((delim_count($4, ',') + 1) != dim) - { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), - errdetail("Different point dimensions in (%s) and (%s).", - $2, $4))); - YYABORT; - } - if (dim > CUBE_MAX_DIM) { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), - errdetail("A cube cannot have more than %d dimensions.", - CUBE_MAX_DIM))); + if ( (dim = check_dim($2, $4)) && check_maxdim(dim, $2) ) + *((void **)result) = write_box(dim, $2, $4, ""); + else YYABORT; - } + } - *result = write_box( dim, $2, $4 ); + | O_BRACKET paren_list COMMA paren_list C_BRACKET TYPMOD + { + int dim; + if ( (dim = check_dim($2, $4)) && check_maxdim(dim, $2) ) + *((void **)result) = write_box(dim, $2, $4, $6); + else + YYABORT; } | paren_list COMMA paren_list { int dim; - dim = delim_count($1, ',') + 1; + if ( (dim = check_dim($1, $3)) && check_maxdim(dim, $1) ) + *((void **)result) = write_box(dim, $1, $3, ""); + else + YYABORT; + } + + | paren_list COMMA paren_list TYPMOD + { + int dim; - if ( (delim_count($3, ',') + 1) != dim ) { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), - errdetail("Different point dimensions in (%s) and (%s).", - $1, $3))); + if ( (dim = check_dim($1, $3)) && check_maxdim(dim, $1) ) + *((void **)result) = write_box(dim, $1, $3, $4); + else YYABORT; - } - if (dim > CUBE_MAX_DIM) { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), - errdetail("A cube cannot have more than %d dimensions.", - CUBE_MAX_DIM))); + } + + | paren_list + { + int dim; + + dim = delim_count($1, ',') + 1; + if (!check_maxdim(dim, $1)) YYABORT; - } - *result = write_box( dim, $1, $3 ); + *((void **)result) = write_point_as_box($1, dim, ""); } - | paren_list + | paren_list TYPMOD { int dim; dim = delim_count($1, ',') + 1; - if (dim > CUBE_MAX_DIM) { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), - errdetail("A cube cannot have more than %d dimensions.", - CUBE_MAX_DIM))); + if (!check_maxdim(dim, $1)) YYABORT; - } - *result = write_point_as_box($1, dim); + *((void **)result) = write_point_as_box($1, dim, $2); } | list @@ -122,15 +116,21 @@ box: O_BRACKET paren_list COMMA paren_list C_BRACKET int dim; dim = delim_count($1, ',') + 1; - if (dim > CUBE_MAX_DIM) { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("bad cube representation"), - errdetail("A cube cannot have more than %d dimensions.", - CUBE_MAX_DIM))); + if (!check_maxdim(dim, $1)) YYABORT; - } - *result = write_point_as_box($1, dim); + + *((void **)result) = write_point_as_box($1, dim, ""); + } + + | list TYPMOD + { + int dim; + + dim = delim_count($1, ',') + 1; + if (!check_maxdim(dim, $1)) + YYABORT; + + *((void **)result) = write_point_as_box($1, dim, $2); } ; @@ -169,65 +169,129 @@ delim_count(char *s, char delim) return (ndelim); } +static int +check_dim(char *str1, char *str2) +{ + int dim; + + dim = delim_count(str1, ',') + 1; + if ((delim_count(str2, ',') + 1) != dim) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("bad cube representation"), + errdetail("Different point dimensions in (%s) and (%s).", + str1, str2))); + return 0; + } else + return dim; +} + +static bool +check_maxdim(int dim, char *str1) +{ + if (dim > CUBE_MAX_DIM) { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("bad cube representation"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + return 0; + } else + return 1; +} + static NDBOX * -write_box(unsigned int dim, char *str1, char *str2) +write_box(int dim, char *str1, char *str2, char *typestr) { NDBOX *bp; char *s; - int i; - int size = offsetof(NDBOX, x[0]) + sizeof(double) * dim * 2; - - bp = palloc0(size); - SET_VARSIZE(bp, size); - bp->dim = dim; + int i, type; + double x; + bool point = true; + + if (strcmp(typestr, ":f4") == 0) + type = CUBE_FLOAT4; + else if (strcmp(typestr, ":i4") == 0) + type = CUBE_INT4; + else if (strcmp(typestr, ":i2") == 0) + type = CUBE_INT2; + else if (strcmp(typestr, ":i1") == 0) + type = CUBE_INT1; + else + type = CUBE_FLOAT8; + + bp = init_cube(dim, 0, type); s = str1; - bp->x[i=0] = strtod(s, NULL); + x = strtod(s, NULL); + check_coord(x, type); + set_coord(bp, i=0, x); while ((s = strchr(s, ',')) != NULL) { s++; i++; - bp->x[i] = strtod(s, NULL); + x = strtod(s, NULL); + check_coord(x, type); + set_coord(bp, i, x); } s = str2; - bp->x[i=dim] = strtod(s, NULL); + x = strtod(s, NULL); + check_coord(x, type); + set_coord(bp, i=dim, x); while ((s = strchr(s, ',')) != NULL) { s++; i++; - bp->x[i] = strtod(s, NULL); + x = strtod(s, NULL); + check_coord(x, type); + set_coord(bp, i, x); + if (LL_COORD(bp, i-dim) != UR_COORD(bp, i-dim)) + point = false; } + if (LL_COORD(bp, 0) != UR_COORD(bp, 0)) + point = false; + + if (point) + cube_to_point(bp); + return(bp); } static NDBOX * -write_point_as_box(char *str, int dim) +write_point_as_box(char *str, int dim, char *typestr) { - 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); + NDBOX *bp; + int i, type; + double x; + char *s = str; + + if (strcmp(typestr, ":f4") == 0) + type = CUBE_FLOAT4; + else if (strcmp(typestr, ":i4") == 0) + type = CUBE_INT4; + else if (strcmp(typestr, ":i2") == 0) + type = CUBE_INT2; + else if (strcmp(typestr, ":i1") == 0) + type = CUBE_INT1; + else + type = CUBE_FLOAT8; + + bp = init_cube(dim, 1, type); + + i = 0; + x = strtod(s, NULL); + check_coord(x, type); + set_coord(bp, 0, x); + while ((s = strchr(s, ',')) != NULL) + { + s++; i++; + x = strtod(s, NULL); + check_coord(x, type); + set_coord(bp, i, x); + } + + return(bp); } #include "cubescan.c" diff --git a/contrib/cube/cubescan.l b/contrib/cube/cubescan.l index e383b59..7033c08 100644 --- a/contrib/cube/cubescan.l +++ b/contrib/cube/cubescan.l @@ -46,6 +46,7 @@ n [0-9]+ integer [+-]?{n} real [+-]?({n}\.{n}?|\.{n}) float ({integer}|{real})([eE]{integer})? +typmod :(f8|f4|i4|i2|i1) %% @@ -55,6 +56,7 @@ float ({integer}|{real})([eE]{integer})? \( yylval = "("; return O_PAREN; \) yylval = ")"; return C_PAREN; \, yylval = ")"; return COMMA; +{typmod} yylval = yytext; return TYPMOD; [ \t\n\r\f]+ /* discard spaces */ . return yytext[0]; /* alert parser of the garbage */