Cube extension point support // GSoC'13

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

Hello.

here is a patch adding to cube extension support for compressed representation of point cubes. If cube is a point, i.e. has coincident lower left and upper right corners, than only one corner is stored. First bit of the cube header indicates whether the cube is point or not. Few moments:

* Patch preserves binary compatibility with old indices
* All functions that create cubes from user input, check whether it is a point or not
* All internal functions that can return cubes takes care of all cases where a cube might become a point
* Added tests for checking correct point behavior

Also this patch includes adapted Alexander Korotkov's patch with kNN-based ordering operator, which he wrote for postgresql-9.0beta1 with knngist patch. More info there /messages/by-id/AANLkTimhFaq6hCibRnk0tlcQMIyhYWHwAQ2ZD87wbH86@mail.gmail.com

Stas Kelvich

Attachments:

points.patchapplication/octet-stream; name=points.patchDownload
diff --git a/contrib/cube/cube--1.0.sql b/contrib/cube/cube--1.0.sql
new file mode 100644
index 0307811..053c3dc
*** a/contrib/cube/cube--1.0.sql
--- b/contrib/cube/cube--1.0.sql
*************** CREATE FUNCTION cube(cube, float8, float
*** 173,178 ****
--- 173,182 ----
  AS 'MODULE_PATHNAME', 'cube_c_f8_f8'
  LANGUAGE C IMMUTABLE STRICT;
  
+ CREATE FUNCTION cube_sort_by(cube, int4) RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+ 
  -- Test if cube is also a point
  
  CREATE FUNCTION cube_is_point(cube)
*************** CREATE OPERATOR <@ (
*** 246,251 ****
--- 250,260 ----
  	RESTRICT = contsel, JOIN = contjoinsel
  );
  
+ CREATE OPERATOR <*> (
+ 	LEFTARG = cube, RIGHTARG = int4, PROCEDURE = cube_sort_by,
+ 	COMMUTATOR = '<*>'
+ );
+ 
  -- these are obsolete/deprecated:
  CREATE OPERATOR @ (
  	LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contains,
*************** RETURNS internal
*** 296,301 ****
--- 305,315 ----
  AS 'MODULE_PATHNAME'
  LANGUAGE C IMMUTABLE STRICT;
  
+ CREATE FUNCTION g_cube_distance(internal, cube, smallint, oid)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT;
+ 
  
  -- Create the operator classes for indexing
  
*************** CREATE OPERATOR CLASS gist_cube_ops
*** 316,325 ****
  	OPERATOR	8	<@ ,
  	OPERATOR	13	@ ,
  	OPERATOR	14	~ ,
  	FUNCTION	1	g_cube_consistent (internal, cube, int, oid, internal),
  	FUNCTION	2	g_cube_union (internal, internal),
  	FUNCTION	3	g_cube_compress (internal),
  	FUNCTION	4	g_cube_decompress (internal),
  	FUNCTION	5	g_cube_penalty (internal, internal, internal),
  	FUNCTION	6	g_cube_picksplit (internal, internal),
! 	FUNCTION	7	g_cube_same (cube, cube, internal);
--- 330,341 ----
  	OPERATOR	8	<@ ,
  	OPERATOR	13	@ ,
  	OPERATOR	14	~ ,
+ 	OPERATOR	15	<*> (cube, int) FOR ORDER BY float_ops,
  	FUNCTION	1	g_cube_consistent (internal, cube, int, oid, internal),
  	FUNCTION	2	g_cube_union (internal, internal),
  	FUNCTION	3	g_cube_compress (internal),
  	FUNCTION	4	g_cube_decompress (internal),
  	FUNCTION	5	g_cube_penalty (internal, internal, internal),
  	FUNCTION	6	g_cube_picksplit (internal, internal),
! 	FUNCTION	7	g_cube_same (cube, cube, internal),
! 	FUNCTION	8	g_cube_distance (internal, cube, smallint, oid);
diff --git a/contrib/cube/cube--unpackaged--1.0.sql b/contrib/cube/cube--unpackaged--1.0.sql
new file mode 100644
index 6859682..e14986b
*** a/contrib/cube/cube--unpackaged--1.0.sql
--- b/contrib/cube/cube--unpackaged--1.0.sql
*************** ALTER EXTENSION cube ADD operator <@(cub
*** 43,48 ****
--- 43,49 ----
  ALTER EXTENSION cube ADD operator @>(cube,cube);
  ALTER EXTENSION cube ADD operator ~(cube,cube);
  ALTER EXTENSION cube ADD operator @(cube,cube);
+ ALTER EXTENSION cube ADD operator <*>(cube,integer);
  ALTER EXTENSION cube ADD function g_cube_consistent(internal,cube,integer,oid,internal);
  ALTER EXTENSION cube ADD function g_cube_compress(internal);
  ALTER EXTENSION cube ADD function g_cube_decompress(internal);
*************** ALTER EXTENSION cube ADD function g_cube
*** 50,55 ****
--- 51,57 ----
  ALTER EXTENSION cube ADD function g_cube_picksplit(internal,internal);
  ALTER EXTENSION cube ADD function g_cube_union(internal,internal);
  ALTER EXTENSION cube ADD function g_cube_same(cube,cube,internal);
+ ALTER EXTENSION cube ADD function g_cube_distance(internal, cube, smallint, oid);
  ALTER EXTENSION cube ADD operator family cube_ops using btree;
  ALTER EXTENSION cube ADD operator class cube_ops using btree;
  ALTER EXTENSION cube ADD operator family gist_cube_ops using gist;
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
new file mode 100644
index b591133..a5a1213
*** a/contrib/cube/cube.c
--- b/contrib/cube/cube.c
*************** PG_FUNCTION_INFO_V1(cube_dim);
*** 47,52 ****
--- 47,53 ----
  PG_FUNCTION_INFO_V1(cube_ll_coord);
  PG_FUNCTION_INFO_V1(cube_ur_coord);
  PG_FUNCTION_INFO_V1(cube_subset);
+ PG_FUNCTION_INFO_V1(cube_sort_by);
  
  Datum		cube_in(PG_FUNCTION_ARGS);
  Datum		cube(PG_FUNCTION_ARGS);
*************** Datum		cube_dim(PG_FUNCTION_ARGS);
*** 61,71 ****
  Datum		cube_ll_coord(PG_FUNCTION_ARGS);
  Datum		cube_ur_coord(PG_FUNCTION_ARGS);
  Datum		cube_subset(PG_FUNCTION_ARGS);
  
  /*
  ** GiST support methods
  */
- 
  PG_FUNCTION_INFO_V1(g_cube_consistent);
  PG_FUNCTION_INFO_V1(g_cube_compress);
  PG_FUNCTION_INFO_V1(g_cube_decompress);
--- 62,72 ----
  Datum		cube_ll_coord(PG_FUNCTION_ARGS);
  Datum		cube_ur_coord(PG_FUNCTION_ARGS);
  Datum		cube_subset(PG_FUNCTION_ARGS);
+ Datum		cube_sort_by(PG_FUNCTION_ARGS);
  
  /*
  ** GiST support methods
  */
  PG_FUNCTION_INFO_V1(g_cube_consistent);
  PG_FUNCTION_INFO_V1(g_cube_compress);
  PG_FUNCTION_INFO_V1(g_cube_decompress);
*************** PG_FUNCTION_INFO_V1(g_cube_penalty);
*** 73,78 ****
--- 74,80 ----
  PG_FUNCTION_INFO_V1(g_cube_picksplit);
  PG_FUNCTION_INFO_V1(g_cube_union);
  PG_FUNCTION_INFO_V1(g_cube_same);
+ PG_FUNCTION_INFO_V1(g_cube_distance);
  
  Datum		g_cube_consistent(PG_FUNCTION_ARGS);
  Datum		g_cube_compress(PG_FUNCTION_ARGS);
*************** Datum		g_cube_penalty(PG_FUNCTION_ARGS);
*** 81,86 ****
--- 83,89 ----
  Datum		g_cube_picksplit(PG_FUNCTION_ARGS);
  Datum		g_cube_union(PG_FUNCTION_ARGS);
  Datum		g_cube_same(PG_FUNCTION_ARGS);
+ Datum		g_cube_distance(PG_FUNCTION_ARGS);
  
  /*
  ** B-tree support functions
*************** Datum		cube_cmp(PG_FUNCTION_ARGS);
*** 104,110 ****
  /*
  ** R-tree support functions
  */
- 
  PG_FUNCTION_INFO_V1(cube_contains);
  PG_FUNCTION_INFO_V1(cube_contained);
  PG_FUNCTION_INFO_V1(cube_overlap);
--- 107,112 ----
*************** Datum		cube_enlarge(PG_FUNCTION_ARGS);
*** 136,146 ****
  int32		cube_cmp_v0(NDBOX *a, NDBOX *b);
  bool		cube_contains_v0(NDBOX *a, NDBOX *b);
  bool		cube_overlap_v0(NDBOX *a, NDBOX *b);
! NDBOX	   *cube_union_v0(NDBOX *a, NDBOX *b);
  void		rt_cube_size(NDBOX *a, double *sz);
! NDBOX	   *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep);
  bool		g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy);
  bool		g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy);
  
  /*
  ** Auxiliary funxtions
--- 138,149 ----
  int32		cube_cmp_v0(NDBOX *a, NDBOX *b);
  bool		cube_contains_v0(NDBOX *a, NDBOX *b);
  bool		cube_overlap_v0(NDBOX *a, NDBOX *b);
! NDBOX*		cube_union_v0(NDBOX *a, NDBOX *b);
  void		rt_cube_size(NDBOX *a, double *sz);
! NDBOX*		g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep);
  bool		g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy);
  bool		g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy);
+ float8		cube_sort_by_v0(NDBOX *cube, int d);
  
  /*
  ** Auxiliary funxtions
*************** cube_a_f8_f8(PG_FUNCTION_ARGS)
*** 183,188 ****
--- 186,192 ----
  	int			i;
  	int			dim;
  	int			size;
+ 	bool		point = true;
  	double	   *dur,
  			   *dll;
  
*************** cube_a_f8_f8(PG_FUNCTION_ARGS)
*** 200,219 ****
  	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;
  
  	for (i = 0; i < dim; i++)
  	{
  		result->x[i] = dur[i];
  		result->x[i + dim] = dll[i];
  	}
  
  	PG_RETURN_NDBOX(result);
  }
  
  /*
  ** Allows the construction of a zero-volume cube from a float[]
  */
--- 204,234 ----
  	dur = ARRPTR(ur);
  	dll = ARRPTR(ll);
  
! 	size = CUBE_SIZE(dim);
  	result = (NDBOX *) palloc0(size);
  	SET_VARSIZE(result, size);
! 	SET_DIM(result, dim);
  
  	for (i = 0; i < dim; i++)
  	{
  		result->x[i] = dur[i];
  		result->x[i + dim] = dll[i];
+ 		if (dur[i] != dll[i])
+ 			point = false;
+ 	}
+ 
+ 	if (point)
+ 	{
+ 		size = POINT_SIZE(dim);
+ 		result = repalloc(result, size);
+ 		SET_VARSIZE(result, size);
+ 		SET_POINT_BIT(result);
  	}
  
  	PG_RETURN_NDBOX(result);
  }
  
+ 
  /*
  ** Allows the construction of a zero-volume cube from a float[]
  */
*************** cube_a_f8(PG_FUNCTION_ARGS)
*** 233,255 ****
  				 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;
  
  	for (i = 0; i < dim; i++)
- 	{
  		result->x[i] = dur[i];
- 		result->x[i + dim] = dur[i];
- 	}
  
  	PG_RETURN_NDBOX(result);
  }
  
  Datum
  cube_subset(PG_FUNCTION_ARGS)
  {
--- 248,268 ----
  				 errmsg("cannot work with arrays containing NULLs")));
  
  	dim = ARRNELEMS(ur);
  	dur = ARRPTR(ur);
  
! 	size = POINT_SIZE(dim);
  	result = (NDBOX *) palloc0(size);
  	SET_VARSIZE(result, size);
! 	SET_DIM(result, dim);
! 	SET_POINT_BIT(result);
  
  	for (i = 0; i < dim; i++)
  		result->x[i] = dur[i];
  
  	PG_RETURN_NDBOX(result);
  }
  
+ 
  Datum
  cube_subset(PG_FUNCTION_ARGS)
  {
*************** cube_subset(PG_FUNCTION_ARGS)
*** 269,282 ****
  	dx = (int32 *) ARR_DATA_PTR(idx);
  
  	dim = ARRNELEMS(idx);
! 	size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
  	result = (NDBOX *) palloc0(size);
  	SET_VARSIZE(result, size);
! 	result->dim = dim;
  
  	for (i = 0; i < dim; i++)
  	{
! 		if ((dx[i] <= 0) || (dx[i] > c->dim))
  		{
  			pfree(result);
  			ereport(ERROR,
--- 282,298 ----
  	dx = (int32 *) ARR_DATA_PTR(idx);
  
  	dim = ARRNELEMS(idx);
! 	size = IS_POINT(c) ? POINT_SIZE(dim) : CUBE_SIZE(dim);
  	result = (NDBOX *) palloc0(size);
  	SET_VARSIZE(result, size);
! 	SET_DIM(result, dim);
! 
! 	if (IS_POINT(c))
! 		SET_POINT_BIT(result);
  
  	for (i = 0; i < dim; i++)
  	{
! 		if ((dx[i] <= 0) || (dx[i] > DIM(c)))
  		{
  			pfree(result);
  			ereport(ERROR,
*************** cube_subset(PG_FUNCTION_ARGS)
*** 284,303 ****
  					 errmsg("Index out of bounds")));
  		}
  		result->x[i] = c->x[dx[i] - 1];
! 		result->x[i + dim] = c->x[dx[i] + c->dim - 1];
  	}
  
  	PG_FREE_IF_COPY(c, 0);
  	PG_RETURN_NDBOX(result);
  }
  
  Datum
  cube_out(PG_FUNCTION_ARGS)
  {
  	NDBOX	   *cube = PG_GETARG_NDBOX(0);
  	StringInfoData buf;
! 	int			dim = cube->dim;
! 	bool		equal = true;
  	int			i;
  	int			ndig;
  
--- 300,329 ----
  					 errmsg("Index out of bounds")));
  		}
  		result->x[i] = c->x[dx[i] - 1];
! 		if (!IS_POINT(c))
! 			result->x[i + dim] = c->x[dx[i] + DIM(c) - 1];
  	}
  
  	PG_FREE_IF_COPY(c, 0);
  	PG_RETURN_NDBOX(result);
  }
  
