From 796de9c1ed3d2cfc074c3cdbe9a12c698cd53336 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Tue, 25 Jul 2006 23:23:45 +0000
Subject: [PATCH] /contrib/cube improvements:

Update the calling convention for all external facing functions. By
external facing, I mean all functions that are directly referenced in
cube.sql. Prior to my update, all functions used the older V0 calling
convention. They now use V1.

New Functions:

cube(float[]), which makes a zero volume cube from a float array

cube(float[], float[]), which allows the user to create a cube from
two float arrays; one for the upper right and one for the lower left
coordinate.

cube_subset(cube, int4[]), to allow you to reorder or choose a subset of
dimensions from a cube, using index values specified in the array.

Joshua Reich
---
 contrib/cube/CHANGES            |  24 ++
 contrib/cube/README.cube        |  24 ++
 contrib/cube/cube.c             | 726 ++++++++++++++++++++++++--------
 contrib/cube/cube.sql.in        |  13 +
 contrib/cube/expected/cube.out  |  51 ++-
 contrib/cube/sql/cube.sql       |  14 +-
 contrib/cube/uninstall_cube.sql |   6 +
 7 files changed, 662 insertions(+), 196 deletions(-)

diff --git a/contrib/cube/CHANGES b/contrib/cube/CHANGES
index a867e4efe36..5e5e7c8d4a9 100644
--- a/contrib/cube/CHANGES
+++ b/contrib/cube/CHANGES
@@ -1,4 +1,28 @@
+********************************************************************************
+Changes that were made in July 2006 by Joshua Reich I.
+********************************************************************************
+
+Code Cleanup:
+
+Update the calling convention for all external facing functions. By external
+facing, I mean all functions that are directly referenced in cube.sql. Prior
+to my update, all functions used the older V0 calling convention. They now 
+use V1.
+
+New Functions: 
+
+cube(float[]), which makes a zero volume cube from a float array
+
+cube(float[], float[]), which allows the user to create a cube from
+two float arrays; one for the upper right and one for the lower left
+coordinate.
+
+cube_subset(cube, int4[]), to allow you to reorder or choose a subset of
+dimensions from a cube, using index values specified in the array.
+
+********************************************************************************
 Changes that were made in August/September 2002 by Bruno Wolff III.
+********************************************************************************
 
 Note that this was based on a 7.3 development version and changes may not
 directly work with earlier versions.
diff --git a/contrib/cube/README.cube b/contrib/cube/README.cube
index 9617009eb2c..bc28c6ec313 100644
--- a/contrib/cube/README.cube
+++ b/contrib/cube/README.cube
@@ -244,6 +244,16 @@ cube(float8, float8) returns cube
   This makes a one dimensional cube.
   cube(1,2) == '(1),(2)'
 
+cube(float8[]) returns cube
+  This makes a zero-volume cube using the coordinates defined by the
+  array.
+  cube(ARRAY[1,2]) == '(1,2)'
+
+cube(float8[], float8[]) returns cube
+  This makes a cube, with upper right and lower left coordinates as
+  defined by the 2 float arrays. Arrays must be of the same length.
+  cube('{1,2}'::float[], '{3,4}'::float[]) == '(1,2),(3,4)'
+
 cube(cube, float8) returns cube
   This builds a new cube by adding a dimension on to an existing cube with
   the same values for both parts of the new coordinate. This is useful for
@@ -267,6 +277,13 @@ cube_ur_coord(cube, int) returns double
   cube_ur_coord returns the nth coordinate value for the upper right corner
   of a cube. This is useful for doing coordinate transformations.
 
+cube_subset(cube, int[]) returns cube
+  Builds a new cube from an existing cube, using a list of dimension indexes
+  from an array. Can be used to find both the ll and ur coordinate of single
+  dimenion, e.g.: cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[2]) = '(3),(7)'
+  Or can be used to drop dimensions, or reorder them as desired, e.g.:
+  cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]) = '(5, 3, 1, 1),(8, 7, 6, 6)'
+
 cube_is_point(cube) returns bool
   cube_is_point returns true if a cube is also a point. This is true when the
   two defining corners are the same.
@@ -327,3 +344,10 @@ in August/September of 2002.
 
 These include changing the precision from single precision to double
 precision and adding some new functions.
+
+------------------------------------------------------------------------
+
+Additional updates were made by Joshua Reich <josh@root.net> in July 2006.
+
+These include cube(float8[], float8[]) and cleaning up the code to use 
+the V1 call protocol instead of the deprecated V0 form.
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 87ca2db7688..7495ea8ce4b 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -1,5 +1,5 @@
 /******************************************************************************
-  $PostgreSQL: pgsql/contrib/cube/cube.c,v 1.26 2006/06/28 11:59:59 teodor Exp $
+  $PostgreSQL: pgsql/contrib/cube/cube.c,v 1.27 2006/07/25 23:23:44 momjian Exp $
 
   This file contains routines that can be bound to a Postgres backend and
   called by the backend in the process of processing queries.  The calling
@@ -28,63 +28,113 @@ extern void cube_scanner_finish(void);
 /*
 ** Input/Output routines
 */
