Commit 796de9c1 authored by Bruce Momjian's avatar Bruce Momjian

/contrib/cube improvements:

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

New Functions:

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

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

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

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