+ 
+ Datum
+ cube_sort_by(PG_FUNCTION_ARGS)
+ {
+ 	NDBOX *key = PG_GETARG_NDBOX(0);
+ 	int d = PG_GETARG_INT32(1);
+ 	PG_RETURN_FLOAT8(cube_sort_by_v0(key, d));
+ }
+ 
+ 
  Datum
  cube_out(PG_FUNCTION_ARGS)
  {
  	NDBOX	   *cube = PG_GETARG_NDBOX(0);
  	StringInfoData buf;
! 	int			dim = DIM(cube);
  	int			i;
  	int			ndig;
  
*************** cube_out(PG_FUNCTION_ARGS)
*** 319,338 ****
  	{
  		if (i > 0)
  			appendStringInfo(&buf, ", ");
! 		appendStringInfo(&buf, "%.*g", ndig, cube->x[i]);
! 		if (cube->x[i] != cube->x[i + dim])
! 			equal = false;
  	}
  	appendStringInfoChar(&buf, ')');
  
! 	if (!equal)
  	{
  		appendStringInfo(&buf, ",(");
  		for (i = 0; i < dim; i++)
  		{
  			if (i > 0)
  				appendStringInfo(&buf, ", ");
! 			appendStringInfo(&buf, "%.*g", ndig, cube->x[i + dim]);
  		}
  		appendStringInfoChar(&buf, ')');
  	}
--- 345,362 ----
  	{
  		if (i > 0)
  			appendStringInfo(&buf, ", ");
! 		appendStringInfo(&buf, "%.*g", ndig, LL_COORD(cube,i));
  	}
  	appendStringInfoChar(&buf, ')');
  
! 	if (!IS_POINT(cube))
  	{
  		appendStringInfo(&buf, ",(");
  		for (i = 0; i < dim; i++)
  		{
  			if (i > 0)
  				appendStringInfo(&buf, ", ");
! 			appendStringInfo(&buf, "%.*g", ndig, UR_COORD(cube, i));
  		}
  		appendStringInfoChar(&buf, ')');
  	}
*************** g_cube_union(PG_FUNCTION_ARGS)
*** 395,403 ****
  	NDBOX	   *tmp;
  	int			i;
  
- 	/*
- 	 * fprintf(stderr, "union\n");
- 	 */
  	tmp = DatumGetNDBOX(entryvec->vector[0].key);
  
  	/*
--- 419,424 ----
*************** g_cube_union(PG_FUNCTION_ARGS)
*** 416,447 ****
  	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));
  }
  
  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);
  }
  
--- 437,458 ----
  	PG_RETURN_POINTER(out);
  }
  
+ 
  /*
  ** GiST Compress and Decompress methods for boxes
  ** do not do anything.
  */
  Datum
  g_cube_compress(PG_FUNCTION_ARGS)
  {
! 	GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
! 	PG_RETURN_POINTER(entry);
  }
  
  Datum
  g_cube_decompress(PG_FUNCTION_ARGS)
  {
! 	GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
  	PG_RETURN_POINTER(entry);
  }
  
*************** g_cube_penalty(PG_FUNCTION_ARGS)
*** 466,479 ****
  	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
--- 477,486 ----
*************** g_cube_picksplit(PG_FUNCTION_ARGS)
*** 508,517 ****
  	OffsetNumber *left,
  			   *right;
  	OffsetNumber maxoff;
! 
! 	/*
! 	 * fprintf(stderr, "picksplit\n");
! 	 */
  	maxoff = entryvec->n - 2;
  	nbytes = (maxoff + 2) * sizeof(OffsetNumber);
  	v->spl_left = (OffsetNumber *) palloc(nbytes);
--- 515,521 ----
  	OffsetNumber *left,
  			   *right;
  	OffsetNumber maxoff;
! 	 
  	maxoff = entryvec->n - 2;
  	nbytes = (maxoff + 2) * sizeof(OffsetNumber);
  	v->spl_left = (OffsetNumber *) palloc(nbytes);
*************** g_cube_picksplit(PG_FUNCTION_ARGS)
*** 627,632 ****
--- 631,637 ----
  	PG_RETURN_POINTER(v);
  }
  
+ 
  /*
  ** Equality method
  */
*************** g_cube_same(PG_FUNCTION_ARGS)
*** 642,653 ****
  	else
  		*result = FALSE;
  
- 	/*
- 	 * fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" ));
- 	 */
  	PG_RETURN_NDBOX(result);
  }
  
  /*
  ** SUPPORT ROUTINES
  */
--- 647,670 ----
  	else
  		*result = FALSE;
  
  	PG_RETURN_NDBOX(result);
  }
  
+ 
+ /*
+ ** kNN sorting support
+ */
+ Datum
+ g_cube_distance(PG_FUNCTION_ARGS)
+ {
+ 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ 	int			d = PG_GETARG_INT32(1);
+ 	NDBOX		*key = DatumGetNDBOX(entry->key);
+ 
+ 	PG_RETURN_FLOAT8(cube_sort_by_v0(key, d));
+ }
+ 
+ 
  /*
  ** SUPPORT ROUTINES
  */
*************** g_cube_leaf_consistent(NDBOX *key,
*** 658,666 ****
  {
  	bool		retval;
  
- 	/*
- 	 * fprintf(stderr, "leaf_consistent, %d\n", strategy);
- 	 */
  	switch (strategy)
  	{
  		case RTOverlapStrategyNumber:
--- 675,680 ----
*************** g_cube_leaf_consistent(NDBOX *key,
*** 683,688 ****
--- 697,703 ----
  	return (retval);
  }
  
+ 
  bool
  g_cube_internal_consistent(NDBOX *key,
  						   NDBOX *query,
*************** g_cube_internal_consistent(NDBOX *key,
*** 690,698 ****
  {
  	bool		retval;
  
- 	/*
- 	 * fprintf(stderr, "internal_consistent, %d\n", strategy);
- 	 */
  	switch (strategy)
  	{
  		case RTOverlapStrategyNumber:
--- 705,710 ----
*************** g_cube_internal_consistent(NDBOX *key,
*** 713,718 ****
--- 725,747 ----
  	return (retval);
  }
  
+ 
+ float8
+ cube_sort_by_v0(NDBOX *cube, int d)
+ {
+ 	bool is_min;
+ 
+ 	is_min = ((d % 2) == 0);
+ 	d = d/2;
+ 	if (DIM(cube) <= d)
+ 		return 0.0;
+ 	if (is_min)
+ 		return LL_COORD(cube,d);
+ 	else
+ 		return 1.0 / UR_COORD(cube,d);
+ }
+ 
+ 
  NDBOX *
  g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
  {
*************** NDBOX *
*** 730,786 ****
  cube_union_v0(NDBOX *a, NDBOX *b)
  {
  	int			i;
  	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;
! 	}
  
  	/* swap the box pointers if needed */
! 	if (a->dim < b->dim)
  	{
  		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->x[i] = Min(b->x[i], b->x[i + b->dim]);
! 		result->x[i + a->dim] = Max(b->x[i], b->x[i + b->dim]);
  	}
! 	for (i = b->dim; i < a->dim; i++)
  	{
! 		result->x[i] = 0;
! 		result->x[i + a->dim] = 0;
  	}
  
! 	/* compute the 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]);
  	}
  
  	return (result);
  }
  
  Datum
  cube_union(PG_FUNCTION_ARGS)
  {
--- 759,820 ----
  cube_union_v0(NDBOX *a, NDBOX *b)
  {
  	int			i;
+ 	bool		point_result = true;
  	NDBOX	   *result;
  
! 	/* let's try to guess result for same pointers */
! 	if (a == b)
! 		return a;
  
  	/* swap the box pointers if needed */
! 	if (DIM(a) < DIM(b))
  	{
  		NDBOX	   *tmp = b;
  		b = a;
  		a = tmp;
  	}
  
! 	result = palloc0(CUBE_SIZE(DIM(a)));
! 	SET_VARSIZE(result, CUBE_SIZE(DIM(a)));
! 	SET_DIM(result, DIM(a));
! 
! 	 /* compute the union */
! 	for (i = 0; i < DIM(b); i++)
  	{
! 		result->x[i] = Min(
! 			Min(LL_COORD(a,i), UR_COORD(a,i)),
! 			Min(LL_COORD(b,i), UR_COORD(b,i))
! 		);
! 		result->x[i + DIM(a)] = Max(
! 			Max(LL_COORD(a,i), UR_COORD(a,i)), 
! 			Max(LL_COORD(b,i), UR_COORD(b,i))
! 		);
! 		if (result->x[i] != result->x[i + DIM(a)])
! 			point_result = false;
  	}
! 	for (i = DIM(b); i < DIM(a); i++)
  	{
! 		result->x[i] = Min(0,
! 			Min(LL_COORD(a,i), UR_COORD(a,i))
! 		);
! 		result->x[i + DIM(a)] = Max(0,
! 			Max(LL_COORD(a,i), UR_COORD(a,i))
! 		);
! 		if (result->x[i] != result->x[i + DIM(a)])
! 			point_result = false;
  	}
  
! 	if (point_result)
  	{
! 		result = repalloc(result, POINT_SIZE(DIM(a)));
! 		SET_VARSIZE(result, POINT_SIZE(DIM(a)));
! 		SET_POINT_BIT(result);
  	}
  
  	return (result);
  }
  
+ 
  Datum
  cube_union(PG_FUNCTION_ARGS)
  {
*************** cube_union(PG_FUNCTION_ARGS)
*** 795,800 ****
--- 829,835 ----
  	PG_RETURN_NDBOX(res);
  }
  
+ 
  /* cube_inter */
  Datum
  cube_inter(PG_FUNCTION_ARGS)
*************** cube_inter(PG_FUNCTION_ARGS)
*** 802,825 ****
  	NDBOX	   *a = PG_GETARG_NDBOX(0);
  	NDBOX	   *b = PG_GETARG_NDBOX(1);
  	NDBOX	   *result;
! 	bool		swapped = false;
  	int			i;
  
- 	if (a->dim >= b->dim)
- 	{
- 		result = palloc0(VARSIZE(a));
- 		SET_VARSIZE(result, VARSIZE(a));
- 		result->dim = a->dim;
- 	}
- 	else
- 	{
- 		result = palloc0(VARSIZE(b));
- 		SET_VARSIZE(result, VARSIZE(b));
- 		result->dim = b->dim;
- 	}
- 
  	/* swap the box pointers if needed */
! 	if (a->dim < b->dim)
  	{
  		NDBOX	   *tmp = b;
  
--- 837,848 ----
  	NDBOX	   *a = PG_GETARG_NDBOX(0);
  	NDBOX	   *b = PG_GETARG_NDBOX(1);
  	NDBOX	   *result;
! 	bool		swapped = false,
! 				point_result = true;
  	int			i;
  
  	/* swap the box pointers if needed */
! 	if (DIM(a) < DIM(b))
  	{
  		NDBOX	   *tmp = b;
  
*************** cube_inter(PG_FUNCTION_ARGS)
*** 828,855 ****
  		swapped = true;
  	}
  
! 	/*
! 	 * use the potentially	smaller of the two boxes (b) to fill in the
! 	 * result, padding absent dimensions with zeroes
! 	 */
! 	for (i = 0; i < b->dim; i++)
  	{
! 		result->x[i] = Min(b->x[i], b->x[i + b->dim]);
! 		result->x[i + a->dim] = Max(b->x[i], b->x[i + b->dim]);
  	}
! 	for (i = b->dim; i < a->dim; i++)
  	{
! 		result->x[i] = 0;
! 		result->x[i + a->dim] = 0;
  	}
  
! 	/* compute the intersection */
! 	for (i = 0; i < a->dim; i++)
  	{
! 		result->x[i] =
! 			Max(Min(a->x[i], a->x[i + a->dim]), result->x[i]);
! 		result->x[i + a->dim] = Min(Max(a->x[i],
! 								   a->x[i + a->dim]), result->x[i + a->dim]);
  	}
  
  	if (swapped)
--- 851,890 ----
  		swapped = true;
  	}
  
! 	result = (NDBOX *) palloc0(CUBE_SIZE(DIM(a)));
! 	SET_VARSIZE(result, CUBE_SIZE(DIM(a)));
! 	SET_DIM(result, DIM(a));
! 
! 	for (i = 0; i < DIM(b); i++)
  	{
! 		result->x[i] = Max(
! 			Min(LL_COORD(a,i), UR_COORD(a,i)),
! 			Min(LL_COORD(b,i), UR_COORD(b,i))
! 		);
! 		result->x[i + DIM(a)] = Min(
! 			Max(LL_COORD(a,i), UR_COORD(a,i)),
! 			Max(LL_COORD(b,i), UR_COORD(b,i))
! 		);
! 		if (result->x[i] != result->x[i + DIM(a)])
! 			point_result = false;
  	}
! 	for (i = DIM(b); i < DIM(a); i++)
  	{
! 		result->x[i] = Max(0,
! 			Min(LL_COORD(a,i), UR_COORD(a,i))
! 		);
! 		result->x[i + DIM(a)] = Min(0,
! 			Max(LL_COORD(a,i), UR_COORD(a,i))
! 		);
! 		if (result->x[i] != result->x[i + DIM(a)])
! 			point_result = false;
  	}
  
! 	if (point_result)
  	{
! 		result = repalloc(result, POINT_SIZE(DIM(a)));
! 		SET_VARSIZE(result, POINT_SIZE(DIM(a)));
! 		SET_POINT_BIT(result);
  	}
  
  	if (swapped)
*************** cube_inter(PG_FUNCTION_ARGS)
*** 869,908 ****
  	PG_RETURN_NDBOX(result);
  }
  
  /* cube_size */
  Datum
  cube_size(PG_FUNCTION_ARGS)
  {
  	NDBOX	   *a = PG_GETARG_NDBOX(0);
  	double		result;
! 	int			i,
! 				j;
  
  	result = 1.0;
! 	for (i = 0, j = a->dim; i < a->dim; i++, j++)
! 		result = result * Abs((a->x[j] - a->x[i]));
  
  	PG_FREE_IF_COPY(a, 0);
  	PG_RETURN_FLOAT8(result);
  }
  
  void
  rt_cube_size(NDBOX *a, double *size)
  {
! 	int			i,
! 				j;
  
  	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]));
  	}
  	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
--- 904,944 ----
  	PG_RETURN_NDBOX(result);
  }
  
+ 
  /* cube_size */
  Datum
  cube_size(PG_FUNCTION_ARGS)
  {
  	NDBOX	   *a = PG_GETARG_NDBOX(0);
  	double		result;
! 	int			i;
  
  	result = 1.0;
! 	for (i = 0; i < DIM(a); i++)
! 		result = result * Abs((LL_COORD(a,i) - UR_COORD(a,i)));
  
  	PG_FREE_IF_COPY(a, 0);
  	PG_RETURN_FLOAT8(result);
  }
  
+ 
  void
  rt_cube_size(NDBOX *a, double *size)
  {
! 	int i;
  
  	if (a == (NDBOX *) NULL)
  		*size = 0.0;
  	else
  	{
  		*size = 1.0;
! 		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
*************** cube_cmp_v0(NDBOX *a, NDBOX *b)
*** 911,953 ****
  	int			i;
  	int			dim;
  
! 	dim = Min(a->dim, b->dim);
  
  	/* 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]))
  			return 1;
! 		if (Min(a->x[i], a->x[a->dim + i]) <
! 			Min(b->x[i], b->x[b->dim + 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]))
  			return 1;
! 		if (Max(a->x[i], a->x[a->dim + i]) <
! 			Max(b->x[i], b->x[b->dim + i]))
  			return -1;
  	}
  
  	/* compare extra dimensions to zero */
! 	if (a->dim > b->dim)
  	{
! 		for (i = dim; i < a->dim; i++)
  		{
! 			if (Min(a->x[i], a->x[a->dim + i]) > 0)
  				return 1;
! 			if (Min(a->x[i], a->x[a->dim + i]) < 0)
  				return -1;
  		}
! 		for (i = dim; i < a->dim; i++)
  		{
! 			if (Max(a->x[i], a->x[a->dim + i]) > 0)
  				return 1;
! 			if (Max(a->x[i], a->x[a->dim + i]) < 0)
  				return -1;
  		}
  
--- 947,989 ----
  	int			i;
  	int			dim;
  
! 	dim = Min(DIM(a), DIM(b));
  
  	/* compare the common dimensions */
  	for (i = 0; i < dim; i++)
  	{
! 		if (Min(LL_COORD(a, i), UR_COORD(a, i)) >
! 			Min(LL_COORD(b, i), UR_COORD(b, i)))
  			return 1;
! 		if (Min(LL_COORD(a, i), UR_COORD(a, i)) <
! 			Min(LL_COORD(b, i), UR_COORD(b, i)))
  			return -1;
  	}
  	for (i = 0; i < dim; i++)
  	{
! 		if (Max(LL_COORD(a, i), UR_COORD(a, i)) >
! 			Max(LL_COORD(b, i), UR_COORD(b, i)))
  			return 1;
! 		if (Max(LL_COORD(a, i), UR_COORD(a, i)) <
! 			Max(LL_COORD(b, i), UR_COORD(b, i)))
  			return -1;
  	}
  
  	/* compare extra dimensions to zero */
! 	if (DIM(a) > DIM(b))
  	{
! 		for (i = dim; i < DIM(a); i++)
  		{
! 			if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0)
  				return 1;
! 			if (Min(LL_COORD(a, i), UR_COORD(a, i)) < 0)
  				return -1;
  		}
! 		for (i = dim; i < DIM(a); i++)
  		{
! 			if (Max(LL_COORD(a, i), UR_COORD(a, i)) > 0)
  				return 1;
! 			if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0)
  				return -1;
  		}
  
*************** cube_cmp_v0(NDBOX *a, NDBOX *b)
*** 957,976 ****
  		 */
  		return 1;
  	}
! 	if (a->dim < b->dim)
  	{
! 		for (i = dim; i < b->dim; i++)
  		{
! 			if (Min(b->x[i], b->x[b->dim + i]) > 0)
  				return -1;
! 			if (Min(b->x[i], b->x[b->dim + i]) < 0)
  				return 1;
  		}
! 		for (i = dim; i < b->dim; i++)
  		{
! 			if (Max(b->x[i], b->x[b->dim + i]) > 0)
  				return -1;
! 			if (Max(b->x[i], b->x[b->dim + i]) < 0)
  				return 1;
  		}
  
--- 993,1012 ----
  		 */
  		return 1;
  	}
! 	if (DIM(a) < DIM(b))
  	{
! 		for (i = dim; i < DIM(b); i++)
  		{
! 			if (Min(LL_COORD(b, i), UR_COORD(b, i)) > 0)
  				return -1;
! 			if (Min(LL_COORD(b, i), UR_COORD(b, i)) < 0)
  				return 1;
  		}
! 		for (i = dim; i < DIM(b); i++)
  		{
! 			if (Max(LL_COORD(b, i), UR_COORD(b, i)) > 0)
  				return -1;
! 			if (Max(LL_COORD(b, i), UR_COORD(b, i)) < 0)
  				return 1;
  		}
  
*************** cube_cmp_v0(NDBOX *a, NDBOX *b)
*** 985,990 ****
--- 1021,1027 ----
  	return 0;
  }
  
+ 
  Datum
  cube_cmp(PG_FUNCTION_ARGS)
  {
*************** cube_contains_v0(NDBOX *a, NDBOX *b)
*** 1100,1135 ****
  	if ((a == NULL) || (b == NULL))
  		return (FALSE);
  
! 	if (a->dim < b->dim)
  	{
  		/*
  		 * 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++)
  		{
! 			if (b->x[i] != 0)
  				return (FALSE);
! 			if (b->x[i + b->dim] != 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++)
  	{
! 		if (Min(a->x[i], a->x[a->dim + i]) >
! 			Min(b->x[i], b->x[b->dim + i]))
  			return (FALSE);
! 		if (Max(a->x[i], a->x[a->dim + i]) <
! 			Max(b->x[i], b->x[b->dim + i]))
  			return (FALSE);
  	}
  
  	return (TRUE);
  }
  
  Datum
  cube_contains(PG_FUNCTION_ARGS)
  {
--- 1137,1173 ----
  	if ((a == NULL) || (b == NULL))
  		return (FALSE);
  
! 	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 = DIM(a); i < DIM(b); i++)
  		{
! 			if (LL_COORD(b,i) != 0)
  				return (FALSE);
! 			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(DIM(a), DIM(b)); i++)
  	{
! 		if (Min(LL_COORD(a,i), UR_COORD(a, i)) >
! 			Min(LL_COORD(b,i), UR_COORD(b, i)))
  			return (FALSE);
! 		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)
  {
*************** cube_contains(PG_FUNCTION_ARGS)
*** 1144,1149 ****
--- 1182,1188 ----
  	PG_RETURN_BOOL(res);
  }
  
+ 
  /* Contained */
  /* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */
  Datum
*************** cube_contained(PG_FUNCTION_ARGS)
*** 1160,1165 ****
--- 1199,1205 ----
  	PG_RETURN_BOOL(res);
  }
  
+ 
  /* Overlap */
  /* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */
  bool
*************** cube_overlap_v0(NDBOX *a, NDBOX *b)
*** 1175,1181 ****
  		return (FALSE);
  
  	/* swap the box pointers if needed */
! 	if (a->dim < b->dim)
  	{
  		NDBOX	   *tmp = b;
  
--- 1215,1221 ----
  		return (FALSE);
  
  	/* swap the box pointers if needed */
! 	if (DIM(a) < DIM(b))
  	{
  		NDBOX	   *tmp = b;
  
*************** cube_overlap_v0(NDBOX *a, NDBOX *b)
*** 1184,1205 ****
  	}
  
  	/* compare within the dimensions of (b) */
! 	for (i = 0; i < b->dim; i++)
  	{
! 		if (Min(a->x[i], a->x[a->dim + i]) >
! 			Max(b->x[i], b->x[b->dim + i]))
  			return (FALSE);
! 		if (Max(a->x[i], a->x[a->dim + i]) <
! 			Min(b->x[i], b->x[b->dim + i]))
  			return (FALSE);
  	}
  
  	/* compare to zero those dimensions in (a) absent in (b) */
! 	for (i = b->dim; i < a->dim; i++)
  	{
! 		if (Min(a->x[i], a->x[a->dim + i]) > 0)
  			return (FALSE);
! 		if (Max(a->x[i], a->x[a->dim + i]) < 0)
  			return (FALSE);
  	}
  
--- 1224,1243 ----
  	}
  
  	/* compare within the dimensions of (b) */
! 	for (i = 0; i < DIM(b); i++)
  	{
! 		if (Min(LL_COORD(a,i), UR_COORD(a,i)) > Max(LL_COORD(b,i), UR_COORD(b,i)))
  			return (FALSE);
! 		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 = DIM(b); i < DIM(a); i++)
  	{
! 		if (Min(LL_COORD(a,i), UR_COORD(a,i)) > 0)
  			return (FALSE);
! 		if (Max(LL_COORD(a,i), UR_COORD(a,i)) < 0)
  			return (FALSE);
  	}
  
*************** cube_distance(PG_FUNCTION_ARGS)
*** 1238,1244 ****
  	int			i;
  
  	/* swap the box pointers if needed */
! 	if (a->dim < b->dim)
  	{
  		NDBOX	   *tmp = b;
  
--- 1276,1282 ----
  	int			i;
  
  	/* swap the box pointers if needed */
! 	if (DIM(a) < DIM(b))
  	{
  		NDBOX	   *tmp = b;
  
*************** cube_distance(PG_FUNCTION_ARGS)
*** 1249,1264 ****
  
  	distance = 0.0;
  	/* compute within the dimensions of (b) */
! 	for (i = 0; i < b->dim; i++)
  	{
! 		d = distance_1D(a->x[i], a->x[i + a->dim], b->x[i], b->x[i + b->dim]);
  		distance += d * d;
  	}
  
  	/* compute distance to zero for those dimensions in (a) absent in (b) */
! 	for (i = b->dim; i < a->dim; i++)
  	{
! 		d = distance_1D(a->x[i], a->x[i + a->dim], 0.0, 0.0);
  		distance += d * d;
  	}
  
--- 1287,1302 ----
  
  	distance = 0.0;
  	/* compute within the dimensions of (b) */
! 	for (i = 0; i < DIM(b); i++)
  	{
! 		d = distance_1D(LL_COORD(a,i), UR_COORD(a,i), LL_COORD(b,i), UR_COORD(b,i));
  		distance += d * d;
  	}
  
  	/* compute distance to zero for those dimensions in (a) absent in (b) */
! 	for (i = DIM(b); i < DIM(a); i++)
  	{
! 		d = distance_1D(LL_COORD(a,i), UR_COORD(a,i), 0.0, 0.0);
  		distance += d * d;
  	}
  
*************** cube_distance(PG_FUNCTION_ARGS)
*** 1276,1281 ****
--- 1314,1320 ----
  	PG_RETURN_FLOAT8(sqrt(distance));
  }
  
+ 
  static double
  distance_1D(double a1, double a2, double b1, double b2)
  {
*************** distance_1D(double a1, double a2, double
*** 1291,1325 ****
  	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);
  }
  
  /* Return dimensions in use in the data structure */
  Datum
  cube_dim(PG_FUNCTION_ARGS)
  {
  	NDBOX	   *c = PG_GETARG_NDBOX(0);
! 	int			dim = c->dim;
! 
  	PG_FREE_IF_COPY(c, 0);
  	PG_RETURN_INT32(dim);
  }
  
  /* Return a specific normalized LL coordinate */
  Datum
  cube_ll_coord(PG_FUNCTION_ARGS)
--- 1330,1359 ----
  	return (0.0);
  }
  
+ 
  /* Test if a box is also a point */
  Datum
  cube_is_point(PG_FUNCTION_ARGS)
  {
! 	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 = 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)
*************** cube_ll_coord(PG_FUNCTION_ARGS)
*** 1328,1335 ****
  	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]);
  	else
  		result = 0;
  
--- 1362,1369 ----
  	int			n = PG_GETARG_INT16(1);
  	double		result;
  
! 	if (DIM(c) >= n && n > 0)
! 		result = Min(LL_COORD(c, n-1), UR_COORD(c, n-1));
  	else
  		result = 0;
  
*************** cube_ll_coord(PG_FUNCTION_ARGS)
*** 1337,1342 ****
--- 1371,1377 ----
  	PG_RETURN_FLOAT8(result);
  }
  
+ 
  /* Return a specific normalized UR coordinate */
  Datum
  cube_ur_coord(PG_FUNCTION_ARGS)
*************** cube_ur_coord(PG_FUNCTION_ARGS)
*** 1345,1352 ****
  	int			n = PG_GETARG_INT16(1);
  	double		result;
  
! 	if (c->dim >= n && n > 0)
! 		result = Max(c->x[n - 1], c->x[c->dim + n - 1]);
  	else
  		result = 0;
  
--- 1380,1387 ----
  	int			n = PG_GETARG_INT16(1);
  	double		result;
  
! 	if (DIM(c) >= n && n > 0)
! 		result = Max(LL_COORD(c, n-1), UR_COORD(c, n-1));
  	else
  		result = 0;
  
*************** cube_ur_coord(PG_FUNCTION_ARGS)
*** 1354,1359 ****
--- 1389,1395 ----
  	PG_RETURN_FLOAT8(result);
  }
  