-NDBOX	   *cube_in(char *str);
-NDBOX	   *cube(text *str);
-char	   *cube_out(NDBOX * cube);
-NDBOX	   *cube_f8(double *);
-NDBOX	   *cube_f8_f8(double *, double *);
-NDBOX	   *cube_c_f8(NDBOX *, double *);
-NDBOX	   *cube_c_f8_f8(NDBOX *, double *, double *);
-int4		cube_dim(NDBOX * a);
-double	   *cube_ll_coord(NDBOX * a, int4 n);
-double	   *cube_ur_coord(NDBOX * a, int4 n);
-
+PG_FUNCTION_INFO_V1(cube_in);
+PG_FUNCTION_INFO_V1(cube);
+PG_FUNCTION_INFO_V1(cube_a_f8_f8);
+PG_FUNCTION_INFO_V1(cube_a_f8);
+PG_FUNCTION_INFO_V1(cube_out);
+PG_FUNCTION_INFO_V1(cube_f8);
+PG_FUNCTION_INFO_V1(cube_f8_f8);
+PG_FUNCTION_INFO_V1(cube_c_f8);
+PG_FUNCTION_INFO_V1(cube_c_f8_f8);
+PG_FUNCTION_INFO_V1(cube_dim);
+PG_FUNCTION_INFO_V1(cube_ll_coord);
+PG_FUNCTION_INFO_V1(cube_ur_coord);
+PG_FUNCTION_INFO_V1(cube_subset);
+
+Datum		cube_in(PG_FUNCTION_ARGS);
+Datum		cube(PG_FUNCTION_ARGS);
+Datum		cube_a_f8_f8(PG_FUNCTION_ARGS);
+Datum		cube_a_f8(PG_FUNCTION_ARGS);
+Datum		cube_out(PG_FUNCTION_ARGS);
+Datum		cube_f8(PG_FUNCTION_ARGS);
+Datum		cube_f8_f8(PG_FUNCTION_ARGS);
+Datum		cube_c_f8(PG_FUNCTION_ARGS);
+Datum		cube_c_f8_f8(PG_FUNCTION_ARGS);
+Datum		cube_dim(PG_FUNCTION_ARGS);
+Datum		cube_ll_coord(PG_FUNCTION_ARGS);
+Datum		cube_ur_coord(PG_FUNCTION_ARGS);
+Datum		cube_subset(PG_FUNCTION_ARGS);
 
 /*
 ** GiST support methods
 */
-bool		g_cube_consistent(GISTENTRY *entry, NDBOX * query, StrategyNumber strategy);
-GISTENTRY  *g_cube_compress(GISTENTRY *entry);
-GISTENTRY  *g_cube_decompress(GISTENTRY *entry);
-float	   *g_cube_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result);
-GIST_SPLITVEC *g_cube_picksplit(GistEntryVector *entryvec, GIST_SPLITVEC *v);
-bool		g_cube_leaf_consistent(NDBOX * key, NDBOX * query, StrategyNumber strategy);
-bool		g_cube_internal_consistent(NDBOX * key, NDBOX * query, StrategyNumber strategy);
-NDBOX	   *g_cube_union(GistEntryVector *entryvec, int *sizep);
-NDBOX	   *g_cube_binary_union(NDBOX * r1, NDBOX * r2, int *sizep);
-bool	   *g_cube_same(NDBOX * b1, NDBOX * b2, bool *result);
+
+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);
+PG_FUNCTION_INFO_V1(g_cube_picksplit);
+PG_FUNCTION_INFO_V1(g_cube_union);
+PG_FUNCTION_INFO_V1(g_cube_same);
+
+Datum		g_cube_consistent(PG_FUNCTION_ARGS);
+Datum		g_cube_compress(PG_FUNCTION_ARGS);
+Datum		g_cube_decompress(PG_FUNCTION_ARGS);
+Datum		g_cube_penalty(PG_FUNCTION_ARGS);
+Datum		g_cube_picksplit(PG_FUNCTION_ARGS);
+Datum		g_cube_union(PG_FUNCTION_ARGS);
+Datum		g_cube_same(PG_FUNCTION_ARGS);
 
 /*
 ** B-tree support functions
 */
-bool		cube_eq(NDBOX * a, NDBOX * b);
-bool		cube_ne(NDBOX * a, NDBOX * b);
-bool		cube_lt(NDBOX * a, NDBOX * b);
-bool		cube_gt(NDBOX * a, NDBOX * b);
-bool		cube_le(NDBOX * a, NDBOX * b);
-bool		cube_ge(NDBOX * a, NDBOX * b);
-int32		cube_cmp(NDBOX * a, NDBOX * b);
+PG_FUNCTION_INFO_V1(cube_eq);
+PG_FUNCTION_INFO_V1(cube_ne);
+PG_FUNCTION_INFO_V1(cube_lt);
+PG_FUNCTION_INFO_V1(cube_gt);
+PG_FUNCTION_INFO_V1(cube_le);
+PG_FUNCTION_INFO_V1(cube_ge);
+PG_FUNCTION_INFO_V1(cube_cmp);
+
+Datum		cube_eq(PG_FUNCTION_ARGS);
+Datum		cube_ne(PG_FUNCTION_ARGS);
+Datum		cube_lt(PG_FUNCTION_ARGS);
+Datum		cube_gt(PG_FUNCTION_ARGS);
+Datum		cube_le(PG_FUNCTION_ARGS);
+Datum		cube_ge(PG_FUNCTION_ARGS);
+Datum		cube_cmp(PG_FUNCTION_ARGS);
 
 /*
 ** R-tree support functions
 */
-bool		cube_contains(NDBOX * a, NDBOX * b);
-bool		cube_contained(NDBOX * a, NDBOX * b);
-bool		cube_overlap(NDBOX * a, NDBOX * b);
-NDBOX	   *cube_union(NDBOX * a, NDBOX * b);
-NDBOX	   *cube_inter(NDBOX * a, NDBOX * b);
-double	   *cube_size(NDBOX * a);
-void		rt_cube_size(NDBOX * a, double *sz);
+
+PG_FUNCTION_INFO_V1(cube_contains);
+PG_FUNCTION_INFO_V1(cube_contained);
+PG_FUNCTION_INFO_V1(cube_overlap);
+PG_FUNCTION_INFO_V1(cube_union);
+PG_FUNCTION_INFO_V1(cube_inter);
+PG_FUNCTION_INFO_V1(cube_size);
+
+Datum		cube_contains(PG_FUNCTION_ARGS);
+Datum		cube_contained(PG_FUNCTION_ARGS);
+Datum		cube_overlap(PG_FUNCTION_ARGS);
+Datum		cube_union(PG_FUNCTION_ARGS);
+Datum		cube_inter(PG_FUNCTION_ARGS);
+Datum		cube_size(PG_FUNCTION_ARGS);
 
 /*
 ** miscellaneous
 */
