Please find my cleanup of cube attached.

I have also included the cube_a_f8_f8() function to allow construction of a cube from 2 float8[]'s.


Thanks,

Josh Reich

Neil Conway wrote:
On Mon, 2006-07-17 at 17:55 -0400, Joshua Reich wrote:
Ok. So, the cube code looks very unmaintained (not to offend anyone), but it is all in V0 and I believe make installcheck fails out of the box due to new error message formats.

It passes for me with CVS HEAD. The cube regression test is also run as
part of the buildfarm process, so it sounds like an error on your end.

I'm in the process of twisting the arm of another guy here to help me
clean up the code - if that is ok with the powers that be?

Cleanup would certainly be welcome.

This is my first patch submission, so please let me know what heinous errors I have made

You should submit patches in context diff format (diff -c). You should
also send a single patch for all the (related) changes you want to make,
and you seem to have omitted the diff headers. You should generate
patches like:

$ cvs diff                    # from the root of the source tree

or

$ diff -rc ../orig_tree .     # from the root of the modified tree

Depending on whether you're working against CVS or if you've made a copy
of the source tree to make your changes in.

      if (ARRNELEMS(ll) != dim)
      {
              ereport(ERROR,
                      (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
                      errmsg("UR and LL arrays must be of same
length")));
              PG_RETURN_NULL();
      }

You don't need to return anything after ereport(ERROR) -- it won't
return control to the caller.

-Neil



---------------------------(end of broadcast)---------------------------
TIP 1: if posting/reading through Usenet, please send an appropriate
       subscribe-nomail command to [EMAIL PROTECTED] so that your
       message can get through to the mailing list cleanly
? cube.sql
? cube_from_arrays.c
? cube_v0_to_v1.diff
? libcube.so.0.0
? logfile
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      18 Jul 2006 15:31:43 -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,136 ----
  /*
  ** 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_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);
! 
! Datum         cube_in(PG_FUNCTION_ARGS);
! Datum         cube(PG_FUNCTION_ARGS);
! Datum         cube_a_f8_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);
  
  /*
  ** 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);
  
--- 144,156 ----
  
  /* 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.
         */
--- 159,254 ----
  
        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);
  }
  
! 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;
  }
  
  
--- 283,289 ----
                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
--- 297,309 ----
  ** 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");
--- 321,337 ----
  ** 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);
--- 351,392 ----
                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);
  }
  
  
--- 395,401 ----
        /*
         * 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,
--- 404,414 ----
  ** 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 ****
--- 435,443 ----
                           *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;
  
--- 458,468 ----
  
                        /* 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);
  
        /*
--- 486,495 ----
        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);
  
--- 528,535 ----
  
                /* 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;
--- 554,576 ----
        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);
  }
  
  /*
--- 578,584 ----
        /*
         * 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;
--- 597,612 ----
        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;
--- 627,640 ----
        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;
--- 647,662 ----
  {
        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)
        {
--- 712,737 ----
        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
--- 784,808 ----
        /*
         * 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;
--- 825,831 ----
  /* 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;
  
--- 904,998 ----
        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;
  
--- 1029,1062 ----
        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)
--- 1100,1132 ----
  }
  
  
+ 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
--- 1152,1158 ----
                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;
--- 1171,1244 ----
  }
  
  /* 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 ****
--- 1246,1258 ----
        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;
--- 1289,1301 ----
                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;
--- 1305,1319 ----
        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);
--- 1323,1348 ----
        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);
--- 1353,1378 ----
                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;
  }
--- 1383,1392 ----
                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 18 Jul 2006 15:31:43 -0000
***************
*** 9,14 ****
--- 9,18 ----
  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_out(cube)
  RETURNS cstring
  AS 'MODULE_PATHNAME'
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        18 Jul 2006 15:31:43 -0000
***************
*** 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;
--- 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)' ORDER BY c;
  
  -- Test sorting 
! SELECT * FROM test_cube       WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER 
BY c;
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

Reply via email to