+ 
  /* Increase or decrease box size by a radius in at least n dimensions. */
  Datum
  cube_enlarge(PG_FUNCTION_ARGS)
*************** cube_enlarge(PG_FUNCTION_ARGS)
*** 1366,1400 ****
  	int			size;
  	int			i,
  				j,
! 				k;
  
  	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 (a->x[i] >= a->x[k])
  		{
! 			result->x[i] = a->x[k] - r;
! 			result->x[j] = a->x[i] + r;
  		}
  		else
  		{
! 			result->x[i] = a->x[i] - r;
! 			result->x[j] = a->x[k] + r;
  		}
  		if (result->x[i] > result->x[j])
  		{
  			result->x[i] = (result->x[i] + result->x[j]) / 2;
  			result->x[j] = result->x[i];
  		}
  	}
  	/* dim > a->dim only if r > 0 */
  	for (; i < dim; i++, j++)
--- 1402,1441 ----
  	int			size;
  	int			i,
  				j,
! 				shrunk_coordinates = 0;
  
  	if (n > CUBE_MAX_DIM)
  		n = CUBE_MAX_DIM;
  	if (r > 0 && n > 0)
  		dim = n;
! 	if (DIM(a) > dim)
! 		dim = DIM(a);
! 
! 	size = CUBE_SIZE(dim);
  	result = (NDBOX *) palloc0(size);
  	SET_VARSIZE(result, size);
! 	SET_DIM(result, dim);
! 	
! 	for (i = 0, j = dim; i < DIM(a); i++, j++)
  	{
! 		if (LL_COORD(a,i) >= UR_COORD(a,i))
  		{
! 			result->x[i] = UR_COORD(a,i) - r;
! 			result->x[j] = LL_COORD(a,i) + r;
  		}
  		else
  		{
! 			result->x[i] = LL_COORD(a,i) - r;
! 			result->x[j] = UR_COORD(a,i) + r;
  		}
  		if (result->x[i] > result->x[j])
  		{
  			result->x[i] = (result->x[i] + result->x[j]) / 2;
  			result->x[j] = result->x[i];
+ 			shrunk_coordinates++;
  		}
+ 		else if (result->x[i] == result->x[j])
+ 			shrunk_coordinates++;
  	}
  	/* dim > a->dim only if r > 0 */
  	for (; i < dim; i++, j++)
*************** cube_enlarge(PG_FUNCTION_ARGS)
*** 1403,1412 ****
--- 1444,1464 ----
  		result->x[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) ){
+ 		size = POINT_SIZE(dim);
+ 		result = (NDBOX *) repalloc(result, size);
+ 		SET_VARSIZE(result, size);
+ 		SET_POINT_BIT(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)
*************** cube_f8(PG_FUNCTION_ARGS)
*** 1415,1498 ****
  	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);
  	double		x = PG_GETARG_FLOAT8(1);
! 	NDBOX	   *result;
  	int			size;
  	int			i;
  
! 	size = offsetof(NDBOX, x[0]) +sizeof(double) * (c->dim + 1) *2;
! 	result = (NDBOX *) palloc0(size);
! 	SET_VARSIZE(result, size);
! 	result->dim = c->dim + 1;
! 	for (i = 0; i < c->dim; i++)
  	{
! 		result->x[i] = c->x[i];
! 		result->x[result->dim + i] = c->x[c->dim + i];
  	}
- 	result->x[result->dim - 1] = x;
- 	result->x[2 * result->dim - 1] = x;
  
! 	PG_FREE_IF_COPY(c, 0);
  	PG_RETURN_NDBOX(result);
  }
  
  /* Add a dimension to an existing cube */
  Datum
  cube_c_f8_f8(PG_FUNCTION_ARGS)
  {
! 	NDBOX	   *c = 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++)
  	{
! 		result->x[i] = c->x[i];
! 		result->x[result->dim + i] = c->x[c->dim + i];
  	}
- 	result->x[result->dim - 1] = x1;
- 	result->x[2 * result->dim - 1] = x2;
  
! 	PG_FREE_IF_COPY(c, 0);
  	PG_RETURN_NDBOX(result);
  }
--- 1467,1595 ----
  	NDBOX	   *result;
  	int			size;
  
! 	size = POINT_SIZE(1);
  	result = (NDBOX *) palloc0(size);
  	SET_VARSIZE(result, size);
! 	SET_DIM(result, 1);
! 	SET_POINT_BIT(result);
! 
! 	result->x[0] = 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;
  
! 	if (x0 == x1)
! 	{
! 		size = POINT_SIZE(1);
! 		result = (NDBOX *) palloc0(size);
! 		SET_VARSIZE(result, size);
! 		SET_DIM(result, 1);
! 		SET_POINT_BIT(result);
! 		result->x[0] = x0;
! 	}
! 	else
! 	{
! 		size = CUBE_SIZE(1);
! 		result = (NDBOX *) palloc0(size);
! 		SET_VARSIZE(result, size);
! 		SET_DIM(result, 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		*cube = PG_GETARG_NDBOX(0);
  	double		x = PG_GETARG_FLOAT8(1);
! 	NDBOX		*result;
  	int			size;
  	int			i;
  
! 	if (IS_POINT(cube))
  	{
! 		size = POINT_SIZE((DIM(cube) + 1));
! 		result = (NDBOX *) palloc0(size);
! 		SET_VARSIZE(result, size);
! 		SET_DIM(result, DIM(cube) + 1);
! 		SET_POINT_BIT(result);
! 		for (i = 0; i < DIM(cube); i++)
! 			result->x[i] = cube->x[i];
! 		result->x[DIM(result) - 1] = x;
! 	}
! 	else
! 	{
! 		size = CUBE_SIZE((DIM(cube) + 1));
! 		result = (NDBOX *) palloc0(size);
! 		SET_VARSIZE(result, size);
! 		SET_DIM(result, DIM(cube) + 1);
! 		for (i = 0; i < DIM(cube); i++)
! 		{
! 			result->x[i] = cube->x[i];
! 			result->x[DIM(result) + i] = cube->x[DIM(cube) + i];
! 		}
! 		result->x[DIM(result) - 1] = x;
! 		result->x[2*DIM(result) - 1] = x;
  	}
  
! 	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	   *cube = PG_GETARG_NDBOX(0);
  	double		x1 = PG_GETARG_FLOAT8(1);
  	double		x2 = PG_GETARG_FLOAT8(2);
  	NDBOX	   *result;
  	int			size;
  	int			i;
  
! 	if (IS_POINT(cube) && (x1 == x2)){
! 		size = POINT_SIZE((DIM(cube) + 1));
! 		result = (NDBOX *) palloc0(size);
! 		SET_VARSIZE(result, size);
! 		SET_DIM(result, DIM(cube) + 1);
! 		SET_POINT_BIT(result);
! 		for (i = 0; i < DIM(cube); i++)
! 			result->x[i] = cube->x[i];
! 		result->x[DIM(result) - 1] = x1;
! 	}
! 	else
  	{
! 		size = CUBE_SIZE((DIM(cube) + 1));
! 		result = (NDBOX *) palloc0(size);
! 		SET_VARSIZE(result, size);
! 		SET_DIM(result, DIM(cube) + 1);
! 		for (i = 0; i < DIM(cube); i++)
! 		{
! 			result->x[i] = LL_COORD(cube, i);
! 			result->x[DIM(result) + i] = UR_COORD(cube, i);
! 		}
! 		result->x[DIM(result) - 1] = x1;
! 		result->x[2 * DIM(result) - 1] = x2;
  	}
  
! 	PG_FREE_IF_COPY(cube, 0);
  	PG_RETURN_NDBOX(result);
  }
+ 
diff --git a/contrib/cube/cubedata.h b/contrib/cube/cubedata.h
new file mode 100644
index fd0c26a..9ef297d
*** a/contrib/cube/cubedata.h
--- b/contrib/cube/cubedata.h
***************
*** 4,14 ****
  
  typedef struct NDBOX
  {
! 	int32		vl_len_;		/* varlena header (do not touch directly!) */
! 	unsigned int dim;
! 	double		x[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)
--- 4,39 ----
  
  typedef struct NDBOX
  {
! 	/* varlena header (do not touch directly!) */
! 	int32 vl_len_;
! 
! 	/* 
! 	 * 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-30 : not used;
! 	 *  bit  31   : point flag. If set, then NDBOX stores
! 	 *             n dimensions instead of 2*n;
! 	 */
! 	unsigned int header;
! 	double x[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)
! 
! #define IS_POINT(cube)		( cube->header >> 31 )
! #define SET_POINT_BIT(cube)	( cube->header = cube->header + 0x80000000 )
! #define DIM(cube)			( cube->header & 0x7fffffff )
! #define SET_DIM(cube, _dim)	( cube->header = _dim )
! 
! #define LL_COORD(cube, i) ( cube->x[i] )
! #define UR_COORD(cube, i) ( IS_POINT(cube) ? cube->x[i] : cube->x[i + DIM(cube)] )
! 
! #define POINT_SIZE(_dim) (offsetof(NDBOX, x[0]) + sizeof(double)*_dim)
! #define CUBE_SIZE(_dim) (offsetof(NDBOX, x[0]) + sizeof(double)*_dim*2)
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
new file mode 100644
index 21fe537..abc0790
*** a/contrib/cube/cubeparse.y
--- b/contrib/cube/cubeparse.y
*************** write_box(unsigned int dim, char *str1, 
*** 175,185 ****
  	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;
  
  	s = str1;
  	bp->x[i=0] = strtod(s, NULL);
--- 175,186 ----
  	NDBOX	   *bp;
  	char	   *s;
  	int			i;
! 	int			size = CUBE_SIZE(dim);
! 	bool		point = true;
  
  	bp = palloc0(size);
  	SET_VARSIZE(bp, size);
! 	SET_DIM(bp, dim);
  
  	s = str1;
  	bp->x[i=0] = strtod(s, NULL);
*************** write_box(unsigned int dim, char *str1, 
*** 195,200 ****
--- 196,213 ----
  	{
  		s++; i++;
  		bp->x[i] = strtod(s, NULL);
+ 		if (bp->x[i] != bp->x[i-dim])
+ 			point = false;
+ 	}
+ 
+ 	if (bp->x[0] != bp->x[dim])
+ 		point = false;
+ 	if (point)
+ 	{
+ 		size = POINT_SIZE(dim);
+ 		bp = repalloc(bp, size);
+ 		SET_VARSIZE(bp, size);
+ 		SET_POINT_BIT(bp);
  	}
  
  	return(bp);
*************** write_box(unsigned int dim, char *str1, 
*** 203,233 ****
  static NDBOX *
  write_point_as_box(char *str, int dim)
  {
!   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);
  }
  
  #include "cubescan.c"
--- 216,244 ----
  static NDBOX *
  write_point_as_box(char *str, int dim)
  {
! 	NDBOX		*bp;
! 	int			i,
  				size;
! 	double		x;
! 	char		*s = str;
  
! 	size = POINT_SIZE(dim);
! 	bp = palloc0(size);
! 	SET_VARSIZE(bp, size);
! 	SET_DIM(bp, dim);
! 	SET_POINT_BIT(bp);
  
! 	i = 0;
! 	x = strtod(s, NULL);
! 	bp->x[0] = x;
! 	while ((s = strchr(s, ',')) != NULL)
! 	{
! 		s++; i++;
! 		x = strtod(s, NULL);
! 		bp->x[i] = x;
! 	}
  
! 	return(bp);
  }
  
  #include "cubescan.c"
diff --git a/contrib/cube/expected/cube_1.out b/contrib/cube/expected/cube_1.out
new file mode 100644
index fefebf5..c07d61d
*** a/contrib/cube/expected/cube_1.out
--- b/contrib/cube/expected/cube_1.out
*************** SELECT cube_subset(cube('(1,3,5),(6,7,8)
*** 473,480 ****
--- 473,557 ----
   (5, 3, 1, 1),(8, 7, 6, 6)
  (1 row)
  
+ SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]);
+  cube_subset  
+ --------------
+  (5, 3, 1, 1)
+ (1 row)
+ 
  SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]);
  ERROR:  Index out of bounds
+ SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]);
+ ERROR:  Index out of bounds
+ --
+ -- Test point processing
+ --
+ SELECT cube('(1,2),(1,2)'); -- cube_in
+   cube  
+ --------
+  (1, 2)
+ (1 row)
+ 
+ SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8
+    cube    
+ -----------
+  (0, 1, 2)
+ (1 row)
+ 
+ SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8
+      cube     
+ --------------
+  (5, 6, 7, 8)
+ (1 row)
+ 
+ SELECT cube(1.37); -- cube_f8
+   cube  
+ --------
+  (1.37)
+ (1 row)
+ 
+ SELECT cube(1.37, 1.37); -- cube_f8_f8
+   cube  
+ --------
+  (1.37)
+ (1 row)
+ 
+ SELECT cube(cube(1,1), 42); -- cube_c_f8
+   cube   
+ ---------
+  (1, 42)
+ (1 row)
+ 
+ SELECT cube(cube(1,2), 42); -- cube_c_f8
+       cube       
+ -----------------
+  (1, 42),(2, 42)
+ (1 row)
+ 
+ SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8
+   cube   
+ ---------
+  (1, 42)
+ (1 row)
+ 
+ SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8
+       cube       
+ -----------------
+  (1, 42),(1, 24)
+ (1 row)
+ 
+ SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8
+       cube       
+ -----------------
+  (1, 42),(2, 42)
+ (1 row)
+ 
+ SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8
+       cube       
+ -----------------
+  (1, 42),(2, 24)
+ (1 row)
+ 
  --
  -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in.
  --
*************** SELECT cube_distance('(0)'::cube,'(.3,.4
*** 878,883 ****
--- 955,978 ----
             0.5
  (1 row)
  
+ SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube);
+  cube_distance 
+ ---------------
+              0
+ (1 row)
+ 
+ SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube);
+  cube_distance 
+ ---------------
+            190
+ (1 row)
+ 
+ SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube);
+   cube_distance   
+ ------------------
+  140.762210837994
+ (1 row)
+ 
  -- Test of cube function (text to cube)
  --
  SELECT cube('(1,1.2)'::text);
*************** SELECT cube_dim('(0,0,0)'::cube);
*** 912,917 ****
--- 1007,1024 ----
          3
  (1 row)
  
+ SELECT cube_dim('(42,42,42),(42,42,42)'::cube);
+  cube_dim 
+ ----------
+         3
+ (1 row)
+ 
+ SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube);
+  cube_dim 
+ ----------
+         5
+ (1 row)
+ 
  -- Test of cube_ll_coord function (retrieves LL coodinate values)
  --
  SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1);
*************** SELECT cube_ll_coord('(-1,1),(2,-2)'::cu
*** 932,937 ****
--- 1039,1080 ----
               0
  (1 row)
  
+ SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1);
+  cube_ll_coord 
+ ---------------
+              1
+ (1 row)
+ 
+ SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2);
+  cube_ll_coord 
+ ---------------
+              2
+ (1 row)
+ 
+ SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3);
+  cube_ll_coord 
+ ---------------
+              0
+ (1 row)
+ 
+ SELECT cube_ll_coord('(42,137)'::cube, 1);
+  cube_ll_coord 
+ ---------------
+             42
+ (1 row)
+ 
+ SELECT cube_ll_coord('(42,137)'::cube, 2);
+  cube_ll_coord 
+ ---------------
+            137
+ (1 row)
+ 
+ SELECT cube_ll_coord('(42,137)'::cube, 3);
+  cube_ll_coord 
+ ---------------
+              0
+ (1 row)
+ 
  -- Test of cube_ur_coord function (retrieves UR coodinate values)
  --
  SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1);
*************** SELECT cube_ur_coord('(-1,1),(2,-2)'::cu
*** 952,957 ****
--- 1095,1136 ----
               0
  (1 row)
  
+ SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1);
+  cube_ur_coord 
+ ---------------
+              1
+ (1 row)
+ 
+ SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2);
+  cube_ur_coord 
+ ---------------
+              2
+ (1 row)
+ 
+ SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3);
+  cube_ur_coord 
+ ---------------
+              0
+ (1 row)
+ 
+ SELECT cube_ur_coord('(42,137)'::cube, 1);
+  cube_ur_coord 
+ ---------------
+             42
+ (1 row)
+ 
+ SELECT cube_ur_coord('(42,137)'::cube, 2);
+  cube_ur_coord 
+ ---------------
+            137
+ (1 row)
+ 
+ SELECT cube_ur_coord('(42,137)'::cube, 3);
+  cube_ur_coord 
+ ---------------
+              0
+ (1 row)
+ 
  -- Test of cube_is_point
  --
  SELECT cube_is_point('(0)'::cube);
*************** SELECT cube_enlarge('(2,-2),(-3,7)'::cub
*** 1100,1105 ****
--- 1279,1386 ----
   (-0.5, 1),(-0.5, 4)
  (1 row)
  
+ SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5);
+  cube_enlarge 
+ --------------
+  (42, 0, 0)
+ (1 row)
+ 
+ SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5);
+  cube_enlarge 
+ --------------
+  (42, 0, 0)
+ (1 row)
+ 
+ -- Test of cube_union (MBR for two cubes)
+ --
+ SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube);
+       cube_union      
+ ----------------------
+  (1, 2, 0),(8, 9, 10)
+ (1 row)
+ 
+ SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube);
+         cube_union         
+ ---------------------------
+  (1, 2, 0, 0),(4, 2, 0, 0)
+ (1 row)
+ 
+ SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube);
+   cube_union   
+ ---------------
+  (1, 2),(4, 2)
+ (1 row)
+ 
+ SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube);
+  cube_union 
+ ------------
+  (1, 2)
+ (1 row)
+ 
+ SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube);
+  cube_union 
+ ------------
+  (1, 2, 0)
+ (1 row)
+ 
+ -- Test of cube_inter
+ --
+ SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects
+    cube_inter    
+ -----------------
+  (3, 4),(10, 11)
+ (1 row)
+ 
+ SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes
+   cube_inter   
+ ---------------
+  (3, 4),(6, 5)
+ (1 row)
+ 
+ SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection
+     cube_inter     
+ -------------------
+  (13, 14),(10, 11)
+ (1 row)
+ 
+ SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects
+     cube_inter    
+ ------------------
+  (3, 14),(10, 11)
+ (1 row)
+ 
+ SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection
+  cube_inter 
+ ------------
+  (10, 11)
+ (1 row)
+ 
+ SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args
+  cube_inter 
+ ------------
+  (1, 2, 3)
+ (1 row)
+ 
+ SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args
+      cube_inter      
+ ---------------------
+  (5, 6, 3),(1, 2, 3)
+ (1 row)
+ 
+ -- Test of cube_size
+ --
+ SELECT cube_size('(4,8),(15,16)'::cube);
+  cube_size 
+ -----------
+         88
+ (1 row)
+ 
+ SELECT cube_size('(42,137)'::cube);
+  cube_size 
+ -----------
+          0
+ (1 row)
+ 
  -- Load some example data and build the index
  --
  CREATE TABLE test_cube (c cube);
diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql
new file mode 100644
index 02e068e..d58974c
*** a/contrib/cube/sql/cube.sql
--- b/contrib/cube/sql/cube.sql
*************** SELECT cube('{0,1,2}'::float[], '{3}'::f
*** 112,118 ****
--- 112,135 ----
  SELECT cube(NULL::float[], '{3}'::float[]);
  SELECT cube('{0,1,2}'::float[]);
  SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]);
+ SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]);
  SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]);
+ SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]);
+ 
+ --
+ -- Test point processing
+ --
+ SELECT cube('(1,2),(1,2)'); -- cube_in
+ SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8
+ SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8
+ SELECT cube(1.37); -- cube_f8
+ SELECT cube(1.37, 1.37); -- cube_f8_f8
+ SELECT cube(cube(1,1), 42); -- cube_c_f8
+ SELECT cube(cube(1,2), 42); -- cube_c_f8
+ SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8
+ SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8
+ SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8
+ SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8
  
  --
  -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in.
*************** SELECT '(-1,-1),(1,1)'::cube            
*** 212,217 ****
--- 229,237 ----
  --
  SELECT cube_distance('(0)'::cube,'(2,2,2,2)'::cube);
  SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
+ SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube);
+ SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube);
+ SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube);
  
  -- Test of cube function (text to cube)
  --
*************** SELECT cube(NULL);
*** 223,240 ****
--- 243,274 ----
  SELECT cube_dim('(0)'::cube);
  SELECT cube_dim('(0,0)'::cube);
  SELECT cube_dim('(0,0,0)'::cube);
+ SELECT cube_dim('(42,42,42),(42,42,42)'::cube);
+ SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube);
  
  -- Test of cube_ll_coord function (retrieves LL coodinate values)
  --
  SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1);
  SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 2);
  SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3);
+ SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1);
+ SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2);
+ SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3);
+ SELECT cube_ll_coord('(42,137)'::cube, 1);
+ SELECT cube_ll_coord('(42,137)'::cube, 2);
+ SELECT cube_ll_coord('(42,137)'::cube, 3);
  
  -- Test of cube_ur_coord function (retrieves UR coodinate values)
  --
  SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1);
  SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 2);
  SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3);
+ SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1);
+ SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2);
+ SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3);
+ SELECT cube_ur_coord('(42,137)'::cube, 1);
+ SELECT cube_ur_coord('(42,137)'::cube, 2);
+ SELECT cube_ur_coord('(42,137)'::cube, 3);
  
  -- Test of cube_is_point
  --
*************** SELECT cube_enlarge('(2,-2),(-3,7)'::cub
*** 265,270 ****
--- 299,329 ----
  SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 3, 2);
  SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -1, 2);
  SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2);
+ SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5);
+ SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5);
+ 
+ -- Test of cube_union (MBR for two cubes)
+ --
+ SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube);
+ SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube);
+ SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube);
+ SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube);
+ SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube);
+ 
+ -- Test of cube_inter
+ --
+ SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects
+ SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes
+ SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection
+ SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects
+ SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection
+ SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args
+ SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args
+ 
+ -- Test of cube_size
+ --
+ SELECT cube_size('(4,8),(15,16)'::cube);
+ SELECT cube_size('(42,137)'::cube);
  
  -- Load some example data and build the index
  --
#2Alexander Korotkov
aekorotkov@gmail.com
In reply to: Stas Kelvich (#1)
Re: [HACKERS] Cube extension point support // GSoC'13

On Fri, Jul 12, 2013 at 3:57 PM, Stas Kelvich <stas.kelvich@gmail.com>wrote:

Hello.

here is a patch adding to cube extension support for compressed
representation of point cubes. If cube is a point, i.e. has coincident
lower left and upper right corners, than only one corner is stored. First
bit of the cube header indicates whether the cube is point or not. Few
moments:

* Patch preserves binary compatibility with old indices

New representation of points will work in both index and heap. So, we
should speak about just compatibility with old cubes.

* All functions that create cubes from user input, check whether it is a
point or not
* All internal functions that can return cubes takes care of all cases
where a cube might become a point
* Added tests for checking correct point behavior

Also this patch includes adapted Alexander Korotkov's patch with kNN-based
ordering operator, which he wrote for postgresql-9.0beta1 with knngist
patch. More info there
/messages/by-id/AANLkTimhFaq6hCibRnk0tlcQMIyhYWHwAQ2ZD87wbH86@mail.gmail.com

I think ordering operator should be extracted into separated patch together
with another ordering operators of your project.

Patch contains some formatting issues. For example, this comment

/* Point can arise in two cases:
1) When argument is point and r == 0
2) When all coordinates was set to their averages */

should contain star sign on the beginning of each line. Also it will be
reflowed by pgindent. Correct formatting for this comment should look like
this:

/*--------------------------------------------------
* Point can arise in two cases:
* 1) When argument is point and r == 0
* 2) When all coordinates was set to their averages
*/

See coding convention for details:
http://www.postgresql.org/docs/current/static/source-format.html

------
With best regards,
Alexander Korotkov.

#3Heikki Linnakangas
hlinnakangas@vmware.com
In reply to: Stas Kelvich (#1)
Re: [HACKERS] Cube extension point support // GSoC'13

On 12.07.2013 14:57, Stas Kelvich wrote:

Hello.

here is a patch adding to cube extension support for compressed representation of point cubes. If cube is a point, i.e. has coincident lower left and upper right corners, than only one corner is stored. First bit of the cube header indicates whether the cube is point or not. Few moments:

* Patch preserves binary compatibility with old indices
* All functions that create cubes from user input, check whether it is a point or not
* All internal functions that can return cubes takes care of all cases where a cube might become a point

Great!

cube_is_point() needs to still handle old-style points. An NDBOX without
the point-flag set, where the ll and ur coordinates for each dimension
are the same, still needs to be considered a point. Even if you are
careful to never construct such structs in the code, they can be present
on-disk if you have upgraded from an earlier version with pg_upgrade.
Same in cube_out().

* Added tests for checking correct point behavior

You'll need to adjust all the expected output files, not only cube_1.out.

Also this patch includes adapted Alexander Korotkov's patch with kNN-based ordering operator, which he wrote for postgresql-9.0beta1 with knngist patch. More info there /messages/by-id/AANLkTimhFaq6hCibRnk0tlcQMIyhYWHwAQ2ZD87wbH86@mail.gmail.com

To make review easier, it would be better to keep that as a separate
patch, actually. Could you split it up again, please?

- Heikki

--
Sent via pgsql-students mailing list (pgsql-students@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-students

#4Stas Kelvich
stas.kelvich@gmail.com
In reply to: Heikki Linnakangas (#3)
1 attachment(s)
Re: [HACKERS] Cube extension point support // GSoC'13

Hello

There is new version of patch. I have separated ordering operators to different patch (https://commitfest.postgresql.org/action/patch_view?id=1243), fixed formatting issues and implemented backward compatibility with old-style points in cube_is_point() and cube_out().

Also comparing output files I've discovered that this four files is combination of two types of different behavior:

1) SELECT '-1e-700'::cube AS cube;
can be (0) or (-0)

2) Amount of zeros in exponent of floating point, i.e. SELECT '1e27'::cube AS cube;
can be (1e+027) or (1e+27)

On my system (OSX) it is second option in both situations. I've also tested it on FreeBSD 9.0 and Ubuntu 12.04 with the same results. So is there some ideas how can I reproduce such results?

Stas.

Attachments:

points.diffapplication/octet-stream; name=points.diff; x-unix-mode=0644Download
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index dab0e6e..89cc85a 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -181,6 +181,7 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
 	int			i;
 	int			dim;
 	int			size;
+	bool		point = true;
 	double	   *dur,
 			   *dll;
 
@@ -198,15 +199,25 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
 	dur = ARRPTR(ur);
 	dll = ARRPTR(ll);
 
-	size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
+	size = CUBE_SIZE(dim);
 	result = (NDBOX *) palloc0(size);
 	SET_VARSIZE(result, size);
-	result->dim = dim;
+	SET_DIM(result, dim);
 
 	for (i = 0; i < dim; i++)
 	{
 		result->x[i] = dur[i];
 		result->x[i + dim] = dll[i];
+		if (dur[i] != dll[i])
+			point = false;
+	}
+
+	if (point)
+	{
+		size = POINT_SIZE(dim);
+		result = repalloc(result, size);
+		SET_VARSIZE(result, size);
+		SET_POINT_BIT(result);
 	}
 
 	PG_RETURN_NDBOX(result);
@@ -234,16 +245,14 @@ cube_a_f8(PG_FUNCTION_ARGS)
 
 	dur = ARRPTR(ur);
 
-	size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
+	size = POINT_SIZE(dim);
 	result = (NDBOX *) palloc0(size);
 	SET_VARSIZE(result, size);
-	result->dim = dim;
+	SET_DIM(result, dim);
+	SET_POINT_BIT(result);
 
 	for (i = 0; i < dim; i++)
-	{
 		result->x[i] = dur[i];
-		result->x[i + dim] = dur[i];
-	}
 
 	PG_RETURN_NDBOX(result);
 }
@@ -267,14 +276,17 @@ cube_subset(PG_FUNCTION_ARGS)
 	dx = (int32 *) ARR_DATA_PTR(idx);
 
 	dim = ARRNELEMS(idx);
-	size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
+	size = IS_POINT(c) ? POINT_SIZE(dim) : CUBE_SIZE(dim);
 	result = (NDBOX *) palloc0(size);
 	SET_VARSIZE(result, size);
-	result->dim = dim;
+	SET_DIM(result, dim);
+
+	if (IS_POINT(c))
+		SET_POINT_BIT(result);
 
 	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,
@@ -282,7 +294,8 @@ cube_subset(PG_FUNCTION_ARGS)
 					 errmsg("Index out of bounds")));
 		}
 		result->x[i] = c->x[dx[i] - 1];
-		result->x[i + dim] = c->x[dx[i] + c->dim - 1];
+		if (!IS_POINT(c))
+			result->x[i + dim] = c->x[dx[i] + DIM(c) - 1];
 	}
 
 	PG_FREE_IF_COPY(c, 0);
@@ -294,10 +307,10 @@ 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;
+	bool		old_style_point = true;
 
 	initStringInfo(&buf);
 
@@ -317,20 +330,22 @@ 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));
+
+		/* backward compatibility */
+		if (LL_COORD(cube,i) != UR_COORD(cube, i))
+			old_style_point = false;
 	}
 	appendStringInfoChar(&buf, ')');
 
-	if (!equal)
+	if (!IS_POINT(cube) || !old_style_point)
 	{
 		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, ')');
 	}
@@ -422,24 +437,14 @@ g_cube_union(PG_FUNCTION_ARGS)
 Datum
 g_cube_compress(PG_FUNCTION_ARGS)
 {
-	PG_RETURN_DATUM(PG_GETARG_DATUM(0));
+	GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	PG_RETURN_POINTER(entry);
 }
 
 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);
-	}
+	GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	PG_RETURN_POINTER(entry);
 }
 
@@ -728,23 +733,15 @@ 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;
 
@@ -752,28 +749,41 @@ cube_union_v0(NDBOX *a, NDBOX *b)
 		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 = palloc0(CUBE_SIZE(DIM(a)));
+	SET_VARSIZE(result, CUBE_SIZE(DIM(a)));
+	SET_DIM(result, DIM(a));
+
+	 /* 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]);
+		result->x[i] = Min(
+			Min(LL_COORD(a,i), UR_COORD(a,i)),
+			Min(LL_COORD(b,i), UR_COORD(b,i))
+		);
+		result->x[i + DIM(a)] = Max(
+			Max(LL_COORD(a,i), UR_COORD(a,i)), 
+			Max(LL_COORD(b,i), UR_COORD(b,i))
+		);
+		if (result->x[i] != result->x[i + DIM(a)])
+			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;
+		result->x[i] = Min(0,
+			Min(LL_COORD(a,i), UR_COORD(a,i))
+		);
+		result->x[i + DIM(a)] = Max(0,
+			Max(LL_COORD(a,i), UR_COORD(a,i))
+		);
+		if (result->x[i] != result->x[i + DIM(a)])
+			point_result = false;
 	}
 
-	/* compute the union */
-	for (i = 0; i < a->dim; i++)
+	if (point_result)
 	{
-		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]);
+		result = repalloc(result, POINT_SIZE(DIM(a)));
+		SET_VARSIZE(result, POINT_SIZE(DIM(a)));
+		SET_POINT_BIT(result);
 	}
 
 	return (result);
@@ -800,24 +810,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,28 +824,40 @@ 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 = (NDBOX *) palloc0(CUBE_SIZE(DIM(a)));
+	SET_VARSIZE(result, CUBE_SIZE(DIM(a)));
+	SET_DIM(result, DIM(a));
+
+	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]);
+		result->x[i] = Max(
+			Min(LL_COORD(a,i), UR_COORD(a,i)),
+			Min(LL_COORD(b,i), UR_COORD(b,i))
+		);
+		result->x[i + DIM(a)] = Min(
+			Max(LL_COORD(a,i), UR_COORD(a,i)),
+			Max(LL_COORD(b,i), UR_COORD(b,i))
+		);
+		if (result->x[i] != result->x[i + DIM(a)])
+			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;
+		result->x[i] = Max(0,
+			Min(LL_COORD(a,i), UR_COORD(a,i))
+		);
+		result->x[i + DIM(a)] = Min(0,
+			Max(LL_COORD(a,i), UR_COORD(a,i))
+		);
+		if (result->x[i] != result->x[i + DIM(a)])
+			point_result = false;
 	}
 
-	/* compute the intersection */
-	for (i = 0; i < a->dim; i++)
+	if (point_result)
 	{
-		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]);
+		result = repalloc(result, POINT_SIZE(DIM(a)));
+		SET_VARSIZE(result, POINT_SIZE(DIM(a)));
+		SET_POINT_BIT(result);
 	}
 
 	if (swapped)
@@ -873,12 +883,11 @@ 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);
@@ -887,16 +896,15 @@ cube_size(PG_FUNCTION_ARGS)
 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;
 }
@@ -909,43 +917,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 +963,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;
 		}
 
@@ -1098,30 +1106,30 @@ 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);
 	}
 
@@ -1173,7 +1181,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 +1190,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 +1242,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 +1253,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;
 	}
 
@@ -1293,17 +1299,18 @@ distance_1D(double a1, double a2, double b1, double b2)
 Datum
 cube_is_point(PG_FUNCTION_ARGS)
 {
-	NDBOX	   *a = PG_GETARG_NDBOX(0);
-	int			i,
-				j;
+	NDBOX		*cube = PG_GETARG_NDBOX(0);
+	int			i;
 
-	for (i = 0, j = a->dim; i < a->dim; i++, j++)
+	if (IS_POINT(cube))
+		PG_RETURN_BOOL(TRUE);
+
+	/* backward compatibility */
+	for (i=0; i<DIM(cube); i++)
 	{
-		if (a->x[i] != a->x[j])
+		if (LL_COORD(cube, i) != UR_COORD(cube, i))
 			PG_RETURN_BOOL(FALSE);
 	}
-
-	PG_FREE_IF_COPY(a, 0);
 	PG_RETURN_BOOL(TRUE);
 }
 
@@ -1312,8 +1319,7 @@ 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);
 }
@@ -1326,8 +1332,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;
 
@@ -1343,8 +1349,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;
 
@@ -1364,35 +1370,40 @@ cube_enlarge(PG_FUNCTION_ARGS)
 	int			size;
 	int			i,
 				j,
-				k;
+				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;
+	if (DIM(a) > dim)
+		dim = DIM(a);
+
+	size = CUBE_SIZE(dim);
 	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++)
+	SET_DIM(result, dim);
+	
+	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;
+			result->x[i] = UR_COORD(a,i) - r;
+			result->x[j] = LL_COORD(a,i) + r;
 		}
 		else
 		{
-			result->x[i] = a->x[i] - r;
-			result->x[j] = a->x[k] + r;
+			result->x[i] = LL_COORD(a,i) - r;
+			result->x[j] = UR_COORD(a,i) + r;
 		}
 		if (result->x[i] > result->x[j])
 		{
 			result->x[i] = (result->x[i] + result->x[j]) / 2;
 			result->x[j] = result->x[i];
+			shrunk_coordinates++;
 		}
+		else if (result->x[i] == result->x[j])
+			shrunk_coordinates++;
 	}
 	/* dim > a->dim only if r > 0 */
 	for (; i < dim; i++, j++)
@@ -1401,6 +1412,18 @@ cube_enlarge(PG_FUNCTION_ARGS)
 		result->x[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) ){
+		size = POINT_SIZE(dim);
+		result = (NDBOX *) repalloc(result, size);
+		SET_VARSIZE(result, size);
+		SET_POINT_BIT(result);
+	}
+
 	PG_FREE_IF_COPY(a, 0);
 	PG_RETURN_NDBOX(result);
 }
@@ -1413,11 +1436,13 @@ cube_f8(PG_FUNCTION_ARGS)
 	NDBOX	   *result;
 	int			size;
 
-	size = offsetof(NDBOX, x[0]) +sizeof(double) * 2;
+	size = POINT_SIZE(1);
 	result = (NDBOX *) palloc0(size);
 	SET_VARSIZE(result, size);
-	result->dim = 1;
-	result->x[0] = result->x[1] = x;
+	SET_DIM(result, 1);
+	SET_POINT_BIT(result);
+
+	result->x[0] = x;
 
 	PG_RETURN_NDBOX(result);
 }
@@ -1428,15 +1453,27 @@ cube_f8_f8(PG_FUNCTION_ARGS)
 {
 	double		x0 = PG_GETARG_FLOAT8(0);
 	double		x1 = PG_GETARG_FLOAT8(1);
-	NDBOX	   *result;
+	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;
+	if (x0 == x1)
+	{
+		size = POINT_SIZE(1);
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, 1);
+		SET_POINT_BIT(result);
+		result->x[0] = x0;
+	}
+	else
+	{
+		size = CUBE_SIZE(1);
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, 1);
+		result->x[0] = x0;
+		result->x[1] = x1;
+	}
 
 	PG_RETURN_NDBOX(result);
 }
@@ -1446,25 +1483,39 @@ cube_f8_f8(PG_FUNCTION_ARGS)
 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;
+	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))
 	{
-		result->x[i] = c->x[i];
-		result->x[result->dim + i] = c->x[c->dim + i];
+		size = POINT_SIZE((DIM(cube) + 1));
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, DIM(cube) + 1);
+		SET_POINT_BIT(result);
+		for (i = 0; i < DIM(cube); i++)
+			result->x[i] = cube->x[i];
+		result->x[DIM(result) - 1] = x;
+	}
+	else
+	{
+		size = CUBE_SIZE((DIM(cube) + 1));
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, DIM(cube) + 1);
+		for (i = 0; i < DIM(cube); i++)
+		{
+			result->x[i] = cube->x[i];
+			result->x[DIM(result) + i] = cube->x[DIM(cube) + i];
+		}
+		result->x[DIM(result) - 1] = x;
+		result->x[2*DIM(result) - 1] = x;
 	}
-	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);
 }
 
@@ -1472,25 +1523,39 @@ cube_c_f8(PG_FUNCTION_ARGS)
 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)){
+		size = POINT_SIZE((DIM(cube) + 1));
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, DIM(cube) + 1);
+		SET_POINT_BIT(result);
+		for (i = 0; i < DIM(cube); i++)
+			result->x[i] = cube->x[i];
+		result->x[DIM(result) - 1] = x1;
+	}
+	else
 	{
-		result->x[i] = c->x[i];
-		result->x[result->dim + i] = c->x[c->dim + i];
+		size = CUBE_SIZE((DIM(cube) + 1));
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, DIM(cube) + 1);
+		for (i = 0; i < DIM(cube); i++)
+		{
+			result->x[i] = LL_COORD(cube, i);
+			result->x[DIM(result) + i] = UR_COORD(cube, i);
+		}
+		result->x[DIM(result) - 1] = x1;
+		result->x[2 * DIM(result) - 1] = x2;
 	}
