Cube extension types support
Hello, hackers.
In this patch I've implemented support for different storage types for cubes. Now it supports float8, float4, int4, int2, int1. Type stored in the header of each cube, one for all coordinates. So for cubes with int1 coordinates it can save up to 8x disk space. Typed cubes can be created in two ways:
1) Via cube_suffix() functions, where suffix can be "f4", "i4", "i2", "i1", and arguments are two or one numbers or arrays, i.e.
# select cube_i1(1,2) as c;
c
------------
(1),(2):i1
# select cube_f4(array[1,2,3], array[5,6,7]) as c;
c
------------------------
(1, 2, 3),(5, 6, 7):f4
2) Via modificator in the end of string that will be casted to cube, i.e.
# select '(1,2,3):i2'::cube as c;
c
--------------
(1, 2, 3):i2
When no modificator given float8 will be used by default. Old-style cubes without type in header also treated as float8 for backward compatibility.
This patch changes a lot of things in code, so it interfere with others patches to the cube extension. I will update this patch, if other patches will be accepted to commit.
Attachments:
types_cumulative.diffapplication/octet-stream; name=types_cumulative.diffDownload
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 */
On 9/24/13 11:44 AM, Stas Kelvich wrote:
In this patch I've implemented support for different storage types for cubes.
Doesn't build:
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -g -fpic -I. -I. -I../../src/include -D_GNU_SOURCE -I/usr/include/libxml2 -c -o cubeparse.o cubeparse.c -MMD -MP -MF .deps/cubeparse.Po
cubeparse.y:35:13: warning: �check_coord� used but never defined [enabled by default]
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -g -fpic -shared -o cube.so cube.o cubeparse.o -L../../src/port -L../../src/common -L/usr/lib -Wl,--as-needed -lm
/usr/bin/ld: cubeparse.o: relocation R_X86_64_PC32 against symbol `check_coord' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
make[2]: *** [cube.so] Error 1
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers