Final version of my cube patch - fixed test cases, added documentation - Mailing list pgsql-patches

From Joshua Reich
Subject Final version of my cube patch - fixed test cases, added documentation
Date
Msg-id 44C1B541.5010902@root.net
Whole thread Raw
Responses Re: Final version of my cube patch - fixed test cases,
List pgsql-patches
Any committers want to take ownership of this?

Thanks,

Joshua Reich


********************************************************************************
  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.

? cube.diff
? cubeparse.tab.c
? logfile
Index: CHANGES
===================================================================
RCS file: /projects/cvsroot/pgsql/contrib/cube/CHANGES,v
retrieving revision 1.2
diff -c -r1.2 CHANGES
*** CHANGES    12 Sep 2002 00:26:00 -0000    1.2
--- CHANGES    22 Jul 2006 05:15:44 -0000
***************
*** 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.
Index: README.cube
===================================================================
RCS file: /projects/cvsroot/pgsql/contrib/cube/README.cube,v
retrieving revision 1.7
diff -c -r1.7 README.cube
*** README.cube    27 Jun 2005 01:19:43 -0000    1.7
--- README.cube    22 Jul 2006 05:15:45 -0000
***************
*** 244,249 ****
--- 244,259 ----
    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,272 ****
--- 277,289 ----
    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,329 ****
--- 344,353 ----

  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.
Index: cube.c
===================================================================
RCS file: /projects/cvsroot/pgsql/contrib/cube/cube.c,v
retrieving revision 1.26
diff -c -r1.26 cube.c
*** cube.c    28 Jun 2006 11:59:59 -0000    1.26
--- cube.c    22 Jul 2006 05:15:45 -0000
***************
*** 28,90 ****
  /*
  ** 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);
!

  /*
  ** 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);

  /*
  ** 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);

  /*
  ** 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);

  /*
  ** 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);


  /*
  ** Auxiliary funxtions
--- 28,140 ----
  /*
  ** Input/Output routines
  */
! 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
  */
!
! 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
  */
! 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
  */
!
! 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
  */
! 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,107 ****

  /* NdBox = [(lowerleft),(upperright)] */
  /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
! NDBOX *
! cube_in(char *str)
  {
      void       *result;

      cube_scanner_init(str);

--- 148,160 ----

  /* NdBox = [(lowerleft),(upperright)] */
  /* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */
! Datum
! cube_in(PG_FUNCTION_ARGS)
  {
      void       *result;
+     char        *str;
+
+     str = PG_GETARG_CSTRING(0);

      cube_scanner_init(str);

***************
*** 110,138 ****

      cube_scanner_finish();

!     return ((NDBOX *) 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)
  {
!     return cube_in(DatumGetCString(DirectFunctionCall1(textout,
!                                                      PointerGetDatum(str))));
  }

! char *
! cube_out(NDBOX * cube)
  {
      StringInfoData buf;
      bool        equal = true;
!     int            dim = cube->dim;
      int            i;
      int            ndig;

      initStringInfo(&buf);

      /*
       * Get the number of digits to display.
       */
--- 163,342 ----

      cube_scanner_finish();

!     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.*/
! 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)
! {
!     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);
! }
!
! 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;
      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,173 ****
          appendStringInfoChar(&buf, ')');
      }

!     return buf.data;
  }


--- 371,377 ----
          appendStringInfoChar(&buf, ')');
      }

!     PG_RETURN_CSTRING (buf.data);
  }


***************
*** 181,191 ****
  ** 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)
  {
      /*
       * if entry is not leaf, use g_cube_internal_consistent, else use
       * g_cube_leaf_consistent
--- 385,397 ----
  ** the predicate x op query == FALSE, where op is the oper
  ** corresponding to strategy in the pg_amop table.
  */
! 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,214 ****
  ** 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)
  {
      int            i;
      NDBOX       *out = (NDBOX *) NULL;
      NDBOX       *tmp;

      /*
       * fprintf(stderr, "union\n");
--- 409,425 ----
  ** The GiST Union method for boxes
  ** returns the minimal bounding box that encloses all the entries in entryvec
  */
! 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,264 ****
          tmp = out;
      }

!     return (out);
  }

  /*
  ** GiST Compress and Decompress methods for boxes
  ** do not do anything.
  */
! GISTENTRY *
! g_cube_compress(GISTENTRY *entry)
  {
!     return (entry);
  }