-	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..9ef297d 100644
--- a/contrib/cube/cubedata.h
+++ b/contrib/cube/cubedata.h
@@ -4,11 +4,36 @@
 
 typedef struct NDBOX
 {
-	int32		vl_len_;		/* varlena header (do not touch directly!) */
-	unsigned int dim;
-	double		x[1];
+	/* varlena header (do not touch directly!) */
+	int32 vl_len_;
+
+	/* 
+	 * 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-30 : not used;
+	 *  bit  31   : point flag. If set, then NDBOX stores
+	 *             n dimensions instead of 2*n;
+	 */
+	unsigned int header;
+	double x[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)
+#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)
+
+#define IS_POINT(cube)		( cube->header >> 31 )
+#define SET_POINT_BIT(cube)	( cube->header = cube->header + 0x80000000 )
+#define DIM(cube)			( cube->header & 0x7fffffff )
+#define SET_DIM(cube, _dim)	( cube->header = _dim )
+
+#define LL_COORD(cube, i) ( cube->x[i] )
+#define UR_COORD(cube, i) ( IS_POINT(cube) ? cube->x[i] : cube->x[i + DIM(cube)] )
+
+#define POINT_SIZE(_dim) (offsetof(NDBOX, x[0]) + sizeof(double)*_dim)
+#define CUBE_SIZE(_dim) (offsetof(NDBOX, x[0]) + sizeof(double)*_dim*2)
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index d7205b8..80a2e21 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -175,11 +175,12 @@ write_box(unsigned int dim, char *str1, char *str2)
 	NDBOX	   *bp;
 	char	   *s;
 	int			i;
-	int			size = offsetof(NDBOX, x[0]) + sizeof(double) * dim * 2;
+	int			size = CUBE_SIZE(dim);
+	bool		point = true;
 
 	bp = palloc0(size);
 	SET_VARSIZE(bp, size);
-	bp->dim = dim;
+	SET_DIM(bp, dim);
 
 	s = str1;
 	bp->x[i=0] = strtod(s, NULL);
@@ -195,6 +196,18 @@ write_box(unsigned int dim, char *str1, char *str2)
 	{
 		s++; i++;
 		bp->x[i] = strtod(s, NULL);
+		if (bp->x[i] != bp->x[i-dim])
+			point = false;
+	}
+
+	if (bp->x[0] != bp->x[dim])
+		point = false;
+	if (point)
+	{
+		size = POINT_SIZE(dim);
+		bp = repalloc(bp, size);
+		SET_VARSIZE(bp, size);
+		SET_POINT_BIT(bp);
 	}
 
 	return(bp);
@@ -203,31 +216,29 @@ write_box(unsigned int dim, char *str1, char *str2)
 static NDBOX *
 write_point_as_box(char *str, int dim)
 {
-  NDBOX		   *bp;
-  int			i,
+	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);
+	double		x;
+	char		*s = str;
+
+	size = POINT_SIZE(dim);
+	bp = palloc0(size);
+	SET_VARSIZE(bp, size);
+	SET_DIM(bp, dim);
+	SET_POINT_BIT(bp);
+
+	i = 0;
+	x = strtod(s, NULL);
+	bp->x[0] = x;
+	while ((s = strchr(s, ',')) != NULL)
+	{
+		s++; i++;
+		x = strtod(s, NULL);
+		bp->x[i] = x;
+	}
+
+	return(bp);
 }
 
 #include "cubescan.c"
diff --git a/contrib/cube/expected/cube_1.out b/contrib/cube/expected/cube_1.out
index fefebf5..c07d61d 100644
--- a/contrib/cube/expected/cube_1.out
+++ b/contrib/cube/expected/cube_1.out
@@ -473,8 +473,85 @@ SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]);
  (5, 3, 1, 1),(8, 7, 6, 6)
 (1 row)
 
+SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]);
+ cube_subset  
+--------------
+ (5, 3, 1, 1)
+(1 row)
+
 SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]);
 ERROR:  Index out of bounds
+SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]);
+ERROR:  Index out of bounds
+--
+-- Test point processing
+--
+SELECT cube('(1,2),(1,2)'); -- cube_in
+  cube  
+--------
+ (1, 2)
+(1 row)
+
+SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8
+   cube    
+-----------
+ (0, 1, 2)
+(1 row)
+
+SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8
+     cube     
+--------------
+ (5, 6, 7, 8)
+(1 row)
+
+SELECT cube(1.37); -- cube_f8
+  cube  
+--------
+ (1.37)
+(1 row)
+
+SELECT cube(1.37, 1.37); -- cube_f8_f8
+  cube  
+--------
+ (1.37)
+(1 row)
+
+SELECT cube(cube(1,1), 42); -- cube_c_f8
+  cube   
+---------
+ (1, 42)
+(1 row)
+
+SELECT cube(cube(1,2), 42); -- cube_c_f8
+      cube       
+-----------------
+ (1, 42),(2, 42)
+(1 row)
+
+SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8
+  cube   
+---------
+ (1, 42)
+(1 row)
+
+SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(1, 24)
+(1 row)
+
+SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(2, 42)
+(1 row)
+
+SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(2, 24)
+(1 row)
+
 --
 -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in.
 --
@@ -878,6 +955,24 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
            0.5
 (1 row)
 
+SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube);
+ cube_distance 
+---------------
+             0
+(1 row)
+
+SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube);
+ cube_distance 
+---------------
+           190
+(1 row)
+
+SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube);
+  cube_distance   
+------------------
+ 140.762210837994
+(1 row)
+
 -- Test of cube function (text to cube)
 --
 SELECT cube('(1,1.2)'::text);
@@ -912,6 +1007,18 @@ SELECT cube_dim('(0,0,0)'::cube);
         3
 (1 row)
 
+SELECT cube_dim('(42,42,42),(42,42,42)'::cube);
+ cube_dim 
+----------
+        3
+(1 row)
+
+SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube);
+ cube_dim 
+----------
+        5
+(1 row)
+
 -- Test of cube_ll_coord function (retrieves LL coodinate values)
 --
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1);
@@ -932,6 +1039,42 @@ SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3);
              0
 (1 row)
 
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1);
+ cube_ll_coord 
+---------------
+             1
+(1 row)
+
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2);
+ cube_ll_coord 
+---------------
+             2
+(1 row)
+
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3);
+ cube_ll_coord 
+---------------
+             0
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 1);
+ cube_ll_coord 
+---------------
+            42
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 2);
+ cube_ll_coord 
+---------------
+           137
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 3);
+ cube_ll_coord 
+---------------
+             0
+(1 row)
+
 -- Test of cube_ur_coord function (retrieves UR coodinate values)
 --
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1);
@@ -952,6 +1095,42 @@ SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3);
              0
 (1 row)
 
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1);
+ cube_ur_coord 
+---------------
+             1
+(1 row)
+
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2);
+ cube_ur_coord 
+---------------
+             2
+(1 row)
+
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3);
+ cube_ur_coord 
+---------------
+             0
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 1);
+ cube_ur_coord 
+---------------
+            42
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 2);
+ cube_ur_coord 
+---------------
+           137
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 3);
+ cube_ur_coord 
+---------------
+             0
+(1 row)
+
 -- Test of cube_is_point
 --
 SELECT cube_is_point('(0)'::cube);
@@ -1100,6 +1279,108 @@ SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2);
  (-0.5, 1),(-0.5, 4)
 (1 row)
 
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5);
+ cube_enlarge 
+--------------
+ (42, 0, 0)
+(1 row)
+
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5);
+ cube_enlarge 
+--------------
+ (42, 0, 0)
+(1 row)
+
+-- Test of cube_union (MBR for two cubes)
+--
+SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube);
+      cube_union      
+----------------------
+ (1, 2, 0),(8, 9, 10)
+(1 row)
+
+SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube);
+        cube_union         
+---------------------------
+ (1, 2, 0, 0),(4, 2, 0, 0)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube);
+  cube_union   
+---------------
+ (1, 2),(4, 2)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube);
+ cube_union 
+------------
+ (1, 2)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube);
+ cube_union 
+------------
+ (1, 2, 0)
+(1 row)
+
+-- Test of cube_inter
+--
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects
+   cube_inter    
+-----------------
+ (3, 4),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes
+  cube_inter   
+---------------
+ (3, 4),(6, 5)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection
+    cube_inter     
+-------------------
+ (13, 14),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects
+    cube_inter    
+------------------
+ (3, 14),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection
+ cube_inter 
+------------
+ (10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args
+ cube_inter 
+------------
+ (1, 2, 3)
+(1 row)
+
+SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args
+     cube_inter      
+---------------------
+ (5, 6, 3),(1, 2, 3)
+(1 row)
+
+-- Test of cube_size
+--
+SELECT cube_size('(4,8),(15,16)'::cube);
+ cube_size 
+-----------
+        88
+(1 row)
+
+SELECT cube_size('(42,137)'::cube);
+ cube_size 
+-----------
+         0
+(1 row)
+
 -- Load some example data and build the index
 --
 CREATE TABLE test_cube (c cube);
diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql
index 02e068e..d58974c 100644
--- a/contrib/cube/sql/cube.sql
+++ b/contrib/cube/sql/cube.sql
@@ -112,7 +112,24 @@ SELECT cube('{0,1,2}'::float[], '{3}'::float[]);
 SELECT cube(NULL::float[], '{3}'::float[]);
 SELECT cube('{0,1,2}'::float[]);
 SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]);
+SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]);
 SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]);
+SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]);
+
+--
+-- Test point processing
+--
+SELECT cube('(1,2),(1,2)'); -- cube_in
+SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8
+SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8
+SELECT cube(1.37); -- cube_f8
+SELECT cube(1.37, 1.37); -- cube_f8_f8
+SELECT cube(cube(1,1), 42); -- cube_c_f8
+SELECT cube(cube(1,2), 42); -- cube_c_f8
+SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8
+SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8
+SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8
+SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8
 
 --
 -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in.
@@ -212,6 +229,9 @@ SELECT '(-1,-1),(1,1)'::cube            @> '(-2),(1)'::cube          AS bool;
 --
 SELECT cube_distance('(0)'::cube,'(2,2,2,2)'::cube);
 SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
+SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube);
+SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube);
+SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube);
 
 -- Test of cube function (text to cube)
 --
@@ -223,18 +243,32 @@ SELECT cube(NULL);
 SELECT cube_dim('(0)'::cube);
 SELECT cube_dim('(0,0)'::cube);
 SELECT cube_dim('(0,0,0)'::cube);
+SELECT cube_dim('(42,42,42),(42,42,42)'::cube);
+SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube);
 
 -- Test of cube_ll_coord function (retrieves LL coodinate values)
 --
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1);
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 2);
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3);
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1);
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2);
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3);
+SELECT cube_ll_coord('(42,137)'::cube, 1);
+SELECT cube_ll_coord('(42,137)'::cube, 2);
+SELECT cube_ll_coord('(42,137)'::cube, 3);
 
 -- Test of cube_ur_coord function (retrieves UR coodinate values)
 --
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1);
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 2);
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3);
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1);
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2);
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3);
+SELECT cube_ur_coord('(42,137)'::cube, 1);
+SELECT cube_ur_coord('(42,137)'::cube, 2);
+SELECT cube_ur_coord('(42,137)'::cube, 3);
 
 -- Test of cube_is_point
 --
@@ -265,6 +299,31 @@ SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 1, 2);
 SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 3, 2);
 SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -1, 2);
 SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2);
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5);
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5);
+
+-- Test of cube_union (MBR for two cubes)
+--
+SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube);
+SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube);
+SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube);
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube);
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube);
+
+-- Test of cube_inter
+--
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes
+SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects
+SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection
+SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args
+SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args
+
+-- Test of cube_size
+--
+SELECT cube_size('(4,8),(15,16)'::cube);
+SELECT cube_size('(42,137)'::cube);
 
 -- Load some example data and build the index
 --
#5Robert Haas
robertmhaas@gmail.com
In reply to: Stas Kelvich (#4)
Re: Cube extension point support // GSoC'13

On Tue, Sep 24, 2013 at 9:07 AM, Stas Kelvich <stas.kelvich@gmail.com> wrote:

Hello

There is new version of patch. I have separated ordering operators to different patch (https://commitfest.postgresql.org/action/patch_view?id=1243), fixed formatting issues and implemented backward compatibility with old-style points in cube_is_point() and cube_out().

Also comparing output files I've discovered that this four files is combination of two types of different behavior:

1) SELECT '-1e-700'::cube AS cube;
can be (0) or (-0)

2) Amount of zeros in exponent of floating point, i.e. SELECT '1e27'::cube AS cube;
can be (1e+027) or (1e+27)

On my system (OSX) it is second option in both situations. I've also tested it on FreeBSD 9.0 and Ubuntu 12.04 with the same results. So is there some ideas how can I reproduce such results?

Heikki, are you going to review this further for this CommitFest?

Is there a prerequisite patch that hasn't been committed yet?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Heikki Linnakangas
hlinnakangas@vmware.com
In reply to: Robert Haas (#5)
1 attachment(s)
Re: [HACKERS] Cube extension point support // GSoC'13

On 09.10.2013 21:07, Robert Haas wrote:

On Tue, Sep 24, 2013 at 9:07 AM, Stas Kelvich<stas.kelvich@gmail.com> wrote:

Hello

There is new version of patch. I have separated ordering operators to different patch (https://commitfest.postgresql.org/action/patch_view?id=1243), fixed formatting issues and implemented backward compatibility with old-style points in cube_is_point() and cube_out().

Also comparing output files I've discovered that this four files is combination of two types of different behavior:

1) SELECT '-1e-700'::cube AS cube;
can be (0) or (-0)

2) Amount of zeros in exponent of floating point, i.e. SELECT '1e27'::cube AS cube;
can be (1e+027) or (1e+27)

On my system (OSX) it is second option in both situations. I've also tested it on FreeBSD 9.0 and Ubuntu 12.04 with the same results. So is there some ideas how can I reproduce such results?

Heikki, are you going to review this further for this CommitFest?

Sorry, I didn't realize the ball was in my court.

I went through the patch now, kibitzing over some minor style issues.
Attached is a new version.

This seems good for commit except for two things:

1. The alternative expected output files still need to be updated. Stas
couldn't find a system where some of those file were used. One option is
to simply commit the patch as is, and see if the buildfarm goes red. If
it doesn't, we can simply remove the alternative files - they are not
used on any supported platform. If some animals go red, we'll get the
required diff from the buildfarm output and apply. So this isn't a
show-stopper.

2. I didn't understand this change:

@@ -422,24 +439,14 @@ g_cube_union(PG_FUNCTION_ARGS)
Datum
g_cube_compress(PG_FUNCTION_ARGS)
{
-	PG_RETURN_DATUM(PG_GETARG_DATUM(0));
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	PG_RETURN_POINTER(entry);
}

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);
}

What did the removed code do, and why isn't it needed anymore?

Is there a prerequisite patch that hasn't been committed yet?

No.

- Heikki

Attachments:

points-2.patchtext/x-diff; name=points-2.patchDownload
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index dab0e6e..853acbe 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -144,6 +144,7 @@ bool		g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strate
 ** Auxiliary funxtions
 */
 static double distance_1D(double a1, double a2, double b1, double b2);
+static bool	cube_is_point_internal(NDBOX *cube);
 
 
 /*****************************************************************************
@@ -181,6 +182,7 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
 	int			i;
 	int			dim;
 	int			size;
+	bool		point;
 	double	   *dur,
 			   *dll;
 
@@ -198,16 +200,32 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
 	dur = ARRPTR(ur);
 	dll = ARRPTR(ll);
 
-	size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
+	/* Check if it's a point */
+	point = true;
+	for (i = 0; i < dim; i++)
+	{
+		if (dur[i] != dll[i])
+		{
+			point = false;
+			break;
+		}
+	}
+
+	size = point ? POINT_SIZE(dim) : CUBE_SIZE(dim);
 	result = (NDBOX *) palloc0(size);
 	SET_VARSIZE(result, size);
-	result->dim = dim;
+	SET_DIM(result, dim);
 
 	for (i = 0; i < dim; i++)
-	{
 		result->x[i] = dur[i];
-		result->x[i + dim] = dll[i];
+
+	if (!point)
+	{
+		for (i = 0; i < dim; i++)
+			result->x[i + dim] = dll[i];
 	}
+	else
+		SET_POINT_BIT(result);
 
 	PG_RETURN_NDBOX(result);
 }
@@ -234,16 +252,14 @@ cube_a_f8(PG_FUNCTION_ARGS)
 
 	dur = ARRPTR(ur);
 
-	size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
+	size = POINT_SIZE(dim);
 	result = (NDBOX *) palloc0(size);
 	SET_VARSIZE(result, size);
-	result->dim = dim;
+	SET_DIM(result, dim);
+	SET_POINT_BIT(result);
 
 	for (i = 0; i < dim; i++)
-	{
 		result->x[i] = dur[i];
-		result->x[i + dim] = dur[i];
-	}
 
 	PG_RETURN_NDBOX(result);
 }
@@ -267,14 +283,17 @@ cube_subset(PG_FUNCTION_ARGS)
 	dx = (int32 *) ARR_DATA_PTR(idx);
 
 	dim = ARRNELEMS(idx);
-	size = offsetof(NDBOX, x[0]) +sizeof(double) * 2 * dim;
+	size = IS_POINT(c) ? POINT_SIZE(dim) : CUBE_SIZE(dim);
 	result = (NDBOX *) palloc0(size);
 	SET_VARSIZE(result, size);
-	result->dim = dim;
+	SET_DIM(result, dim);
+
+	if (IS_POINT(c))
+		SET_POINT_BIT(result);
 
 	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,
