Cube extension types support

Started by Stas Kelvichover 12 years ago2 messages
#1Stas Kelvich
stas.kelvich@gmail.com
1 attachment(s)

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 */
 
#2Peter Eisentraut
peter_e@gmx.net
In reply to: Stas Kelvich (#1)
Re: Cube extension types support

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