-bool		cube_lt(NDBOX * a, NDBOX * b);
-bool		cube_gt(NDBOX * a, NDBOX * b);
-double	   *cube_distance(NDBOX * a, NDBOX * b);
-bool		cube_is_point(NDBOX * a);
-NDBOX	   *cube_enlarge(NDBOX * a, double *r, int4 n);
+PG_FUNCTION_INFO_V1(cube_distance);
+PG_FUNCTION_INFO_V1(cube_is_point);
+PG_FUNCTION_INFO_V1(cube_enlarge);
+
+Datum		cube_distance(PG_FUNCTION_ARGS);
+Datum		cube_is_point(PG_FUNCTION_ARGS);
+Datum		cube_enlarge(PG_FUNCTION_ARGS);
 
+/*
+** For internal use only
+*/
+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
@@ -98,10 +148,13 @@ static double distance_1D(double a1, double a2, double b1, double b2);
 
 /* NdBox = [(lowerleft),(upperright)] */
 /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
-NDBOX *
-cube_in(char *str)
+Datum
+cube_in(PG_FUNCTION_ARGS)
 {
 	void	   *result;
+	char		*str;
+
+	str = PG_GETARG_CSTRING(0);
 
 	cube_scanner_init(str);
 
@@ -110,29 +163,180 @@ cube_in(char *str)
 
 	cube_scanner_finish();
 
-	return ((NDBOX *) result);
+	PG_RETURN_POINTER (result);
 }
 
 /* Allow conversion from text to cube to allow input of computed strings */
 /* There may be issues with toasted data here. I don't know enough to be sure.*/
-NDBOX *
-cube(text *str)
+Datum
+cube(PG_FUNCTION_ARGS)
+{
+	char	*cstring;
+
+	cstring = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0))));
+
+	PG_RETURN_DATUM (DirectFunctionCall1 (cube_in, PointerGetDatum(cstring)));
+}
+
+
+#include "utils/array.h"
+
+/*
+** Taken from the intarray contrib header
+*/
+#define ARRPTR(x)  ( (double *) ARR_DATA_PTR(x) )
+#define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
+
+
+/*
+** Allows the construction of a cube from 2 float[]'s
+*/
+Datum
+cube_a_f8_f8(PG_FUNCTION_ARGS)
+{
+	int		i;
+	int		dim;
+	int		size;
+	NDBOX	*result;
+	ArrayType	*ur, *ll;
+	double	*dur, *dll;
+
+	ur = (ArrayType *) PG_GETARG_VARLENA_P(0);
+	ll = (ArrayType *) PG_GETARG_VARLENA_P(1);
+
+	if (ARR_HASNULL(ur) || ARR_HASNULL(ll))
+	{
+		ereport(ERROR,
+			(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
+			errmsg("Cannot work with NULL arrays")));
+	}
+
+	dim = ARRNELEMS(ur);
+	if (ARRNELEMS(ll) != dim)
+	{
+		ereport(ERROR,
+			(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
+			errmsg("UR and LL arrays must be of same length")));
+	}
+
+	dur = ARRPTR(ur);
+	dll = ARRPTR(ll);
+
+	size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim;
+	result = (NDBOX *) palloc (size);
+	memset (result, 0, size);
+	result->size = size;
+	result->dim = dim;
+
+	for (i=0; i<dim; i++)
+	{
+		result->x[i] = dur[i];
+		result->x[i+dim] = dll[i];
+	}
+
+	PG_RETURN_POINTER(result);
+}
+
+/*
+** Allows the construction of a zero-volume cube from a float[]
+*/
+Datum
+cube_a_f8(PG_FUNCTION_ARGS)
 {
-	return cube_in(DatumGetCString(DirectFunctionCall1(textout,
-													 PointerGetDatum(str))));
+	int		i;
+	int		dim;
+	int		size;
+	NDBOX	*result;
+	ArrayType	*ur;
+	double	*dur;
+
+	ur = (ArrayType *) PG_GETARG_VARLENA_P(0);
+
+	if (ARR_HASNULL(ur))
+	{
+		ereport(ERROR,
+			(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
+			errmsg("Cannot work with NULL arrays")));
+	}
+
+	dim = ARRNELEMS(ur);
+
+	dur = ARRPTR(ur);
+
+	size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim;
+	result = (NDBOX *) palloc (size);
+	memset (result, 0, size);
+	result->size = size;
+	result->dim = dim;
+
+	for (i=0; i<dim; i++)
+	{
+		result->x[i] = dur[i];
+		result->x[i+dim] = dur[i];
+	}
+
+	PG_RETURN_POINTER(result);
 }
 
-char *
-cube_out(NDBOX * cube)
+Datum
+cube_subset(PG_FUNCTION_ARGS)
+{
+	NDBOX	    *c, *result;
+	ArrayType   *idx;
+	int          size, dim, i;
+	int         *dx;
+
+	c = (NDBOX *) PG_GETARG_POINTER(0);
+	idx = (ArrayType *) PG_GETARG_VARLENA_P(1);
+
+	if (ARR_HASNULL(idx))
+	{
+		ereport(ERROR,
+			(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
+			errmsg("Cannot work with NULL arrays")));
+	}
+
+	dx = (int4 *) ARR_DATA_PTR (idx);
+
+	dim = ARRNELEMS(idx);
+	size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim;
+	result = (NDBOX *) palloc (size);
+	memset (result, 0, size);
+	result->size = size;
+	result->dim = dim;
+
+	for (i=0; i<dim; i++)
+	{
+		if ((dx[i] <= 0) || (dx[i] > c->dim))
+		{
+			pfree (result);
+			ereport(ERROR,
+				(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
+				errmsg("Index out of bounds")));
+		}
+		result->x[i] = c->x[dx[i]-1];
+		result->x[i+dim] = c->x[dx[i]+c->dim-1];
+	}
+
+	PG_RETURN_POINTER(result);
+}
+
+Datum
+cube_out(PG_FUNCTION_ARGS)
 {
 	StringInfoData buf;
 	bool		equal = true;
-	int			dim = cube->dim;
+	int			dim;
 	int			i;
 	int			ndig;
+	NDBOX		*cube;
 
 	initStringInfo(&buf);
 
+	cube = (NDBOX *) PG_GETARG_POINTER (0);
+
+	dim = cube->dim;
+
 	/*
 	 * Get the number of digits to display.
 	 */
@@ -167,7 +371,7 @@ cube_out(NDBOX * cube)
 		appendStringInfoChar(&buf, ')');
 	}
 