! GISTENTRY *
! g_cube_decompress(GISTENTRY *entry)
  {
!     return (entry);
  }

  /*
  ** 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)
  {
      NDBOX       *ud;
      double        tmp1,
                  tmp2;

!     ud = cube_union((NDBOX *) DatumGetPointer(origentry->key),
                      (NDBOX *) DatumGetPointer(newentry->key));
      rt_cube_size(ud, &tmp1);
      rt_cube_size((NDBOX *) DatumGetPointer(origentry->key), &tmp2);
--- 439,480 ----
          tmp = out;
      }

!     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)
  {
!     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
  */
! 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_v0((NDBOX *) DatumGetPointer(origentry->key),
                      (NDBOX *) DatumGetPointer(newentry->key));
      rt_cube_size(ud, &tmp1);
      rt_cube_size((NDBOX *) DatumGetPointer(origentry->key), &tmp2);
***************
*** 267,273 ****
      /*
       * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result);
       */
!     return (result);
  }


--- 483,489 ----
      /*
       * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result);
       */
!     PG_RETURN_FLOAT8 (*result);
  }


***************
*** 276,285 ****
  ** The GiST PickSplit method for boxes
  ** We use Guttman's poly time split algorithm
  */
! GIST_SPLITVEC *
! g_cube_picksplit(GistEntryVector *entryvec,
!                  GIST_SPLITVEC *v)
  {
      OffsetNumber i,
                  j;
      NDBOX       *datum_alpha,
--- 492,502 ----
  ** The GiST PickSplit method for boxes
  ** We use Guttman's poly time split algorithm
  */
! Datum
! g_cube_picksplit(PG_FUNCTION_ARGS)
  {
+     GistEntryVector    *entryvec;
+     GIST_SPLITVEC    *v;
      OffsetNumber i,
                  j;
      NDBOX       *datum_alpha,
***************
*** 306,311 ****
--- 523,531 ----
                 *right;
      OffsetNumber maxoff;

+     entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+     v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+
      /*
       * fprintf(stderr, "picksplit\n");
       */
***************
*** 326,334 ****

              /* compute the wasted space by unioning these guys */
              /* size_waste = size_union - size_inter; */
!             union_d = cube_union(datum_alpha, datum_beta);
              rt_cube_size(union_d, &size_union);
!             inter_d = cube_inter(datum_alpha, datum_beta);
              rt_cube_size(inter_d, &size_inter);
              size_waste = size_union - size_inter;

--- 546,556 ----

              /* compute the wasted space by unioning these guys */
              /* size_waste = size_union - size_inter; */
!             union_d = cube_union_v0(datum_alpha, datum_beta);
              rt_cube_size(union_d, &size_union);
!             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,361 ****
      v->spl_nright = 0;

      datum_alpha = (NDBOX *) DatumGetPointer(entryvec->vector[seed_1].key);
!     datum_l = cube_union(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);
      rt_cube_size(datum_r, &size_r);

      /*
--- 574,583 ----
      v->spl_nright = 0;

      datum_alpha = (NDBOX *) DatumGetPointer(entryvec->vector[seed_1].key);
!     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_v0(datum_beta, datum_beta);
      rt_cube_size(datum_r, &size_r);

      /*
***************
*** 394,401 ****

          /* 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);
          rt_cube_size(union_dl, &size_alpha);
          rt_cube_size(union_dr, &size_beta);

--- 616,623 ----

          /* okay, which page needs least enlargement? */
          datum_alpha = (NDBOX *) DatumGetPointer(entryvec->vector[i].key);
!         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,435 ****
      v->spl_ldatum = PointerGetDatum(datum_l);
      v->spl_rdatum = PointerGetDatum(datum_r);

!     return v;
  }

  /*
  ** Equality method
  */
! bool *
! g_cube_same(NDBOX * b1, NDBOX * b2, bool *result)
  {
!     if (cube_eq(b1, b2))
          *result = TRUE;
      else
          *result = FALSE;
--- 642,664 ----
      v->spl_ldatum = PointerGetDatum(datum_l);
      v->spl_rdatum = PointerGetDatum(datum_r);

!     PG_RETURN_POINTER(v);
  }

  /*
  ** Equality method
  */
! Datum
! g_cube_same(PG_FUNCTION_ARGS)
  {
!     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,443 ****
      /*
       * fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" ));
       */
!     return (result);
  }

  /*
--- 666,672 ----
      /*
       * fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" ));
       */
!     PG_RETURN_POINTER (result);
  }

  /*
***************
*** 456,471 ****
      switch (strategy)
      {
          case RTOverlapStrategyNumber:
!             retval = (bool) cube_overlap(key, query);
              break;
          case RTSameStrategyNumber:
!             retval = (bool) cube_eq(key, query);
              break;
          case RTContainsStrategyNumber:
!             retval = (bool) cube_contains(key, query);
              break;
          case RTContainedByStrategyNumber:
!             retval = (bool) cube_contained(key, query);
              break;
          default:
              retval = FALSE;
--- 685,700 ----
      switch (strategy)
      {
          case RTOverlapStrategyNumber:
!             retval = (bool) cube_overlap_v0(key, query);
              break;
          case RTSameStrategyNumber:
!             retval = (bool) (cube_cmp_v0(key, query) == 0);
              break;
          case RTContainsStrategyNumber:
!             retval = (bool) cube_contains_v0(key, query);
              break;
          case RTContainedByStrategyNumber:
!             retval = (bool) cube_contains_v0(query, key);
              break;
          default:
              retval = FALSE;
***************
*** 486,499 ****
      switch (strategy)
      {
          case RTOverlapStrategyNumber:
!             retval = (bool) cube_overlap(key, query);
              break;
          case RTSameStrategyNumber:
          case RTContainsStrategyNumber:
!             retval = (bool) cube_contains(key, query);
              break;
          case RTContainedByStrategyNumber:
!             retval = (bool) cube_overlap(key, query);
              break;
          default:
              retval = FALSE;
--- 715,728 ----
      switch (strategy)
      {
          case RTOverlapStrategyNumber:
!             retval = (bool) cube_overlap_v0(key, query);
              break;
          case RTSameStrategyNumber:
          case RTContainsStrategyNumber:
!             retval = (bool) cube_contains_v0(key, query);
              break;
          case RTContainedByStrategyNumber:
!             retval = (bool) cube_overlap_v0(key, query);
              break;
          default:
              retval = FALSE;
***************
*** 506,521 ****
  {
      NDBOX       *retval;

!     retval = cube_union(r1, r2);
      *sizep = retval->size;

      return (retval);
  }


! /* cube_union */
  NDBOX *