@@ -282,7 +301,8 @@ cube_subset(PG_FUNCTION_ARGS)
 					 errmsg("Index out of bounds")));
 		}
 		result->x[i] = c->x[dx[i] - 1];
-		result->x[i + dim] = c->x[dx[i] + c->dim - 1];
+		if (!IS_POINT(c))
+			result->x[i + dim] = c->x[dx[i] + DIM(c) - 1];
 	}
 
 	PG_FREE_IF_COPY(c, 0);
@@ -294,8 +314,7 @@ 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,20 +336,18 @@ 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 (!cube_is_point_internal(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, ')');
 	}
@@ -422,24 +439,14 @@ g_cube_union(PG_FUNCTION_ARGS)
 Datum
 g_cube_compress(PG_FUNCTION_ARGS)
 {
-	PG_RETURN_DATUM(PG_GETARG_DATUM(0));
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	PG_RETURN_POINTER(entry);
 }
 
 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);
 }
 
@@ -729,51 +736,60 @@ cube_union_v0(NDBOX *a, NDBOX *b)
 {
 	int			i;
 	NDBOX	   *result;
+	int			dim;
+	int			size;
 
-	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;
-	}
+	/* trivial case */
+	if (a == b)
+		return a;
 
-	/* swap the box pointers if needed */
-	if (a->dim < b->dim)
+	/* swap the arguments if needed, so that 'a' is always larger than 'b' */
+	if (DIM(a) < DIM(b))
 	{
 		NDBOX	   *tmp = b;
 
 		b = a;
 		a = tmp;
 	}
+	dim = DIM(a);
 
-	/*
-	 * 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++)
+	size = CUBE_SIZE(dim);
+	result = palloc0(size);
+	SET_VARSIZE(result, size);
+	SET_DIM(result, dim);
+
+	 /* First compute the union of the dimensions present in both args */
+	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]);
+		result->x[i] = Min(
+			Min(LL_COORD(a, i), UR_COORD(a, i)),
+			Min(LL_COORD(b, i), UR_COORD(b, i))
+		);
+		result->x[i + DIM(a)] = Max(
+			Max(LL_COORD(a, i), UR_COORD(a, i)),
+			Max(LL_COORD(b, i), UR_COORD(b, i))
+		);
 	}
-	for (i = b->dim; i < a->dim; i++)
+	/* continue on the higher dimensions only present in 'a' */
+	for (; i < DIM(a); i++)
 	{
-		result->x[i] = 0;
-		result->x[i + a->dim] = 0;
+		result->x[i] = Min(0,
+			Min(LL_COORD(a, i), UR_COORD(a, i))
+		);
+		result->x[i + dim] = Max(0,
+			Max(LL_COORD(a, i), UR_COORD(a, i))
+		);
 	}
 
-	/* compute the union */
-	for (i = 0; i < a->dim; i++)
+	/*
+	 * Check if the result was in fact a point, and set the flag in the datum
+	 * accordingly. (we don't bother to repalloc it smaller)
+	 */
+	if (cube_is_point_internal(result))
 	{
-		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]);
+		size = POINT_SIZE(dim);
+		SET_VARSIZE(result, size);
+		SET_POINT_BIT(result);
 	}
 
 	return (result);
@@ -802,52 +818,57 @@ cube_inter(PG_FUNCTION_ARGS)
 	NDBOX	   *result;
 	bool		swapped = false;
 	int			i;
+	int			dim;
+	int			size;
 
-	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)
+	/* swap the arguments if needed, so that 'a' is always larger than 'b' */
+	if (DIM(a) < DIM(b))
 	{
 		NDBOX	   *tmp = b;
-
 		b = a;
 		a = tmp;
 		swapped = true;
 	}
+	dim = DIM(a);
 
-	/*
-	 * 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++)
+	size = CUBE_SIZE(dim);
+	result = (NDBOX *) palloc0(size);
+	SET_VARSIZE(result, size);
+	SET_DIM(result, dim);
+
+	 /* First compute intersection of the dimensions present in both args */
+	for (i = 0; i < DIM(b); i++)
 	{
-		result->x[i] = Min(b->x[i], b->x[i + b->dim]);
-		result->x[i + a->dim] = Max(b->x[i], b->x[i + b->dim]);
+		result->x[i] = Max(
+			Min(LL_COORD(a, i), UR_COORD(a, i)),
+			Min(LL_COORD(b, i), UR_COORD(b, i))
+		);
+		result->x[i + DIM(a)] = Min(
+			Max(LL_COORD(a, i), UR_COORD(a, i)),
+			Max(LL_COORD(b, i), UR_COORD(b, i))
+		);
 	}
-	for (i = b->dim; i < a->dim; i++)
+	/* continue on the higher dimemsions only present in 'a' */
+	for (; i < DIM(a); i++)
 	{
-		result->x[i] = 0;
-		result->x[i + a->dim] = 0;
+		result->x[i] = Max(0,
+			Min(LL_COORD(a, i), UR_COORD(a, i))
+		);
+		result->x[i + DIM(a)] = Min(0,
+			Max(LL_COORD(a, i), UR_COORD(a, i))
+		);
 	}
 
-	/* compute the intersection */
-	for (i = 0; i < a->dim; i++)
+	/*
+	 * Check if the result was in fact a point, and set the flag in the datum
+	 * accordingly. (we don't bother to repalloc it smaller)
+	 */
+	if (cube_is_point_internal(result))
 	{
-		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]);
+		size = POINT_SIZE(dim);
+		result = repalloc(result, size);
+		SET_VARSIZE(result, size);
+		SET_POINT_BIT(result);
 	}
 
 	if (swapped)
@@ -873,12 +894,11 @@ 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);
@@ -887,16 +907,15 @@ cube_size(PG_FUNCTION_ARGS)
 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;
 }
@@ -909,43 +928,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 +974,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;
 		}
 
@@ -1098,30 +1117,30 @@ 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);
 	}
 
@@ -1173,7 +1192,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 +1201,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 +1253,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 +1264,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;
 	}
 
@@ -1293,18 +1310,35 @@ distance_1D(double a1, double a2, double b1, double b2)
 Datum
 cube_is_point(PG_FUNCTION_ARGS)
 {
-	NDBOX	   *a = PG_GETARG_NDBOX(0);
-	int			i,
-				j;
+	NDBOX	   *cube = PG_GETARG_NDBOX(0);
+	bool		result;
+
+	result = cube_is_point_internal(cube);
+	PG_FREE_IF_COPY(cube, 0);
+	PG_RETURN_BOOL(result);
+}
+
+static bool
+cube_is_point_internal(NDBOX *cube)
+{
+	int			i;
+
+	if (IS_POINT(cube))
+		return true;
 
-	for (i = 0, j = a->dim; i < a->dim; i++, j++)
+	/*
+	 * Even if the point-flag is not set, all the lower-left coordinates
+	 * might match the upper-right coordinates, so that the value is in
+	 * fact a point. Such values don't arise with current code - the point
+	 * flag is always set if appropriate - but they might be present on-disk
+	 * in clusters upgraded from pre-9.4 versions.
+	 */
+	for (i = 0; i < DIM(cube); i++)
 	{
-		if (a->x[i] != a->x[j])
-			PG_RETURN_BOOL(FALSE);
+		if (LL_COORD(cube, i) != UR_COORD(cube, i))
+			return false;
 	}
-
-	PG_FREE_IF_COPY(a, 0);
-	PG_RETURN_BOOL(TRUE);
+	return true;
 }
 
 /* Return dimensions in use in the data structure */
@@ -1312,8 +1346,7 @@ 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);
 }
@@ -1326,8 +1359,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;
 
@@ -1343,8 +1376,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;
 
@@ -1363,30 +1396,31 @@ cube_enlarge(PG_FUNCTION_ARGS)
 	int			dim = 0;
 	int			size;
 	int			i,
-				j,
-				k;
+				j;
 
 	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;
+	if (DIM(a) > dim)
+		dim = DIM(a);
+
+	size = CUBE_SIZE(dim);
 	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++)
+	SET_DIM(result, dim);
+
+	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;
+			result->x[i] = UR_COORD(a,i) - r;
+			result->x[j] = LL_COORD(a,i) + r;
 		}
 		else
 		{
-			result->x[i] = a->x[i] - r;
-			result->x[j] = a->x[k] + r;
+			result->x[i] = LL_COORD(a,i) - r;
+			result->x[j] = UR_COORD(a,i) + r;
 		}
 		if (result->x[i] > result->x[j])
 		{
@@ -1401,6 +1435,17 @@ cube_enlarge(PG_FUNCTION_ARGS)
 		result->x[j] = r;
 	}
 
+	/*
+	 * Check if the result was in fact a point, and set the flag in the datum
+	 * accordingly. (we don't bother to repalloc it smaller)
+	 */
+	if (cube_is_point_internal(result))
+	{
+		size = POINT_SIZE(dim);
+		SET_VARSIZE(result, size);
+		SET_POINT_BIT(result);
+	}
+
 	PG_FREE_IF_COPY(a, 0);
 	PG_RETURN_NDBOX(result);
 }
@@ -1413,11 +1458,12 @@ cube_f8(PG_FUNCTION_ARGS)
 	NDBOX	   *result;
 	int			size;
 
-	size = offsetof(NDBOX, x[0]) +sizeof(double) * 2;
+	size = POINT_SIZE(1);
 	result = (NDBOX *) palloc0(size);
 	SET_VARSIZE(result, size);
-	result->dim = 1;
-	result->x[0] = result->x[1] = x;
+	SET_DIM(result, 1);
+	SET_POINT_BIT(result);
+	result->x[0] = x;
 
 	PG_RETURN_NDBOX(result);
 }
@@ -1431,12 +1477,24 @@ cube_f8_f8(PG_FUNCTION_ARGS)
 	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;
+	if (x0 == x1)
+	{
+		size = POINT_SIZE(1);
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, 1);
+		SET_POINT_BIT(result);
+		result->x[0] = x0;
+	}
+	else
+	{
+		size = CUBE_SIZE(1);
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, 1);
+		result->x[0] = x0;
+		result->x[1] = x1;
+	}
 
 	PG_RETURN_NDBOX(result);
 }
@@ -1446,25 +1504,39 @@ cube_f8_f8(PG_FUNCTION_ARGS)
 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;
 	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];
+		size = POINT_SIZE((DIM(cube) + 1));
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, DIM(cube) + 1);
+		SET_POINT_BIT(result);
+		for (i = 0; i < DIM(cube); i++)
+			result->x[i] = cube->x[i];
+		result->x[DIM(result) - 1] = x;
+	}
+	else
+	{
+		size = CUBE_SIZE((DIM(cube) + 1));
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, DIM(cube) + 1);
+		for (i = 0; i < DIM(cube); i++)
+		{
+			result->x[i] = cube->x[i];
+			result->x[DIM(result) + i] = cube->x[DIM(cube) + i];
+		}
+		result->x[DIM(result) - 1] = x;
+		result->x[2*DIM(result) - 1] = x;
 	}
-	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);
 }
 
@@ -1472,25 +1544,38 @@ cube_c_f8(PG_FUNCTION_ARGS)
 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)){
+		size = POINT_SIZE((DIM(cube) + 1));
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, DIM(cube) + 1);
+		SET_POINT_BIT(result);
+		for (i = 0; i < DIM(cube); i++)
+			result->x[i] = cube->x[i];
+		result->x[DIM(result) - 1] = x1;
+	}
+	else
 	{
-		result->x[i] = c->x[i];
-		result->x[result->dim + i] = c->x[c->dim + i];
+		size = CUBE_SIZE((DIM(cube) + 1));
+		result = (NDBOX *) palloc0(size);
+		SET_VARSIZE(result, size);
+		SET_DIM(result, DIM(cube) + 1);
+		for (i = 0; i < DIM(cube); i++)
+		{
+			result->x[i] = LL_COORD(cube, i);
+			result->x[DIM(result) + i] = UR_COORD(cube, i);
+		}
+		result->x[DIM(result) - 1] = x1;
+		result->x[2 * DIM(result) - 1] = x2;
 	}
-	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..7903c8b 100644
--- a/contrib/cube/cubedata.h
+++ b/contrib/cube/cubedata.h
@@ -4,11 +4,36 @@
 
 typedef struct NDBOX
 {
-	int32		vl_len_;		/* varlena header (do not touch directly!) */
-	unsigned int dim;
+	/* varlena header (do not touch directly!) */
+	int32		vl_len_;
+
+	/*----------
+	 * Header contains info about NDBOX. For binary compatibility with old
+	 * versions, it is defined as "unsigned int".
+	 *
+	 * Following information is stored:
+	 *
+	 *  bits 0-7  : number of cube dimensions;
+	 *  bits 8-30 : not used;
+	 *  bit  31   : point flag. If set, then NDBOX stores
+	 *				n dimensions instead of 2*n;
+	 *----------
+	 */
+	unsigned int header;
 	double		x[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)
+
+#define IS_POINT(cube)		( (cube)->header >> 31 )
+#define SET_POINT_BIT(cube)	( (cube)->header |= 0x80000000 )
+#define DIM(cube)			( (cube)->header & 0x7fffffff )
+#define SET_DIM(cube, _dim)	( (cube)->header = _dim )
+
+#define LL_COORD(cube, i) ( (cube)->x[i] )
+#define UR_COORD(cube, i) ( IS_POINT(cube) ? (cube)->x[i] : (cube)->x[i + DIM(cube)] )
+
+#define POINT_SIZE(_dim) (offsetof(NDBOX, x[0]) + sizeof(double)*(_dim))
+#define CUBE_SIZE(_dim) (offsetof(NDBOX, x[0]) + sizeof(double)*(_dim)*2)
diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y
index d7205b8..0baee8e 100644
--- a/contrib/cube/cubeparse.y
+++ b/contrib/cube/cubeparse.y
@@ -175,11 +175,12 @@ write_box(unsigned int dim, char *str1, char *str2)
 	NDBOX	   *bp;
 	char	   *s;
 	int			i;
-	int			size = offsetof(NDBOX, x[0]) + sizeof(double) * dim * 2;
+	int			size = CUBE_SIZE(dim);
+	bool		point = true;
 
 	bp = palloc0(size);
 	SET_VARSIZE(bp, size);
-	bp->dim = dim;
+	SET_DIM(bp, dim);
 
 	s = str1;
 	bp->x[i=0] = strtod(s, NULL);
@@ -191,10 +192,28 @@ write_box(unsigned int dim, char *str1, char *str2)
 
 	s = str2;
 	bp->x[i=dim] = strtod(s, NULL);
+	if (bp->x[dim] != bp->x[0])
+		point = false;
 	while ((s = strchr(s, ',')) != NULL)
 	{
 		s++; i++;
 		bp->x[i] = strtod(s, NULL);
+		if (bp->x[i] != bp->x[i-dim])
+			point = false;
+	}
+
+	if (point)
+	{
+		/*
+		 * The value turned out to be a point, ie. all the upper-right
+		 * coordinates were equal to the lower-left coordinates. Resize the
+		 * the cube we constructed. Note: we don't bother to repalloc() it
+		 * smaller, it's unlikely that the tiny amount of memory free'd that
+		 * way would be useful.
+		 */
+		size = POINT_SIZE(dim);
+		SET_VARSIZE(bp, size);
+		SET_POINT_BIT(bp);
 	}
 
 	return(bp);
@@ -203,31 +222,29 @@ write_box(unsigned int dim, char *str1, char *str2)
 static NDBOX *
 write_point_as_box(char *str, int dim)
 {
-  NDBOX		   *bp;
-  int			i,
+	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);
+	double		x;
+	char		*s = str;
+
+	size = POINT_SIZE(dim);
+	bp = palloc0(size);
+	SET_VARSIZE(bp, size);
+	SET_DIM(bp, dim);
+	SET_POINT_BIT(bp);
+
+	i = 0;
+	x = strtod(s, NULL);
+	bp->x[0] = x;
+	while ((s = strchr(s, ',')) != NULL)
+	{
+		s++; i++;
+		x = strtod(s, NULL);
+		bp->x[i] = x;
+	}
+
+	return(bp);
 }
 
 #include "cubescan.c"
diff --git a/contrib/cube/expected/cube_1.out b/contrib/cube/expected/cube_1.out
index fefebf5..c07d61d 100644
--- a/contrib/cube/expected/cube_1.out
+++ b/contrib/cube/expected/cube_1.out
@@ -473,8 +473,85 @@ SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]);
  (5, 3, 1, 1),(8, 7, 6, 6)
 (1 row)
 
+SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]);
+ cube_subset  
+--------------
+ (5, 3, 1, 1)
+(1 row)
+
 SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]);
 ERROR:  Index out of bounds
+SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]);
+ERROR:  Index out of bounds
+--
+-- Test point processing
+--
+SELECT cube('(1,2),(1,2)'); -- cube_in
+  cube  
+--------
+ (1, 2)
+(1 row)
+
+SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8
+   cube    
+-----------
+ (0, 1, 2)
+(1 row)
+
+SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8
+     cube     
+--------------
+ (5, 6, 7, 8)
+(1 row)
+
+SELECT cube(1.37); -- cube_f8
+  cube  
+--------
+ (1.37)
+(1 row)
+
+SELECT cube(1.37, 1.37); -- cube_f8_f8
+  cube  
+--------
+ (1.37)
+(1 row)
+
+SELECT cube(cube(1,1), 42); -- cube_c_f8
+  cube   
+---------
+ (1, 42)
+(1 row)
+
+SELECT cube(cube(1,2), 42); -- cube_c_f8
+      cube       
+-----------------
+ (1, 42),(2, 42)
+(1 row)
+
+SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8
+  cube   
+---------
+ (1, 42)
+(1 row)
+
+SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(1, 24)
+(1 row)
+
+SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(2, 42)
+(1 row)
+
+SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8
+      cube       
+-----------------
+ (1, 42),(2, 24)
+(1 row)
+
 --
 -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in.
 --
@@ -878,6 +955,24 @@ SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
            0.5
 (1 row)
 
+SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube);
+ cube_distance 
+---------------
+             0
+(1 row)
+
+SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube);
+ cube_distance 
+---------------
+           190
+(1 row)
+
+SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube);
+  cube_distance   
+------------------
+ 140.762210837994
+(1 row)
+
 -- Test of cube function (text to cube)
 --
 SELECT cube('(1,1.2)'::text);
@@ -912,6 +1007,18 @@ SELECT cube_dim('(0,0,0)'::cube);
         3
 (1 row)
 
+SELECT cube_dim('(42,42,42),(42,42,42)'::cube);
+ cube_dim 
+----------
+        3
+(1 row)
+
+SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube);
+ cube_dim 
+----------
+        5
+(1 row)
+
 -- Test of cube_ll_coord function (retrieves LL coodinate values)
 --
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1);
@@ -932,6 +1039,42 @@ SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3);
              0
 (1 row)
 
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1);
+ cube_ll_coord 
+---------------
+             1
+(1 row)
+
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2);
+ cube_ll_coord 
+---------------
+             2
+(1 row)
+
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3);
+ cube_ll_coord 
+---------------
+             0
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 1);
+ cube_ll_coord 
+---------------
+            42
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 2);
+ cube_ll_coord 
+---------------
+           137
+(1 row)
+
+SELECT cube_ll_coord('(42,137)'::cube, 3);
+ cube_ll_coord 
+---------------
+             0
+(1 row)
+
 -- Test of cube_ur_coord function (retrieves UR coodinate values)
 --
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1);
@@ -952,6 +1095,42 @@ SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3);
              0
 (1 row)
 
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1);
+ cube_ur_coord 
+---------------
+             1
+(1 row)
+
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2);
+ cube_ur_coord 
+---------------
+             2
+(1 row)
+
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3);
+ cube_ur_coord 
+---------------
+             0
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 1);
+ cube_ur_coord 
+---------------
+            42
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 2);
+ cube_ur_coord 
+---------------
+           137
+(1 row)
+
+SELECT cube_ur_coord('(42,137)'::cube, 3);
+ cube_ur_coord 
+---------------
+             0
+(1 row)
+
 -- Test of cube_is_point
 --
 SELECT cube_is_point('(0)'::cube);
@@ -1100,6 +1279,108 @@ SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2);
  (-0.5, 1),(-0.5, 4)
 (1 row)
 
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5);
+ cube_enlarge 
+--------------
+ (42, 0, 0)
+(1 row)
+
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5);
+ cube_enlarge 
+--------------
+ (42, 0, 0)
+(1 row)
+
+-- Test of cube_union (MBR for two cubes)
+--
+SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube);
+      cube_union      
+----------------------
+ (1, 2, 0),(8, 9, 10)
+(1 row)
+
+SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube);
+        cube_union         
+---------------------------
+ (1, 2, 0, 0),(4, 2, 0, 0)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube);
+  cube_union   
+---------------
+ (1, 2),(4, 2)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube);
+ cube_union 
+------------
+ (1, 2)
+(1 row)
+
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube);
+ cube_union 
+------------
+ (1, 2, 0)
+(1 row)
+
+-- Test of cube_inter
+--
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects
+   cube_inter    
+-----------------
+ (3, 4),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes
+  cube_inter   
+---------------
+ (3, 4),(6, 5)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection
+    cube_inter     
+-------------------
+ (13, 14),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects
+    cube_inter    
+------------------
+ (3, 14),(10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection
+ cube_inter 
+------------
+ (10, 11)
+(1 row)
+
+SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args
+ cube_inter 
+------------
+ (1, 2, 3)
+(1 row)
+
+SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args
+     cube_inter      
+---------------------
+ (5, 6, 3),(1, 2, 3)
+(1 row)
+
+-- Test of cube_size
+--
+SELECT cube_size('(4,8),(15,16)'::cube);
+ cube_size 
+-----------
+        88
+(1 row)
+
+SELECT cube_size('(42,137)'::cube);
+ cube_size 
+-----------
+         0
+(1 row)
+
 -- Load some example data and build the index
 --
 CREATE TABLE test_cube (c cube);
diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql
index 02e068e..d58974c 100644
--- a/contrib/cube/sql/cube.sql
+++ b/contrib/cube/sql/cube.sql
@@ -112,7 +112,24 @@ SELECT cube('{0,1,2}'::float[], '{3}'::float[]);
 SELECT cube(NULL::float[], '{3}'::float[]);
 SELECT cube('{0,1,2}'::float[]);
 SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]);
+SELECT cube_subset(cube('(1,3,5),(1,3,5)'), ARRAY[3,2,1,1]);
 SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]);
+SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]);
+
+--
+-- Test point processing
+--
+SELECT cube('(1,2),(1,2)'); -- cube_in
+SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8
+SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8
+SELECT cube(1.37); -- cube_f8
+SELECT cube(1.37, 1.37); -- cube_f8_f8
+SELECT cube(cube(1,1), 42); -- cube_c_f8
+SELECT cube(cube(1,2), 42); -- cube_c_f8
+SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8
+SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8
+SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8
+SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8
 
 --
 -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in.
@@ -212,6 +229,9 @@ SELECT '(-1,-1),(1,1)'::cube            @> '(-2),(1)'::cube          AS bool;
 --
 SELECT cube_distance('(0)'::cube,'(2,2,2,2)'::cube);
 SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube);
+SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube);
+SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube);
+SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube);
 
 -- Test of cube function (text to cube)
 --
@@ -223,18 +243,32 @@ SELECT cube(NULL);
 SELECT cube_dim('(0)'::cube);
 SELECT cube_dim('(0,0)'::cube);
 SELECT cube_dim('(0,0,0)'::cube);
+SELECT cube_dim('(42,42,42),(42,42,42)'::cube);
+SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube);
 
 -- Test of cube_ll_coord function (retrieves LL coodinate values)
 --
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1);
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 2);
 SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3);
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1);
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2);
+SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3);
+SELECT cube_ll_coord('(42,137)'::cube, 1);
+SELECT cube_ll_coord('(42,137)'::cube, 2);
+SELECT cube_ll_coord('(42,137)'::cube, 3);
 
 -- Test of cube_ur_coord function (retrieves UR coodinate values)
 --
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1);
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 2);
 SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3);
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1);
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2);
+SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3);
+SELECT cube_ur_coord('(42,137)'::cube, 1);
+SELECT cube_ur_coord('(42,137)'::cube, 2);
+SELECT cube_ur_coord('(42,137)'::cube, 3);
 
 -- Test of cube_is_point
 --
@@ -265,6 +299,31 @@ SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 1, 2);
 SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 3, 2);
 SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -1, 2);
 SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2);
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5);
+SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5);
+
+-- Test of cube_union (MBR for two cubes)
+--
+SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube);
+SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube);
+SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube);
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube);
+SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube);
+
+-- Test of cube_inter
+--
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes
+SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection
+SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects
+SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection
+SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args
+SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args
+
+-- Test of cube_size
+--
+SELECT cube_size('(4,8),(15,16)'::cube);
+SELECT cube_size('(42,137)'::cube);
 
 -- Load some example data and build the index
 --
#7Alexander Korotkov
aekorotkov@gmail.com
In reply to: Heikki Linnakangas (#6)
Re: Cube extension point support // GSoC'13

On Fri, Oct 11, 2013 at 5:56 PM, Heikki Linnakangas <hlinnakangas@vmware.com

wrote:

2. I didn't understand this change:

@@ -422,24 +439,14 @@ g_cube_union(PG_FUNCTION_ARGS)

Datum
g_cube_compress(PG_FUNCTION_**ARGS)
{
-       PG_RETURN_DATUM(PG_GETARG_**DATUM(0));
+       GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+       PG_RETURN_POINTER(entry);
}

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);
}

What did the removed code do, and why isn't it needed anymore?

I don't understand this place even more generally. What decompress function
do is to detoast key and return new gist entry with it if needed. But can
GiST key ever be toasted? My experiments show that answer is no, it can't.
When too long key is passed then GiST falls during inserting key into page.
And I didn't find any code doing GiST key toast in git.
However taking care about key toast is sequentially repeated in GiST
related code. For example, in contrib/intarray/_int.h

#define SIGLENINT 63 /* >122 => key will *toast*, so very slow!!! */

Any ideas?

------
With best regards,
Alexander Korotkov.

#8Heikki Linnakangas
hlinnakangas@vmware.com
In reply to: Alexander Korotkov (#7)
Re: [HACKERS] Cube extension point support // GSoC'13

On 11.10.2013 17:39, Alexander Korotkov wrote:

On Fri, Oct 11, 2013 at 5:56 PM, Heikki Linnakangas<hlinnakangas@vmware.com

wrote:

2. I didn't understand this change:

@@ -422,24 +439,14 @@ g_cube_union(PG_FUNCTION_ARGS)

Datum
g_cube_compress(PG_FUNCTION_**ARGS)
{
-       PG_RETURN_DATUM(PG_GETARG_**DATUM(0));
+       GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+       PG_RETURN_POINTER(entry);
}

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);
}

What did the removed code do, and why isn't it needed anymore?

I don't understand this place even more generally. What decompress function
do is to detoast key and return new gist entry with it if needed. But can
GiST key ever be toasted? My experiments show that answer is no, it can't.
When too long key is passed then GiST falls during inserting key into page.
And I didn't find any code doing GiST key toast in git.

I guess it can't happen. Or is it possible that a toasted value that
came from disk will be passed to these functions, without detoasting
them somewhere along the way? Not sure.

In any case, I've committed this patch now. I left out the changes to
compress and decompress functions, as that's unrelated to the patch at
hand. I ran the regression test on a Windows VM, and updated the
expected output file that the Windows build used. That leaves two
alternative expected output files unmodified - the buildfarm will tell
us whether they're still needed.

Thanks and congrats on your first committed patch, Stas! :-)

- Heikki

--
Sent via pgsql-students mailing list (pgsql-students@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-students

#9Alexander Korotkov
aekorotkov@gmail.com
In reply to: Heikki Linnakangas (#8)
Re: [HACKERS] Cube extension point support // GSoC'13

On Mon, Oct 21, 2013 at 11:06 PM, Heikki Linnakangas <
hlinnakangas@vmware.com> wrote:

On 11.10.2013 17:39, Alexander Korotkov wrote:

On Fri, Oct 11, 2013 at 5:56 PM, Heikki Linnakangas<hlinnakangas@**
vmware.com <hlinnakangas@vmware.com>

wrote:

2. I didn't understand this change:

@@ -422,24 +439,14 @@ g_cube_union(PG_FUNCTION_ARGS)

Datum
g_cube_compress(PG_FUNCTION_****ARGS)
{
- PG_RETURN_DATUM(PG_GETARG_****DATUM(0));

+       GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+       PG_RETURN_POINTER(entry);
}

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);
}

What did the removed code do, and why isn't it needed anymore?

I don't understand this place even more generally. What decompress
function
do is to detoast key and return new gist entry with it if needed. But can
GiST key ever be toasted? My experiments show that answer is no, it can't.
When too long key is passed then GiST falls during inserting key into
page.
And I didn't find any code doing GiST key toast in git.

I guess it can't happen. Or is it possible that a toasted value that came
from disk will be passed to these functions, without detoasting them
somewhere along the way? Not sure.

I will ask Teodor about it. When situation will be completely clear we
should cleanup confusing comments.
Also, too long GiST key shouldn't cause GiST to fall in its internals. We
should add check somewhere before.

In any case, I've committed this patch now. I left out the changes to

compress and decompress functions, as that's unrelated to the patch at
hand. I ran the regression test on a Windows VM, and updated the expected
output file that the Windows build used. That leaves two alternative
expected output files unmodified - the buildfarm will tell us whether
they're still needed.

Thanks and congrats on your first committed patch, Stas! :-)

Stas, congratulations from me too! Now, it's time to rebase another patches
against head. :)

------
With best regards,
Alexander Korotkov.

#10Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alexander Korotkov (#9)
Re: [HACKERS] Cube extension point support // GSoC'13

Alexander Korotkov <aekorotkov@gmail.com> writes:

On Mon, Oct 21, 2013 at 11:06 PM, Heikki Linnakangas <
hlinnakangas@vmware.com> wrote:

I guess it can't happen. Or is it possible that a toasted value that came
from disk will be passed to these functions, without detoasting them
somewhere along the way? Not sure.

I will ask Teodor about it. When situation will be completely clear we
should cleanup confusing comments.

I believe the reason GIST has compress/decompress functions is not for
TOAST (they predate that, if memory serves), but to allow the on-disk
representation of an index entry to be different from the data type's
normal representation in other ways --- think lossy storage in particular.

It's possible that the code in cube's decompress/decompress functions is
unnecessary because cube doesn't actually do any such compression; the
code might've been copy-pasted from somewhere else without adequate
thought about whether it was useful for cubes. I'd want to see some
discussion about why it's okay to change it before we do so, though.
In any case it seems separate from the claimed purpose of this patch
and thus better done in a different patch.

regards, tom lane

--
Sent via pgsql-students mailing list (pgsql-students@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-students

#11Dimitri Fontaine
dimitri@2ndQuadrant.fr
In reply to: Tom Lane (#10)
Re: [HACKERS] Cube extension point support // GSoC'13

Tom Lane <tgl@sss.pgh.pa.us> writes:

I believe the reason GIST has compress/decompress functions is not for
TOAST (they predate that, if memory serves), but to allow the on-disk
representation of an index entry to be different from the data type's
normal representation in other ways --- think lossy storage in particular.

My understanding of the use case for those functions is to do with
storing a different data type in the index upper nodes and in the index
leafs. It should be possible to do that in a non-lossy way, so that you
would implement compress/decompress and not declare the RECHECK bits.

Then again I'm talking from 8.3 era memories of when I tried to
understand GiST enough to code the prefix extension.

Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

--
Sent via pgsql-students mailing list (pgsql-students@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-students

#12Alexander Korotkov
aekorotkov@gmail.com
In reply to: Dimitri Fontaine (#11)
Re: [HACKERS] Cube extension point support // GSoC'13

On Tue, Oct 22, 2013 at 2:00 AM, Dimitri Fontaine <dimitri@2ndquadrant.fr>wrote:

Tom Lane <tgl@sss.pgh.pa.us> writes:

I believe the reason GIST has compress/decompress functions is not for
TOAST (they predate that, if memory serves), but to allow the on-disk
representation of an index entry to be different from the data type's
normal representation in other ways --- think lossy storage in

particular.

My understanding of the use case for those functions is to do with
storing a different data type in the index upper nodes and in the index
leafs. It should be possible to do that in a non-lossy way, so that you
would implement compress/decompress and not declare the RECHECK bits.

Then again I'm talking from 8.3 era memories of when I tried to
understand GiST enough to code the prefix extension.

Actually, I mean purpose of this particular decompress function
implementation, not compress/decompress in general. I understand that in
general compress/decompress can do useful job.

------
With best regards,
Alexander Korotkov.