-	return buf.data;
+	PG_RETURN_CSTRING (buf.data);
 }
 
 
@@ -181,11 +385,13 @@ cube_out(NDBOX * cube)
 ** the predicate x op query == FALSE, where op is the oper
 ** corresponding to strategy in the pg_amop table.
 */
-bool
-g_cube_consistent(GISTENTRY *entry,
-				  NDBOX * query,
-				  StrategyNumber strategy)
+Datum	
+g_cube_consistent(PG_FUNCTION_ARGS)
 {
+	GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	NDBOX *query = (NDBOX *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
+	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
 	/*
 	 * if entry is not leaf, use g_cube_internal_consistent, else use
 	 * g_cube_leaf_consistent
@@ -203,12 +409,17 @@ g_cube_consistent(GISTENTRY *entry,
 ** The GiST Union method for boxes
 ** returns the minimal bounding box that encloses all the entries in entryvec
 */
-NDBOX *
-g_cube_union(GistEntryVector *entryvec, int *sizep)
+Datum
+g_cube_union(PG_FUNCTION_ARGS)
 {
 	int			i;
 	NDBOX	   *out = (NDBOX *) NULL;
 	NDBOX	   *tmp;
+	int		   *sizep;
+	GistEntryVector	*entryvec;
+
+	entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	sizep = (int *) PG_GETARG_POINTER(1);
 
 	/*
 	 * fprintf(stderr, "union\n");
@@ -228,37 +439,42 @@ g_cube_union(GistEntryVector *entryvec, int *sizep)
 		tmp = out;
 	}
 
-	return (out);
+	PG_RETURN_POINTER(out);
 }
 
 /*
 ** GiST Compress and Decompress methods for boxes
 ** do not do anything.
 */
-GISTENTRY *
-g_cube_compress(GISTENTRY *entry)
+
+Datum
+g_cube_compress (PG_FUNCTION_ARGS)
 {
-	return (entry);
+    PG_RETURN_DATUM(PG_GETARG_DATUM(0));
 }
 
-GISTENTRY *
-g_cube_decompress(GISTENTRY *entry)
+Datum
+g_cube_decompress (PG_FUNCTION_ARGS)
 {
-	return (entry);
+    PG_RETURN_DATUM(PG_GETARG_DATUM(0));
 }
 
+
 /*
 ** The GiST Penalty method for boxes
 ** As in the R-tree paper, we use change in area as our penalty metric
 */
-float *
-g_cube_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
+Datum
+g_cube_penalty (PG_FUNCTION_ARGS)
 {
+	GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
+	float	  *result = (float *) PG_GETARG_POINTER(2);
 	NDBOX	   *ud;
 	double		tmp1,
 				tmp2;
 
-	ud = cube_union((NDBOX *) DatumGetPointer(origentry->key),
+	ud = cube_union_v0((NDBOX *) DatumGetPointer(origentry->key),
 					(NDBOX *) DatumGetPointer(newentry->key));
 	rt_cube_size(ud, &tmp1);
 	rt_cube_size((NDBOX *) DatumGetPointer(origentry->key), &tmp2);
@@ -267,7 +483,7 @@ g_cube_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
 	/*
 	 * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result);
 	 */
-	return (result);
+	PG_RETURN_FLOAT8 (*result);
 }
 
 
@@ -276,10 +492,11 @@ g_cube_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
 ** The GiST PickSplit method for boxes
 ** We use Guttman's poly time split algorithm
 */
-GIST_SPLITVEC *
-g_cube_picksplit(GistEntryVector *entryvec,
-				 GIST_SPLITVEC *v)
+Datum
+g_cube_picksplit(PG_FUNCTION_ARGS)
 {
+	GistEntryVector	*entryvec;
+	GIST_SPLITVEC	*v;
 	OffsetNumber i,
 				j;
 	NDBOX	   *datum_alpha,
@@ -306,6 +523,9 @@ g_cube_picksplit(GistEntryVector *entryvec,
 			   *right;
 	OffsetNumber maxoff;
 
+	entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+
 	/*
 	 * fprintf(stderr, "picksplit\n");
 	 */
@@ -326,9 +546,11 @@ g_cube_picksplit(GistEntryVector *entryvec,
 
 			/* compute the wasted space by unioning these guys */
 			/* size_waste = size_union - size_inter; */
-			union_d = cube_union(datum_alpha, datum_beta);
+			union_d = cube_union_v0(datum_alpha, datum_beta);
 			rt_cube_size(union_d, &size_union);
-			inter_d = cube_inter(datum_alpha, datum_beta);
+			inter_d = (NDBOX *) DatumGetPointer (DirectFunctionCall2 
+			                     (cube_inter, 
+			                      entryvec->vector[i].key, entryvec->vector[j].key));
 			rt_cube_size(inter_d, &size_inter);
 			size_waste = size_union - size_inter;
 
@@ -352,10 +574,10 @@ g_cube_picksplit(GistEntryVector *entryvec,
 	v->spl_nright = 0;
 
 	datum_alpha = (NDBOX *) DatumGetPointer(entryvec->vector[seed_1].key);
-	datum_l = cube_union(datum_alpha, datum_alpha);
+	datum_l = cube_union_v0(datum_alpha, datum_alpha);
 	rt_cube_size(datum_l, &size_l);
 	datum_beta = (NDBOX *) DatumGetPointer(entryvec->vector[seed_2].key);
-	datum_r = cube_union(datum_beta, datum_beta);
+	datum_r = cube_union_v0(datum_beta, datum_beta);
 	rt_cube_size(datum_r, &size_r);
 
 	/*
@@ -394,8 +616,8 @@ g_cube_picksplit(GistEntryVector *entryvec,
 
 		/* okay, which page needs least enlargement? */
 		datum_alpha = (NDBOX *) DatumGetPointer(entryvec->vector[i].key);
-		union_dl = cube_union(datum_l, datum_alpha);
-		union_dr = cube_union(datum_r, datum_alpha);
+		union_dl = cube_union_v0(datum_l, datum_alpha);
+		union_dr = cube_union_v0(datum_r, datum_alpha);
 		rt_cube_size(union_dl, &size_alpha);
 		rt_cube_size(union_dr, &size_beta);
 
@@ -420,16 +642,23 @@ g_cube_picksplit(GistEntryVector *entryvec,
 	v->spl_ldatum = PointerGetDatum(datum_l);
 	v->spl_rdatum = PointerGetDatum(datum_r);
 
-	return v;
+	PG_RETURN_POINTER(v);
 }
 
 /*
 ** Equality method
 */
-bool *
-g_cube_same(NDBOX * b1, NDBOX * b2, bool *result)
+Datum
+g_cube_same(PG_FUNCTION_ARGS)
 {
-	if (cube_eq(b1, b2))
+	NDBOX	*b1, *b2;
+	bool	*result;
+	
+	b1 = (NDBOX *) PG_GETARG_POINTER (0);
+	b2 = (NDBOX *) PG_GETARG_POINTER (1);
+	result = (bool *) PG_GETARG_POINTER (2);
+
+	if (cube_cmp_v0(b1, b2) == 0)
 		*result = TRUE;
 	else
 		*result = FALSE;
@@ -437,7 +666,7 @@ g_cube_same(NDBOX * b1, NDBOX * b2, bool *result)
 	/*
 	 * fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" ));
 	 */
-	return (result);
+	PG_RETURN_POINTER (result);
 }
 
 /*
@@ -456,16 +685,16 @@ g_cube_leaf_consistent(NDBOX * key,
 	switch (strategy)
 	{
 		case RTOverlapStrategyNumber:
-			retval = (bool) cube_overlap(key, query);
+			retval = (bool) cube_overlap_v0(key, query);
 			break;
 		case RTSameStrategyNumber:
-			retval = (bool) cube_eq(key, query);
+			retval = (bool) (cube_cmp_v0(key, query) == 0);
 			break;
 		case RTContainsStrategyNumber:
-			retval = (bool) cube_contains(key, query);
+			retval = (bool) cube_contains_v0(key, query);
 			break;
 		case RTContainedByStrategyNumber:
-			retval = (bool) cube_contained(key, query);
+			retval = (bool) cube_contains_v0(query, key);
 			break;
 		default:
 			retval = FALSE;
@@ -486,14 +715,14 @@ g_cube_internal_consistent(NDBOX * key,
 	switch (strategy)
 	{
 		case RTOverlapStrategyNumber:
-			retval = (bool) cube_overlap(key, query);
+			retval = (bool) cube_overlap_v0(key, query);
 			break;
 		case RTSameStrategyNumber:
 		case RTContainsStrategyNumber:
-			retval = (bool) cube_contains(key, query);
+			retval = (bool) cube_contains_v0(key, query);
 			break;
 		case RTContainedByStrategyNumber:
-			retval = (bool) cube_overlap(key, query);
+			retval = (bool) cube_overlap_v0(key, query);
 			break;
 		default:
 			retval = FALSE;
@@ -506,16 +735,16 @@ g_cube_binary_union(NDBOX * r1, NDBOX * r2, int *sizep)
 {
 	NDBOX	   *retval;
 
-	retval = cube_union(r1, r2);
+	retval = cube_union_v0(r1, r2);
 	*sizep = retval->size;
 
 	return (retval);
 }
 
 
-/* cube_union */
+/* cube_union_v0 */
 NDBOX *
-cube_union(NDBOX * a, NDBOX * b)
+cube_union_v0(NDBOX * a, NDBOX * b)
 {
 	int			i;
 	NDBOX	   *result;
@@ -571,12 +800,26 @@ cube_union(NDBOX * a, NDBOX * b)
 	return (result);
 }
 
+Datum
+cube_union (PG_FUNCTION_ARGS)
+{
+	NDBOX	*a, *b;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_POINTER(cube_union_v0(a,b));
+}
+
 /* cube_inter */
-NDBOX *
-cube_inter(NDBOX * a, NDBOX * b)
+Datum
+cube_inter(PG_FUNCTION_ARGS)
 {
 	int			i;
-	NDBOX	   *result;
+	NDBOX	   *result, *a, *b;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
 
 	if (a->dim >= b->dim)
 	{
@@ -629,24 +872,25 @@ cube_inter(NDBOX * a, NDBOX * b)
 	/*
 	 * Is it OK to return a non-null intersection for non-overlapping boxes?
 	 */
-	return (result);
+	PG_RETURN_POINTER (result);
 }
 
 /* cube_size */
-double *
-cube_size(NDBOX * a)
+Datum
+cube_size(PG_FUNCTION_ARGS)
 {
+	NDBOX		*a;
 	int			i,
 				j;
-	double	   *result;
+	double	   	result;
 
-	result = (double *) palloc(sizeof(double));
+	a = (NDBOX *) PG_GETARG_POINTER(0);
 
-	*result = 1.0;
+	result = 1.0;
 	for (i = 0, j = a->dim; i < a->dim; i++, j++)
-		*result = (*result) * Abs((a->x[j] - a->x[i]));
+		result = result * Abs((a->x[j] - a->x[i]));
 
-	return (result);
+	PG_RETURN_FLOAT8 (result);
 }
 
 void
@@ -669,7 +913,7 @@ rt_cube_size(NDBOX * a, double *size)
 /* 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(NDBOX * a, NDBOX * b)
+cube_cmp_v0(NDBOX * a, NDBOX * b)
 {
 	int			i;
 	int			dim;
@@ -748,48 +992,95 @@ cube_cmp(NDBOX * a, NDBOX * b)
 	return 0;
 }
 
+Datum 
+cube_cmp(PG_FUNCTION_ARGS)
+{
+	NDBOX	*a, *b;
 
-bool
-cube_eq(NDBOX * a, NDBOX * b)
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_INT16(cube_cmp_v0(a, b));
+}
+
+
+Datum
+cube_eq(PG_FUNCTION_ARGS)
 {
-	return (cube_cmp(a, b) == 0);
+	NDBOX	*a, *b;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(cube_cmp_v0(a, b) == 0);
 }
 
-bool
-cube_ne(NDBOX * a, NDBOX * b)
+
+Datum
+cube_ne(PG_FUNCTION_ARGS)
 {
-	return (cube_cmp(a, b) != 0);
+	NDBOX	*a, *b;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(cube_cmp_v0(a, b) != 0);
 }
 
-bool
-cube_lt(NDBOX * a, NDBOX * b)
+
+Datum
+cube_lt(PG_FUNCTION_ARGS)
 {
-	return (cube_cmp(a, b) < 0);
+	NDBOX	*a, *b;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(cube_cmp_v0(a, b) < 0);
 }
 
-bool
-cube_gt(NDBOX * a, NDBOX * b)
+
+Datum
+cube_gt(PG_FUNCTION_ARGS)
 {
-	return (cube_cmp(a, b) > 0);
+	NDBOX	*a, *b;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(cube_cmp_v0(a, b) > 0);
 }
 
-bool
-cube_le(NDBOX * a, NDBOX * b)
+
+Datum
+cube_le(PG_FUNCTION_ARGS)
 {
-	return (cube_cmp(a, b) <= 0);
+	NDBOX	*a, *b;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(cube_cmp_v0(a, b) <= 0);
 }
 
-bool
-cube_ge(NDBOX * a, NDBOX * b)
+
+Datum
+cube_ge(PG_FUNCTION_ARGS)
 {
-	return (cube_cmp(a, b) >= 0);
+	NDBOX	*a, *b;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(cube_cmp_v0(a, b) >= 0);
 }
 
 
+
 /* Contains */
 /* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */
 bool
-cube_contains(NDBOX * a, NDBOX * b)
+cube_contains_v0(NDBOX * a, NDBOX * b)
 {
 	int			i;
 
@@ -826,21 +1117,34 @@ cube_contains(NDBOX * a, NDBOX * b)
 	return (TRUE);
 }
 
+Datum
+cube_contains(PG_FUNCTION_ARGS)
+{
+	NDBOX	*a, *b;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(cube_contains_v0(a, b));
+}
+
 /* Contained */
 /* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */
-bool
-cube_contained(NDBOX * a, NDBOX * b)
+Datum
+cube_contained(PG_FUNCTION_ARGS)
 {
-	if (cube_contains(b, a) == TRUE)
-		return (TRUE);
-	else
-		return (FALSE);
+	NDBOX	*a, *b;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL (cube_contains_v0(b, a));
 }
 
 /* Overlap */
 /* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */
 bool
-cube_overlap(NDBOX * a, NDBOX * b)
+cube_overlap_v0(NDBOX * a, NDBOX * b)
 {
 	int			i;
 
@@ -884,20 +1188,33 @@ cube_overlap(NDBOX * a, NDBOX * b)
 }
 
 
+Datum
+cube_overlap(PG_FUNCTION_ARGS)
+{
+	NDBOX	*a, *b;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL (cube_overlap_v0(a, b));
+}
+
+
 /* Distance */
 /* The distance is computed as a per axis sum of the squared distances
    between 1D projections of the boxes onto Cartesian axes. Assuming zero
    distance between overlapping projections, this metric coincides with the
    "common sense" geometric distance */
-double *
-cube_distance(NDBOX * a, NDBOX * b)
+Datum
+cube_distance(PG_FUNCTION_ARGS)
 {
 	int			i;
 	double		d,
 				distance;
-	double	   *result;
+	NDBOX	   *a, *b;
 
-	result = (double *) palloc(sizeof(double));
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	b = (NDBOX *) PG_GETARG_POINTER(1);
 
 	/* swap the box pointers if needed */
 	if (a->dim < b->dim)
@@ -923,9 +1240,7 @@ cube_distance(NDBOX * a, NDBOX * b)
 		distance += d * d;
 	}
 
-	*result = (double) sqrt(distance);
-
-	return (result);
+	PG_RETURN_FLOAT8(sqrt(distance));
 }
 
 static double
@@ -944,58 +1259,74 @@ distance_1D(double a1, double a2, double b1, double b2)
 }
 
 /* Test if a box is also a point */
-bool
-cube_is_point(NDBOX * a)
+Datum
+cube_is_point(PG_FUNCTION_ARGS)
 {
 	int			i,
 				j;
+	NDBOX		*a;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
 
 	for (i = 0, j = a->dim; i < a->dim; i++, j++)
 	{
 		if (a->x[i] != a->x[j])
-			return FALSE;
+			PG_RETURN_BOOL(FALSE);
 	}
 
-	return TRUE;
+	PG_RETURN_BOOL(TRUE);
 }
 
 /* Return dimensions in use in the data structure */
-int4
-cube_dim(NDBOX * a)
+Datum
+cube_dim(PG_FUNCTION_ARGS)
 {
-	/* Other things will break before unsigned int doesn't fit. */
-	return a->dim;
+	NDBOX	*c;
+
+	c = (NDBOX *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_INT16 (c->dim);
 }
 
 /* Return a specific normalized LL coordinate */
-double *
-cube_ll_coord(NDBOX * a, int4 n)
+Datum
+cube_ll_coord(PG_FUNCTION_ARGS)
 {
-	double	   *result;
+	NDBOX	   *c;
+	int			n;
+	double		result;
 
-	result = (double *) palloc(sizeof(double));
-	*result = 0;
-	if (a->dim >= n && n > 0)
-		*result = Min(a->x[n - 1], a->x[a->dim + n - 1]);
-	return result;
+	c = (NDBOX *) PG_GETARG_POINTER(0);
+	n = PG_GETARG_INT16(1);
+
+	result = 0;
+	if (c->dim >= n && n > 0)
+		result = Min(c->x[n - 1], c->x[c->dim + n - 1]);
+
+	PG_RETURN_FLOAT8(result);
 }
 
 /* Return a specific normalized UR coordinate */
-double *
-cube_ur_coord(NDBOX * a, int4 n)
+Datum
+cube_ur_coord(PG_FUNCTION_ARGS)
 {
-	double	   *result;
+	NDBOX	   *c;
+	int			n;
+	double		result;
+
+	c = (NDBOX *) PG_GETARG_POINTER(0);
+	n = PG_GETARG_INT16(1);
 
-	result = (double *) palloc(sizeof(double));
-	*result = 0;
-	if (a->dim >= n && n > 0)
-		*result = Max(a->x[n - 1], a->x[a->dim + n - 1]);
-	return result;
+	result = 0;
+	if (c->dim >= n && n > 0)
+		result = Max(c->x[n - 1], c->x[c->dim + n - 1]);
+
+	PG_RETURN_FLOAT8(result);
 }
 
 /* Increase or decrease box size by a radius in at least n dimensions. */
-NDBOX *
-cube_enlarge(NDBOX * a, double *r, int4 n)
+Datum
+cube_enlarge(PG_FUNCTION_ARGS)
 {
 	NDBOX	   *result;
 	int			dim = 0;
@@ -1003,6 +1334,13 @@ cube_enlarge(NDBOX * a, double *r, int4 n)
 	int			i,
 				j,
 				k;
+	NDBOX	   *a;
+	double	   *r;
+	int4		n;
+
+	a = (NDBOX *) PG_GETARG_POINTER(0);
+	r = (double *) PG_GETARG_POINTER(1);
+	n = PG_GETARG_INT32(2);
 
 	if (n > CUBE_MAX_DIM)
 		n = CUBE_MAX_DIM;
@@ -1039,12 +1377,13 @@ cube_enlarge(NDBOX * a, double *r, int4 n)
 		result->x[i] = -*r;
 		result->x[j] = *r;
 	}
-	return result;
+
+	PG_RETURN_POINTER(result);
 }
 
 /* Create a one dimensional box with identical upper and lower coordinates */
-NDBOX *
-cube_f8(double *x1)
+Datum
+cube_f8(PG_FUNCTION_ARGS)
 {
 	NDBOX	   *result;
 	int			size;
@@ -1054,14 +1393,15 @@ cube_f8(double *x1)
 	memset(result, 0, size);
 	result->size = size;
 	result->dim = 1;
-	result->x[0] = *x1;
-	result->x[1] = *x1;
-	return result;
+	result->x[0] = PG_GETARG_FLOAT8(0);
+	result->x[1] = result->x[0];
+	
+	PG_RETURN_POINTER (result);
 }
 
 /* Create a one dimensional box */
-NDBOX *
-cube_f8_f8(double *x1, double *x2)
+Datum
+cube_f8_f8(PG_FUNCTION_ARGS)
 {
 	NDBOX	   *result;
 	int			size;
@@ -1071,20 +1411,26 @@ cube_f8_f8(double *x1, double *x2)
 	memset(result, 0, size);
 	result->size = size;
 	result->dim = 1;
-	result->x[0] = *x1;
-	result->x[1] = *x2;
-	return result;
+	result->x[0] = PG_GETARG_FLOAT8(0);
+	result->x[1] = PG_GETARG_FLOAT8(1);
+
+	PG_RETURN_POINTER (result);
 }
 
 /* Add a dimension to an existing cube with the same values for the new
    coordinate */
-NDBOX *
-cube_c_f8(NDBOX * c, double *x1)
+Datum
+cube_c_f8(PG_FUNCTION_ARGS)
 {
+	NDBOX	   *c;
 	NDBOX	   *result;
+	double		x;
 	int			size;
 	int			i;
 
+	c = (NDBOX *) PG_GETARG_POINTER(0);
+	x = PG_GETARG_FLOAT8 (1);
+
 	size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
 	result = (NDBOX *) palloc(size);
 	memset(result, 0, size);
@@ -1095,19 +1441,26 @@ cube_c_f8(NDBOX * c, double *x1)
 		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] = *x1;
-	return result;
+	result->x[result->dim - 1] = x;
+	result->x[2 * result->dim - 1] = x;
+
+	PG_RETURN_POINTER(result);	
 }
 
 /* Add a dimension to an existing cube */
-NDBOX *
-cube_c_f8_f8(NDBOX * c, double *x1, double *x2)
+Datum
+cube_c_f8_f8(PG_FUNCTION_ARGS)
 {
+	NDBOX	   *c;
 	NDBOX	   *result;
+	double		x1, x2;
 	int			size;
 	int			i;
 
+	c = (NDBOX *) PG_GETARG_POINTER(0);
+	x1 = PG_GETARG_FLOAT8 (1);
+	x2 = PG_GETARG_FLOAT8 (2);
+
 	size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
 	result = (NDBOX *) palloc(size);
 	memset(result, 0, size);
@@ -1118,7 +1471,10 @@ cube_c_f8_f8(NDBOX * c, double *x1, double *x2)
 		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;
-	return result;
+	result->x[result->dim - 1] = x1;
+	result->x[2 * result->dim - 1] = x2;
+
+	PG_RETURN_POINTER(result);	
 }
+
+
diff --git a/contrib/cube/cube.sql.in b/contrib/cube/cube.sql.in
index 7b521abf156..3405c8e1f97 100644
--- a/contrib/cube/cube.sql.in
+++ b/contrib/cube/cube.sql.in
@@ -9,6 +9,14 @@ RETURNS cube
 AS 'MODULE_PATHNAME'
 LANGUAGE C IMMUTABLE STRICT;
 
+CREATE OR REPLACE FUNCTION cube(float8[], float8[]) RETURNS cube
+AS 'MODULE_PATHNAME', 'cube_a_f8_f8'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION cube(float8[]) RETURNS cube
+AS 'MODULE_PATHNAME', 'cube_a_f8'
+LANGUAGE C IMMUTABLE STRICT;
+
 CREATE OR REPLACE FUNCTION cube_out(cube)
 RETURNS cstring
 AS 'MODULE_PATHNAME'
@@ -129,6 +137,11 @@ LANGUAGE C IMMUTABLE STRICT;
 
 -- Misc N-dimensional functions
 
+CREATE OR REPLACE FUNCTION cube_subset(cube, int4[])
+RETURNS cube
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
 -- proximity routines
 
 CREATE OR REPLACE FUNCTION cube_distance(cube, cube)
diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out
index 578d27be7f8..57dbc56c711 100644
--- a/contrib/cube/expected/cube.out
+++ b/contrib/cube/expected/cube.out
@@ -8,7 +8,9 @@
 \set ECHO none
 psql:cube.sql:10: NOTICE:  type "cube" is not yet defined
 DETAIL:  Creating a shell type definition.
-psql:cube.sql:15: NOTICE:  argument type cube is only a shell
+psql:cube.sql:14: NOTICE:  return type cube is only a shell
+psql:cube.sql:18: NOTICE:  return type cube is only a shell
+psql:cube.sql:23: NOTICE:  argument type cube is only a shell
 --
 -- testing the input and output functions
 --
@@ -395,6 +397,37 @@ SELECT '(0)'::text::cube;
  (0)
 (1 row)
 
+--
+-- Test the float[] -> cube cast
+--
+SELECT cube('{0,1,2}'::float[], '{3,4,5}'::float[]);
+        cube         
+---------------------
+ (0, 1, 2),(3, 4, 5)
+(1 row)
+
+SELECT cube('{0,1,2}'::float[], '{3}'::float[]);
+ERROR:  UR and LL arrays must be of same length
+SELECT cube(NULL::float[], '{3}'::float[]);
+ cube 
+------
+ 
+(1 row)
+
+SELECT cube('{0,1,2}'::float[]);
+   cube    
+-----------
+ (0, 1, 2)
+(1 row)
+
+SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]); 
+        cube_subset        
+---------------------------
+ (5, 3, 1, 1),(8, 7, 6, 6)
+(1 row)
+
+SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]); 
+ERROR:  Index out of bounds
 --
 -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in.
 --
@@ -1021,24 +1054,24 @@ SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2);
 CREATE TABLE test_cube (c cube);
 \copy test_cube from 'data/test_cube.data'
 CREATE INDEX test_cube_ix ON test_cube USING gist (c);
-SELECT * FROM test_cube	WHERE c && '(3000,1000),(0,0)';
+SELECT * FROM test_cube	WHERE c && '(3000,1000),(0,0)' ORDER BY c;
             c             
 --------------------------
- (2424, 160),(2424, 81)
- (759, 187),(662, 163)
- (1444, 403),(1346, 344)
- (337, 455),(240, 359)
  (1594, 1043),(1517, 971)
+ (337, 455),(240, 359)
+ (1444, 403),(1346, 344)
+ (759, 187),(662, 163)
+ (2424, 160),(2424, 81)
 (5 rows)
 
 -- Test sorting 
-SELECT * FROM test_cube	WHERE c && '(3000,1000),(0,0)' GROUP BY c;
+SELECT * FROM test_cube	WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c;
             c             
 --------------------------
+ (1594, 1043),(1517, 971)
  (337, 455),(240, 359)
- (759, 187),(662, 163)
  (1444, 403),(1346, 344)
- (1594, 1043),(1517, 971)
+ (759, 187),(662, 163)
  (2424, 160),(2424, 81)
 (5 rows)
 
diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql
index 0b22fd768d7..fbfb11ed390 100644
--- a/contrib/cube/sql/cube.sql
+++ b/contrib/cube/sql/cube.sql
@@ -110,6 +110,16 @@ SELECT cube(cube(cube(1,2),3,4),5,6);
 
 SELECT '(0)'::text::cube;
 
+--
+-- Test the float[] -> cube cast
+--
+SELECT cube('{0,1,2}'::float[], '{3,4,5}'::float[]);
+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),(6,7,8)'), ARRAY[4,0]); 
+
 --
 -- Testing limit of CUBE_MAX_DIM dimensions check in cube_in.
 --