! cube_union(NDBOX * a, NDBOX * b)
  {
      int            i;
      NDBOX       *result;
--- 735,750 ----
  {
      NDBOX       *retval;

!     retval = cube_union_v0(r1, r2);
      *sizep = retval->size;

      return (retval);
  }


! /* cube_union_v0 */
  NDBOX *
! cube_union_v0(NDBOX * a, NDBOX * b)
  {
      int            i;
      NDBOX       *result;
***************
*** 571,582 ****
      return (result);
  }

  /* cube_inter */
! NDBOX *
! cube_inter(NDBOX * a, NDBOX * b)
  {
      int            i;
!     NDBOX       *result;

      if (a->dim >= b->dim)
      {
--- 800,825 ----
      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 */
! Datum
! cube_inter(PG_FUNCTION_ARGS)
  {
      int            i;
!     NDBOX       *result, *a, *b;
!
!     a = (NDBOX *) PG_GETARG_POINTER(0);
!     b = (NDBOX *) PG_GETARG_POINTER(1);

      if (a->dim >= b->dim)
      {
***************
*** 629,652 ****
      /*
       * Is it OK to return a non-null intersection for non-overlapping boxes?
       */
!     return (result);
  }

  /* cube_size */
! double *
! cube_size(NDBOX * a)
  {
      int            i,
                  j;
!     double       *result;

!     result = (double *) palloc(sizeof(double));

!     *result = 1.0;
      for (i = 0, j = a->dim; i < a->dim; i++, j++)
!         *result = (*result) * Abs((a->x[j] - a->x[i]));

!     return (result);
  }

  void
--- 872,896 ----
      /*
       * Is it OK to return a non-null intersection for non-overlapping boxes?
       */
!     PG_RETURN_POINTER (result);
  }

  /* cube_size */
! Datum
! cube_size(PG_FUNCTION_ARGS)
  {
+     NDBOX        *a;
      int            i,
                  j;
!     double           result;

!     a = (NDBOX *) PG_GETARG_POINTER(0);

!     result = 1.0;
      for (i = 0, j = a->dim; i < a->dim; i++, j++)
!         result = result * Abs((a->x[j] - a->x[i]));

!     PG_RETURN_FLOAT8 (result);
  }

  void
***************
*** 669,675 ****
  /* 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)
  {
      int            i;
      int            dim;
--- 913,919 ----
  /* 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)
  {
      int            i;
      int            dim;
***************
*** 748,795 ****
      return 0;
  }


! bool
! cube_eq(NDBOX * a, NDBOX * b)
  {
!     return (cube_cmp(a, b) == 0);
  }

! bool
! cube_ne(NDBOX * a, NDBOX * b)
  {
!     return (cube_cmp(a, b) != 0);
  }

! bool
! cube_lt(NDBOX * a, NDBOX * b)
  {
!     return (cube_cmp(a, b) < 0);
  }

! bool
! cube_gt(NDBOX * a, NDBOX * b)
  {
!     return (cube_cmp(a, b) > 0);
  }

! bool
! cube_le(NDBOX * a, NDBOX * b)
  {
!     return (cube_cmp(a, b) <= 0);
  }

! bool
! cube_ge(NDBOX * a, NDBOX * b)
  {
!     return (cube_cmp(a, b) >= 0);
  }


  /* Contains */
  /* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */
  bool
! cube_contains(NDBOX * a, NDBOX * b)
  {
      int            i;

--- 992,1086 ----
      return 0;
  }

+ Datum
+ cube_cmp(PG_FUNCTION_ARGS)
+ {
+     NDBOX    *a, *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)
  {
!     NDBOX    *a, *b;
!
!     a = (NDBOX *) PG_GETARG_POINTER(0);
!     b = (NDBOX *) PG_GETARG_POINTER(1);
!
!     PG_RETURN_BOOL(cube_cmp_v0(a, b) == 0);
  }

!
! Datum
! cube_ne(PG_FUNCTION_ARGS)
  {
!     NDBOX    *a, *b;
!
!     a = (NDBOX *) PG_GETARG_POINTER(0);
!     b = (NDBOX *) PG_GETARG_POINTER(1);
!
!     PG_RETURN_BOOL(cube_cmp_v0(a, b) != 0);
  }

!
! Datum
! cube_lt(PG_FUNCTION_ARGS)
  {
!     NDBOX    *a, *b;
!
!     a = (NDBOX *) PG_GETARG_POINTER(0);
!     b = (NDBOX *) PG_GETARG_POINTER(1);
!
!     PG_RETURN_BOOL(cube_cmp_v0(a, b) < 0);
  }

!
! Datum
! cube_gt(PG_FUNCTION_ARGS)
  {
!     NDBOX    *a, *b;
!
!     a = (NDBOX *) PG_GETARG_POINTER(0);
!     b = (NDBOX *) PG_GETARG_POINTER(1);
!
!     PG_RETURN_BOOL(cube_cmp_v0(a, b) > 0);
  }

!
! Datum
! cube_le(PG_FUNCTION_ARGS)
  {
!     NDBOX    *a, *b;
!
!     a = (NDBOX *) PG_GETARG_POINTER(0);
!     b = (NDBOX *) PG_GETARG_POINTER(1);
!
!     PG_RETURN_BOOL(cube_cmp_v0(a, b) <= 0);
  }

!
! Datum
! cube_ge(PG_FUNCTION_ARGS)
  {
!     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_v0(NDBOX * a, NDBOX * b)
  {
      int            i;

***************
*** 826,846 ****
      return (TRUE);
  }

  /* Contained */
  /* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */
! bool
! cube_contained(NDBOX * a, NDBOX * b)
  {
!     if (cube_contains(b, a) == TRUE)
!         return (TRUE);
!     else
!         return (FALSE);
  }

  /* 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)
  {
      int            i;

--- 1117,1150 ----
      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) */
! Datum
! cube_contained(PG_FUNCTION_ARGS)
  {
!     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_v0(NDBOX * a, NDBOX * b)
  {
      int            i;

***************
*** 884,903 ****
  }


  /* 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)
  {
      int            i;
      double        d,
                  distance;
!     double       *result;

!     result = (double *) palloc(sizeof(double));

      /* swap the box pointers if needed */
      if (a->dim < b->dim)
--- 1188,1220 ----
  }


+ 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 */
! Datum
! cube_distance(PG_FUNCTION_ARGS)
  {
      int            i;
      double        d,
                  distance;
!     NDBOX       *a, *b;

!     a = (NDBOX *) PG_GETARG_POINTER(0);
!     b = (NDBOX *) PG_GETARG_POINTER(1);

      /* swap the box pointers if needed */
      if (a->dim < b->dim)
***************
*** 923,931 ****
          distance += d * d;
      }

!     *result = (double) sqrt(distance);
!
!     return (result);
  }

  static double
--- 1240,1246 ----
          distance += d * d;
      }

!     PG_RETURN_FLOAT8(sqrt(distance));
  }

  static double
***************
*** 944,1001 ****
  }

  /* Test if a box is also a point */
! bool
! cube_is_point(NDBOX * a)
  {
      int            i,
                  j;

      for (i = 0, j = a->dim; i < a->dim; i++, j++)
      {
          if (a->x[i] != a->x[j])
!             return FALSE;
      }

!     return TRUE;
  }

  /* Return dimensions in use in the data structure */
! int4
! cube_dim(NDBOX * a)
  {
!     /* Other things will break before unsigned int doesn't fit. */
!     return a->dim;
  }

  /* Return a specific normalized LL coordinate */
! double *
! cube_ll_coord(NDBOX * a, int4 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;
  }

  /* Return a specific normalized UR coordinate */
! double *
! cube_ur_coord(NDBOX * a, int4 n)
  {
!     double       *result;

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

  /* Increase or decrease box size by a radius in at least n dimensions. */
! NDBOX *
! cube_enlarge(NDBOX * a, double *r, int4 n)
  {
      NDBOX       *result;
      int            dim = 0;
--- 1259,1332 ----
  }

  /* Test if a box is also a point */
! 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])
!             PG_RETURN_BOOL(FALSE);
      }

!     PG_RETURN_BOOL(TRUE);
  }

  /* Return dimensions in use in the data structure */
! Datum
! cube_dim(PG_FUNCTION_ARGS)
  {
!     NDBOX    *c;
!
!     c = (NDBOX *) PG_GETARG_POINTER(0);
!
!     PG_RETURN_INT16 (c->dim);
  }

  /* Return a specific normalized LL coordinate */
! Datum
! cube_ll_coord(PG_FUNCTION_ARGS)
  {
!     NDBOX       *c;
!     int            n;
!     double        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 */
! Datum
! cube_ur_coord(PG_FUNCTION_ARGS)
  {
!     NDBOX       *c;
!     int            n;
!     double        result;

!     c = (NDBOX *) PG_GETARG_POINTER(0);
!     n = PG_GETARG_INT16(1);
!
!     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. */
! Datum
! cube_enlarge(PG_FUNCTION_ARGS)
  {
      NDBOX       *result;
      int            dim = 0;
***************
*** 1003,1008 ****
--- 1334,1346 ----
      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,1050 ****
          result->x[i] = -*r;
          result->x[j] = *r;
      }
!     return result;
  }

  /* Create a one dimensional box with identical upper and lower coordinates */
! NDBOX *
! cube_f8(double *x1)
  {
      NDBOX       *result;
      int            size;
--- 1377,1389 ----
          result->x[i] = -*r;
          result->x[j] = *r;
      }
!
!     PG_RETURN_POINTER(result);
  }

  /* Create a one dimensional box with identical upper and lower coordinates */
! Datum
! cube_f8(PG_FUNCTION_ARGS)
  {
      NDBOX       *result;
      int            size;
***************
*** 1054,1067 ****
      memset(result, 0, size);
      result->size = size;
      result->dim = 1;
!     result->x[0] = *x1;
!     result->x[1] = *x1;
!     return result;
  }

  /* Create a one dimensional box */
! NDBOX *
! cube_f8_f8(double *x1, double *x2)
  {
      NDBOX       *result;
      int            size;
--- 1393,1407 ----
      memset(result, 0, size);
      result->size = size;
      result->dim = 1;
!     result->x[0] = PG_GETARG_FLOAT8(0);
!     result->x[1] = result->x[0];
!
!     PG_RETURN_POINTER (result);
  }

  /* Create a one dimensional box */
! Datum
! cube_f8_f8(PG_FUNCTION_ARGS)
  {
      NDBOX       *result;
      int            size;
***************
*** 1071,1090 ****
      memset(result, 0, size);
      result->size = size;
      result->dim = 1;
!     result->x[0] = *x1;
!     result->x[1] = *x2;
!     return result;
  }

  /* Add a dimension to an existing cube with the same values for the new
     coordinate */
! NDBOX *
! cube_c_f8(NDBOX * c, double *x1)
  {
      NDBOX       *result;
      int            size;
      int            i;

      size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
      result = (NDBOX *) palloc(size);
      memset(result, 0, size);
--- 1411,1436 ----
      memset(result, 0, size);
      result->size = size;
      result->dim = 1;
!     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 */
! 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,1113 ****
          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;
  }

  /* Add a dimension to an existing cube */
! NDBOX *
! cube_c_f8_f8(NDBOX * c, double *x1, double *x2)
  {
      NDBOX       *result;
      int            size;
      int            i;

      size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
      result = (NDBOX *) palloc(size);
      memset(result, 0, size);
--- 1441,1466 ----
          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_RETURN_POINTER(result);
  }

  /* Add a dimension to an existing cube */
! 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,1124 ****
          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;
  }
--- 1471,1480 ----
          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_RETURN_POINTER(result);
  }
+
+
Index: cube.sql.in
===================================================================
RCS file: /projects/cvsroot/pgsql/contrib/cube/cube.sql.in,v
retrieving revision 1.17
diff -c -r1.17 cube.sql.in
*** cube.sql.in    27 Feb 2006 16:09:48 -0000    1.17
--- cube.sql.in    22 Jul 2006 05:15:46 -0000
***************
*** 9,14 ****
--- 9,22 ----
  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,134 ****
--- 137,147 ----

  -- 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)
Index: uninstall_cube.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/contrib/cube/uninstall_cube.sql,v
retrieving revision 1.2
diff -c -r1.2 uninstall_cube.sql
*** uninstall_cube.sql    13 Mar 2006 18:04:57 -0000    1.2
--- uninstall_cube.sql    22 Jul 2006 05:15:46 -0000
***************
*** 46,51 ****
--- 46,57 ----

  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);
Index: expected/cube.out
===================================================================
RCS file: /projects/cvsroot/pgsql/contrib/cube/expected/cube.out,v
retrieving revision 1.16
diff -c -r1.16 cube.out
*** expected/cube.out    1 Mar 2006 21:09:31 -0000    1.16
--- expected/cube.out    22 Jul 2006 05:15:46 -0000
***************
*** 8,14 ****
  \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
  --
  -- testing the input and output functions
  --
--- 8,16 ----
  \set ECHO none
  psql:cube.sql:10: NOTICE:  type "cube" is not yet defined
  DETAIL:  Creating a shell type definition.
! 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
  --
***************
*** 396,401 ****
--- 398,434 ----
  (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.
  --
  select
'(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube;
***************
*** 1021,1044 ****
  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)';
              c
  --------------------------
-  (2424, 160),(2424, 81)
-  (759, 187),(662, 163)
-  (1444, 403),(1346, 344)
-  (337, 455),(240, 359)
   (1594, 1043),(1517, 971)
  (5 rows)

  -- Test sorting
! SELECT * FROM test_cube    WHERE c && '(3000,1000),(0,0)' GROUP BY c;
              c
  --------------------------
   (337, 455),(240, 359)
-  (759, 187),(662, 163)
   (1444, 403),(1346, 344)
!  (1594, 1043),(1517, 971)
   (2424, 160),(2424, 81)
  (5 rows)

--- 1054,1077 ----
  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)' ORDER BY c;
              c
  --------------------------
   (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 ORDER BY c;
              c
  --------------------------
+  (1594, 1043),(1517, 971)
   (337, 455),(240, 359)
   (1444, 403),(1346, 344)
!  (759, 187),(662, 163)
   (2424, 160),(2424, 81)
  (5 rows)

Index: sql/cube.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/contrib/cube/sql/cube.sql,v
retrieving revision 1.8
diff -c -r1.8 cube.sql
*** sql/cube.sql    27 Jun 2005 01:19:43 -0000    1.8
--- sql/cube.sql    22 Jul 2006 05:15:46 -0000
***************
*** 111,116 ****
--- 111,126 ----
  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,275 ****
  \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)';

  -- Test sorting
! SELECT * FROM test_cube    WHERE c && '(3000,1000),(0,0)' GROUP BY c;
--- 279,285 ----
  \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)' ORDER BY c;

  -- Test sorting
! SELECT * FROM test_cube    WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c;

pgsql-patches by date:

Previous
From: Tom Lane
Date:
Subject: Re: BTree tid operators and opclass
Next
From: Robert Treat
Date:
Subject: Re: Mark change-on-restart-only values in postgresql.conf