@@ -269,7 +279,7 @@ CREATE TABLE test_cube (c cube);
 \copy test_cube from 'data/test_cube.data'
 
 CREATE INDEX test_cube_ix ON test_cube USING gist (c);
-SELECT * FROM test_cube	WHERE c && '(3000,1000),(0,0)';
+SELECT * FROM test_cube	WHERE c && '(3000,1000),(0,0)' ORDER BY c;
 
 -- Test sorting 
-SELECT * FROM test_cube	WHERE c && '(3000,1000),(0,0)' GROUP BY c;
+SELECT * FROM test_cube	WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c;
diff --git a/contrib/cube/uninstall_cube.sql b/contrib/cube/uninstall_cube.sql
index 6ae8ee15ccb..6548a784703 100644
--- a/contrib/cube/uninstall_cube.sql
+++ b/contrib/cube/uninstall_cube.sql
@@ -46,6 +46,12 @@ DROP FUNCTION cube(cube, float8);
 
 DROP FUNCTION cube(float8, float8);
 
+DROP FUNCTION cube(float8[], float8[]);
+
+DROP FUNCTION cube(float8[]);
+
+DROP FUNCTION cube_subset(cube, int4[]);
+
 DROP FUNCTION cube(float8);
 
 DROP FUNCTION cube_ur_coord(cube, int4);
-- 
GitLab