diff --git a/contrib/cube/Makefile b/contrib/cube/Makefile
new file mode 100644
index 67f7867..e2a5d2c
*** a/contrib/cube/Makefile
--- b/contrib/cube/Makefile
*************** MODULE_big = cube
*** 4,10 ****
OBJS= cube.o cubeparse.o $(WIN32RES)
EXTENSION = cube
! DATA = cube--1.0.sql cube--unpackaged--1.0.sql
PGFILEDESC = "cube - multidimensional cube data type"
REGRESS = cube
--- 4,10 ----
OBJS= cube.o cubeparse.o $(WIN32RES)
EXTENSION = cube
! DATA = cube--1.1.sql cube--1.0--1.1.sql cube--unpackaged--1.0.sql
PGFILEDESC = "cube - multidimensional cube data type"
REGRESS = cube
diff --git a/contrib/cube/cube--1.0--1.1.sql b/contrib/cube/cube--1.0--1.1.sql
new file mode 100644
index ...f032f73
*** a/contrib/cube/cube--1.0--1.1.sql
--- b/contrib/cube/cube--1.0--1.1.sql
***************
*** 0 ****
--- 1,60 ----
+ /* contrib/cube/cube--1.0--1.1.sql */
+
+ -- complain if script is sourced in psql, rather than via ALTER EXTENSION
+ \echo Use "ALTER EXTENSION cube UPDATE TO '1.1'" to load this file. \quit
+
+ CREATE FUNCTION distance_chebyshev(cube, cube)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION distance_taxicab(cube, cube)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube_coord(cube, int4)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube_coord_llur(cube, int4)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE OPERATOR -> (
+ LEFTARG = cube, RIGHTARG = int, PROCEDURE = cube_coord
+ );
+
+ CREATE OPERATOR ~> (
+ LEFTARG = cube, RIGHTARG = int, PROCEDURE = cube_coord_llur
+ );
+
+ CREATE OPERATOR <#> (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = distance_taxicab,
+ COMMUTATOR = '<#>'
+ );
+
+ CREATE OPERATOR <-> (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_distance,
+ COMMUTATOR = '<->'
+ );
+
+ CREATE OPERATOR <=> (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = distance_chebyshev,
+ COMMUTATOR = '<=>'
+ );
+
+ CREATE FUNCTION g_cube_distance (internal, cube, smallint, oid)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ ALTER OPERATOR FAMILY gist_cube_ops USING gist ADD
+ OPERATOR 15 ~> (cube, int) FOR ORDER BY float_ops,
+ OPERATOR 16 <#> (cube, cube) FOR ORDER BY float_ops,
+ OPERATOR 17 <-> (cube, cube) FOR ORDER BY float_ops,
+ OPERATOR 18 <=> (cube, cube) FOR ORDER BY float_ops,
+ FUNCTION 8 (cube, cube) g_cube_distance (internal, cube, smallint, oid);
+
diff --git a/contrib/cube/cube--1.0.sql b/contrib/cube/cube--1.0.sql
new file mode .
index 0307811..e69de29
*** a/contrib/cube/cube--1.0.sql
--- b/contrib/cube/cube--1.0.sql
***************
*** 1,325 ****
- /* contrib/cube/cube--1.0.sql */
-
- -- complain if script is sourced in psql, rather than via CREATE EXTENSION
- \echo Use "CREATE EXTENSION cube" to load this file. \quit
-
- -- Create the user-defined type for N-dimensional boxes
-
- CREATE FUNCTION cube_in(cstring)
- RETURNS cube
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION cube(float8[], float8[]) RETURNS cube
- AS 'MODULE_PATHNAME', 'cube_a_f8_f8'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION cube(float8[]) RETURNS cube
- AS 'MODULE_PATHNAME', 'cube_a_f8'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION cube_out(cube)
- RETURNS cstring
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE TYPE cube (
- INTERNALLENGTH = variable,
- INPUT = cube_in,
- OUTPUT = cube_out,
- ALIGNMENT = double
- );
-
- COMMENT ON TYPE cube IS 'multi-dimensional cube ''(FLOAT-1, FLOAT-2, ..., FLOAT-N), (FLOAT-1, FLOAT-2, ..., FLOAT-N)''';
-
- --
- -- External C-functions for R-tree methods
- --
-
- -- Comparison methods
-
- CREATE FUNCTION cube_eq(cube, cube)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- COMMENT ON FUNCTION cube_eq(cube, cube) IS 'same as';
-
- CREATE FUNCTION cube_ne(cube, cube)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- COMMENT ON FUNCTION cube_ne(cube, cube) IS 'different';
-
- CREATE FUNCTION cube_lt(cube, cube)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- COMMENT ON FUNCTION cube_lt(cube, cube) IS 'lower than';
-
- CREATE FUNCTION cube_gt(cube, cube)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- COMMENT ON FUNCTION cube_gt(cube, cube) IS 'greater than';
-
- CREATE FUNCTION cube_le(cube, cube)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- COMMENT ON FUNCTION cube_le(cube, cube) IS 'lower than or equal to';
-
- CREATE FUNCTION cube_ge(cube, cube)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- COMMENT ON FUNCTION cube_ge(cube, cube) IS 'greater than or equal to';
-
- CREATE FUNCTION cube_cmp(cube, cube)
- RETURNS int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- COMMENT ON FUNCTION cube_cmp(cube, cube) IS 'btree comparison function';
-
- CREATE FUNCTION cube_contains(cube, cube)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- COMMENT ON FUNCTION cube_contains(cube, cube) IS 'contains';
-
- CREATE FUNCTION cube_contained(cube, cube)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- COMMENT ON FUNCTION cube_contained(cube, cube) IS 'contained in';
-
- CREATE FUNCTION cube_overlap(cube, cube)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- COMMENT ON FUNCTION cube_overlap(cube, cube) IS 'overlaps';
-
- -- support routines for indexing
-
- CREATE FUNCTION cube_union(cube, cube)
- RETURNS cube
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION cube_inter(cube, cube)
- RETURNS cube
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION cube_size(cube)
- RETURNS float8
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
-
- -- Misc N-dimensional functions
-
- CREATE FUNCTION cube_subset(cube, int4[])
- RETURNS cube
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- -- proximity routines
-
- CREATE FUNCTION cube_distance(cube, cube)
- RETURNS float8
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- -- Extracting elements functions
-
- CREATE FUNCTION cube_dim(cube)
- RETURNS int4
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION cube_ll_coord(cube, int4)
- RETURNS float8
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION cube_ur_coord(cube, int4)
- RETURNS float8
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION cube(float8) RETURNS cube
- AS 'MODULE_PATHNAME', 'cube_f8'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION cube(float8, float8) RETURNS cube
- AS 'MODULE_PATHNAME', 'cube_f8_f8'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION cube(cube, float8) RETURNS cube
- AS 'MODULE_PATHNAME', 'cube_c_f8'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION cube(cube, float8, float8) RETURNS cube
- AS 'MODULE_PATHNAME', 'cube_c_f8_f8'
- LANGUAGE C IMMUTABLE STRICT;
-
- -- Test if cube is also a point
-
- CREATE FUNCTION cube_is_point(cube)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- -- Increasing the size of a cube by a radius in at least n dimensions
-
- CREATE FUNCTION cube_enlarge(cube, float8, int4)
- RETURNS cube
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- --
- -- OPERATORS
- --
-
- CREATE OPERATOR < (
- LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_lt,
- COMMUTATOR = '>', NEGATOR = '>=',
- RESTRICT = scalarltsel, JOIN = scalarltjoinsel
- );
-
- CREATE OPERATOR > (
- LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_gt,
- COMMUTATOR = '<', NEGATOR = '<=',
- RESTRICT = scalargtsel, JOIN = scalargtjoinsel
- );
-
- CREATE OPERATOR <= (
- LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_le,
- COMMUTATOR = '>=', NEGATOR = '>',
- RESTRICT = scalarltsel, JOIN = scalarltjoinsel
- );
-
- CREATE OPERATOR >= (
- LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_ge,
- COMMUTATOR = '<=', NEGATOR = '<',
- RESTRICT = scalargtsel, JOIN = scalargtjoinsel
- );
-
- CREATE OPERATOR && (
- LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_overlap,
- COMMUTATOR = '&&',
- RESTRICT = areasel, JOIN = areajoinsel
- );
-
- CREATE OPERATOR = (
- LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_eq,
- COMMUTATOR = '=', NEGATOR = '<>',
- RESTRICT = eqsel, JOIN = eqjoinsel,
- MERGES
- );
-
- CREATE OPERATOR <> (
- LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_ne,
- COMMUTATOR = '<>', NEGATOR = '=',
- RESTRICT = neqsel, JOIN = neqjoinsel
- );
-
- CREATE OPERATOR @> (
- LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contains,
- COMMUTATOR = '<@',
- RESTRICT = contsel, JOIN = contjoinsel
- );
-
- CREATE OPERATOR <@ (
- LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contained,
- COMMUTATOR = '@>',
- RESTRICT = contsel, JOIN = contjoinsel
- );
-
- -- these are obsolete/deprecated:
- CREATE OPERATOR @ (
- LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contains,
- COMMUTATOR = '~',
- RESTRICT = contsel, JOIN = contjoinsel
- );
-
- CREATE OPERATOR ~ (
- LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contained,
- COMMUTATOR = '@',
- RESTRICT = contsel, JOIN = contjoinsel
- );
-
-
- -- define the GiST support methods
- CREATE FUNCTION g_cube_consistent(internal,cube,int,oid,internal)
- RETURNS bool
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION g_cube_compress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION g_cube_decompress(internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION g_cube_penalty(internal,internal,internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION g_cube_picksplit(internal, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION g_cube_union(internal, internal)
- RETURNS cube
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
- CREATE FUNCTION g_cube_same(cube, cube, internal)
- RETURNS internal
- AS 'MODULE_PATHNAME'
- LANGUAGE C IMMUTABLE STRICT;
-
-
- -- Create the operator classes for indexing
-
- CREATE OPERATOR CLASS cube_ops
- DEFAULT FOR TYPE cube USING btree AS
- OPERATOR 1 < ,
- OPERATOR 2 <= ,
- OPERATOR 3 = ,
- OPERATOR 4 >= ,
- OPERATOR 5 > ,
- FUNCTION 1 cube_cmp(cube, cube);
-
- CREATE OPERATOR CLASS gist_cube_ops
- DEFAULT FOR TYPE cube USING gist AS
- OPERATOR 3 && ,
- OPERATOR 6 = ,
- OPERATOR 7 @> ,
- OPERATOR 8 <@ ,
- OPERATOR 13 @ ,
- OPERATOR 14 ~ ,
- FUNCTION 1 g_cube_consistent (internal, cube, int, oid, internal),
- FUNCTION 2 g_cube_union (internal, internal),
- FUNCTION 3 g_cube_compress (internal),
- FUNCTION 4 g_cube_decompress (internal),
- FUNCTION 5 g_cube_penalty (internal, internal, internal),
- FUNCTION 6 g_cube_picksplit (internal, internal),
- FUNCTION 7 g_cube_same (cube, cube, internal);
--- 0 ----
diff --git a/contrib/cube/cube--1.1.sql b/contrib/cube/cube--1.1.sql
new file mode 100644
index ...c944414
*** a/contrib/cube/cube--1.1.sql
--- b/contrib/cube/cube--1.1.sql
***************
*** 0 ****
--- 1,379 ----
+ /* contrib/cube/cube--1.1.sql */
+
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION cube" to load this file. \quit
+
+ -- Create the user-defined type for N-dimensional boxes
+
+ CREATE FUNCTION cube_in(cstring)
+ RETURNS cube
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube(float8[], float8[]) RETURNS cube
+ AS 'MODULE_PATHNAME', 'cube_a_f8_f8'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube(float8[]) RETURNS cube
+ AS 'MODULE_PATHNAME', 'cube_a_f8'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube_out(cube)
+ RETURNS cstring
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE TYPE cube (
+ INTERNALLENGTH = variable,
+ INPUT = cube_in,
+ OUTPUT = cube_out,
+ ALIGNMENT = double
+ );
+
+ COMMENT ON TYPE cube IS 'multi-dimensional cube ''(FLOAT-1, FLOAT-2, ..., FLOAT-N), (FLOAT-1, FLOAT-2, ..., FLOAT-N)''';
+
+ --
+ -- External C-functions for R-tree methods
+ --
+
+ -- Comparison methods
+
+ CREATE FUNCTION cube_eq(cube, cube)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ COMMENT ON FUNCTION cube_eq(cube, cube) IS 'same as';
+
+ CREATE FUNCTION cube_ne(cube, cube)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ COMMENT ON FUNCTION cube_ne(cube, cube) IS 'different';
+
+ CREATE FUNCTION cube_lt(cube, cube)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ COMMENT ON FUNCTION cube_lt(cube, cube) IS 'lower than';
+
+ CREATE FUNCTION cube_gt(cube, cube)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ COMMENT ON FUNCTION cube_gt(cube, cube) IS 'greater than';
+
+ CREATE FUNCTION cube_le(cube, cube)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ COMMENT ON FUNCTION cube_le(cube, cube) IS 'lower than or equal to';
+
+ CREATE FUNCTION cube_ge(cube, cube)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ COMMENT ON FUNCTION cube_ge(cube, cube) IS 'greater than or equal to';
+
+ CREATE FUNCTION cube_cmp(cube, cube)
+ RETURNS int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ COMMENT ON FUNCTION cube_cmp(cube, cube) IS 'btree comparison function';
+
+ CREATE FUNCTION cube_contains(cube, cube)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ COMMENT ON FUNCTION cube_contains(cube, cube) IS 'contains';
+
+ CREATE FUNCTION cube_contained(cube, cube)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ COMMENT ON FUNCTION cube_contained(cube, cube) IS 'contained in';
+
+ CREATE FUNCTION cube_overlap(cube, cube)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ COMMENT ON FUNCTION cube_overlap(cube, cube) IS 'overlaps';
+
+ -- support routines for indexing
+
+ CREATE FUNCTION cube_union(cube, cube)
+ RETURNS cube
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube_inter(cube, cube)
+ RETURNS cube
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube_size(cube)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+
+ -- Misc N-dimensional functions
+
+ CREATE FUNCTION cube_subset(cube, int4[])
+ RETURNS cube
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ -- proximity routines
+
+ CREATE FUNCTION cube_distance(cube, cube)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION distance_chebyshev(cube, cube)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION distance_taxicab(cube, cube)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ -- Extracting elements functions
+
+ CREATE FUNCTION cube_dim(cube)
+ RETURNS int4
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube_ll_coord(cube, int4)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube_ur_coord(cube, int4)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube_coord(cube, int4)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube_coord_llur(cube, int4)
+ RETURNS float8
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube(float8) RETURNS cube
+ AS 'MODULE_PATHNAME', 'cube_f8'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube(float8, float8) RETURNS cube
+ AS 'MODULE_PATHNAME', 'cube_f8_f8'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube(cube, float8) RETURNS cube
+ AS 'MODULE_PATHNAME', 'cube_c_f8'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION cube(cube, float8, float8) RETURNS cube
+ AS 'MODULE_PATHNAME', 'cube_c_f8_f8'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ -- Test if cube is also a point
+
+ CREATE FUNCTION cube_is_point(cube)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ -- Increasing the size of a cube by a radius in at least n dimensions
+
+ CREATE FUNCTION cube_enlarge(cube, float8, int4)
+ RETURNS cube
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ --
+ -- OPERATORS
+ --
+
+ CREATE OPERATOR < (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_lt,
+ COMMUTATOR = '>', NEGATOR = '>=',
+ RESTRICT = scalarltsel, JOIN = scalarltjoinsel
+ );
+
+ CREATE OPERATOR > (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_gt,
+ COMMUTATOR = '<', NEGATOR = '<=',
+ RESTRICT = scalargtsel, JOIN = scalargtjoinsel
+ );
+
+ CREATE OPERATOR <= (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_le,
+ COMMUTATOR = '>=', NEGATOR = '>',
+ RESTRICT = scalarltsel, JOIN = scalarltjoinsel
+ );
+
+ CREATE OPERATOR >= (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_ge,
+ COMMUTATOR = '<=', NEGATOR = '<',
+ RESTRICT = scalargtsel, JOIN = scalargtjoinsel
+ );
+
+ CREATE OPERATOR && (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_overlap,
+ COMMUTATOR = '&&',
+ RESTRICT = areasel, JOIN = areajoinsel
+ );
+
+ CREATE OPERATOR = (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_eq,
+ COMMUTATOR = '=', NEGATOR = '<>',
+ RESTRICT = eqsel, JOIN = eqjoinsel,
+ MERGES
+ );
+
+ CREATE OPERATOR <> (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_ne,
+ COMMUTATOR = '<>', NEGATOR = '=',
+ RESTRICT = neqsel, JOIN = neqjoinsel
+ );
+
+ CREATE OPERATOR @> (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contains,
+ COMMUTATOR = '<@',
+ RESTRICT = contsel, JOIN = contjoinsel
+ );
+
+ CREATE OPERATOR <@ (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contained,
+ COMMUTATOR = '@>',
+ RESTRICT = contsel, JOIN = contjoinsel
+ );
+
+ CREATE OPERATOR -> (
+ LEFTARG = cube, RIGHTARG = int, PROCEDURE = cube_coord
+ );
+
+ CREATE OPERATOR ~> (
+ LEFTARG = cube, RIGHTARG = int, PROCEDURE = cube_coord_llur
+ );
+
+ CREATE OPERATOR <#> (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = distance_taxicab,
+ COMMUTATOR = '<#>'
+ );
+
+ CREATE OPERATOR <-> (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_distance,
+ COMMUTATOR = '<->'
+ );
+
+ CREATE OPERATOR <=> (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = distance_chebyshev,
+ COMMUTATOR = '<=>'
+ );
+
+ -- these are obsolete/deprecated:
+ CREATE OPERATOR @ (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contains,
+ COMMUTATOR = '~',
+ RESTRICT = contsel, JOIN = contjoinsel
+ );
+
+ CREATE OPERATOR ~ (
+ LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contained,
+ COMMUTATOR = '@',
+ RESTRICT = contsel, JOIN = contjoinsel
+ );
+
+
+ -- define the GiST support methods
+ CREATE FUNCTION g_cube_consistent(internal,cube,int,oid,internal)
+ RETURNS bool
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION g_cube_compress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION g_cube_decompress(internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION g_cube_penalty(internal,internal,internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION g_cube_picksplit(internal, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION g_cube_union(internal, internal)
+ RETURNS cube
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION g_cube_same(cube, cube, internal)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ CREATE FUNCTION g_cube_distance (internal, cube, smallint, oid)
+ RETURNS internal
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C IMMUTABLE STRICT;
+
+ -- Create the operator classes for indexing
+
+ CREATE OPERATOR CLASS cube_ops
+ DEFAULT FOR TYPE cube USING btree AS
+ OPERATOR 1 < ,
+ OPERATOR 2 <= ,
+ OPERATOR 3 = ,
+ OPERATOR 4 >= ,
+ OPERATOR 5 > ,
+ FUNCTION 1 cube_cmp(cube, cube);
+
+ CREATE OPERATOR CLASS gist_cube_ops
+ DEFAULT FOR TYPE cube USING gist AS
+ OPERATOR 3 && ,
+ OPERATOR 6 = ,
+ OPERATOR 7 @> ,
+ OPERATOR 8 <@ ,
+ OPERATOR 13 @ ,
+ OPERATOR 14 ~ ,
+ OPERATOR 15 ~> (cube, int) FOR ORDER BY float_ops,
+ OPERATOR 16 <#> (cube, cube) FOR ORDER BY float_ops,
+ OPERATOR 17 <-> (cube, cube) FOR ORDER BY float_ops,
+ OPERATOR 18 <=> (cube, cube) FOR ORDER BY float_ops,
+
+ FUNCTION 1 g_cube_consistent (internal, cube, int, oid, internal),
+ FUNCTION 2 g_cube_union (internal, internal),
+ FUNCTION 3 g_cube_compress (internal),
+ FUNCTION 4 g_cube_decompress (internal),
+ FUNCTION 5 g_cube_penalty (internal, internal, internal),
+ FUNCTION 6 g_cube_picksplit (internal, internal),
+ FUNCTION 7 g_cube_same (cube, cube, internal),
+ FUNCTION 8 g_cube_distance (internal, cube, smallint, oid);
+
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
new file mode 100644
index a6be59e..676d9a9
*** a/contrib/cube/cube.c
--- b/contrib/cube/cube.c
*************** PG_FUNCTION_INFO_V1(cube_c_f8_f8);
*** 40,45 ****
--- 40,47 ----
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_coord);
+ PG_FUNCTION_INFO_V1(cube_coord_llur);
PG_FUNCTION_INFO_V1(cube_subset);
/*
*************** PG_FUNCTION_INFO_V1(g_cube_penalty);
*** 53,58 ****
--- 55,62 ----
PG_FUNCTION_INFO_V1(g_cube_picksplit);
PG_FUNCTION_INFO_V1(g_cube_union);
PG_FUNCTION_INFO_V1(g_cube_same);
+ PG_FUNCTION_INFO_V1(g_cube_distance);
+
/*
** B-tree support functions
*************** PG_FUNCTION_INFO_V1(cube_size);
*** 79,85 ****
--- 83,91 ----
/*
** miscellaneous
*/
+ PG_FUNCTION_INFO_V1(distance_taxicab);
PG_FUNCTION_INFO_V1(cube_distance);
+ PG_FUNCTION_INFO_V1(distance_chebyshev);
PG_FUNCTION_INFO_V1(cube_is_point);
PG_FUNCTION_INFO_V1(cube_enlarge);
*************** cube_overlap(PG_FUNCTION_ARGS)
*** 1202,1208 ****
PG_RETURN_BOOL(res);
}
-
/* 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
--- 1208,1213 ----
*************** cube_distance(PG_FUNCTION_ARGS)
*** 1257,1262 ****
--- 1262,1405 ----
PG_RETURN_FLOAT8(sqrt(distance));
}
+ Datum
+ distance_taxicab(PG_FUNCTION_ARGS)
+ {
+ NDBOX *a = PG_GETARG_NDBOX(0),
+ *b = PG_GETARG_NDBOX(1);
+ bool swapped = false;
+ double distance;
+ int i;
+
+ /* swap the box pointers if needed */
+ if (DIM(a) < DIM(b))
+ {
+ NDBOX *tmp = b;
+ b = a;
+ a = tmp;
+ swapped = true;
+ }
+
+ distance = 0.0;
+ /* compute within the dimensions of (b) */
+ for (i = 0; i < DIM(b); i++)
+ distance += fabs(distance_1D(LL_COORD(a,i), UR_COORD(a,i), LL_COORD(b,i), UR_COORD(b,i)));
+
+ /* compute distance to zero for those dimensions in (a) absent in (b) */
+ for (i = DIM(b); i < DIM(a); i++)
+ distance += fabs(distance_1D(LL_COORD(a,i), UR_COORD(a,i), 0.0, 0.0));
+
+ if (swapped)
+ {
+ PG_FREE_IF_COPY(b, 0);
+ PG_FREE_IF_COPY(a, 1);
+ }
+ else
+ {
+ PG_FREE_IF_COPY(a, 0);
+ PG_FREE_IF_COPY(b, 1);
+ }
+
+ PG_RETURN_FLOAT8(distance);
+ }
+
+ Datum
+ distance_chebyshev(PG_FUNCTION_ARGS)
+ {
+ NDBOX *a = PG_GETARG_NDBOX(0),
+ *b = PG_GETARG_NDBOX(1);
+ bool swapped = false;
+ double d, distance;
+ int i;
+
+ /* swap the box pointers if needed */
+ if (DIM(a) < DIM(b))
+ {
+ NDBOX *tmp = b;
+ b = a;
+ a = tmp;
+ swapped = true;
+ }
+
+ distance = 0.0;
+ /* compute within the dimensions of (b) */
+ for (i = 0; i < DIM(b); i++)
+ {
+ d = fabs(distance_1D(LL_COORD(a,i), UR_COORD(a,i), LL_COORD(b,i), UR_COORD(b,i)));
+ if (d > distance)
+ distance = d;
+ }
+
+ /* compute distance to zero for those dimensions in (a) absent in (b) */
+ for (i = DIM(b); i < DIM(a); i++)
+ {
+ d = fabs(distance_1D(LL_COORD(a,i), UR_COORD(a,i), 0.0, 0.0));
+ if (d > distance)
+ distance = d;
+ }
+
+ if (swapped)
+ {
+ PG_FREE_IF_COPY(b, 0);
+ PG_FREE_IF_COPY(a, 1);
+ }
+ else
+ {
+ PG_FREE_IF_COPY(a, 0);
+ PG_FREE_IF_COPY(b, 1);
+ }
+
+ PG_RETURN_FLOAT8(distance);
+ }
+
+ Datum
+ g_cube_distance(PG_FUNCTION_ARGS)
+ {
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+ NDBOX *cube = DatumGetNDBOX(entry->key);
+ double retval;
+
+ if (strategy == CubeKNNDistanceCoord)
+ {
+ int coord = PG_GETARG_INT32(1);
+
+ if IS_POINT(cube)
+ {
+ retval = (cube)->x[(coord-1)%DIM(cube)];
+ }
+ else
+ {
+ retval = Min(
+ (cube)->x[(coord-1)%DIM(cube)],
+ (cube)->x[(coord-1)%DIM(cube) + DIM(cube)]
+ );
+ }
+ }
+ else
+ {
+ NDBOX *query = PG_GETARG_NDBOX(1);
+ switch(strategy)
+ {
+ case CubeKNNDistanceTaxicab:
+ retval = DatumGetFloat8(DirectFunctionCall2(distance_taxicab,
+ PointerGetDatum(cube), PointerGetDatum(query)));
+ break;
+ case CubeKNNDistanceEuclid:
+ retval = DatumGetFloat8(DirectFunctionCall2(cube_distance,
+ PointerGetDatum(cube), PointerGetDatum(query)));
+ break;
+ case CubeKNNDistanceChebyshev:
+ retval = DatumGetFloat8(DirectFunctionCall2(distance_chebyshev,
+ PointerGetDatum(cube), PointerGetDatum(query)));
+ break;
+ default:
+ elog(ERROR, "Cube: unknown strategy number.");
+ }
+ }
+ PG_RETURN_FLOAT8(retval);
+ }
+
static double
distance_1D(double a1, double a2, double b1, double b2)
{
*************** cube_ur_coord(PG_FUNCTION_ARGS)
*** 1352,1357 ****
--- 1495,1565 ----
PG_RETURN_FLOAT8(result);
}
+ /*
+ * Function returns cube coordinate.
+ * Numbers from 1 to DIM denotes first corner coordinates.
+ * Numbers from DIM+1 to 2*DIM denotes second corner coordinates.
+ */
+ Datum
+ cube_coord(PG_FUNCTION_ARGS)
+ {
+ NDBOX *cube = PG_GETARG_NDBOX(0);
+ int coord = PG_GETARG_INT16(1);
+
+ if ((coord > 0) && (coord <= 2*DIM(cube)))
+ {
+ if IS_POINT(cube)
+ PG_RETURN_FLOAT8( (cube)->x[(coord-1)%DIM(cube)] );
+ else
+ PG_RETURN_FLOAT8( (cube)->x[coord-1] );
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
+ errmsg("Cube index out of bounds")));
+ }
+ }
+
+
+ /*
+ * This function works like cube_coord(),
+ * but rearranges coordinates of corners to get cube representation
+ * in the form of (lower left, upper right).
+ * For historical reasons that extension allows us to create cubes in form
+ * ((2,1),(1,2)) and instead of normalizing such cube to ((1,1),(2,2)) it
+ * stores cube in original way. But to get cubes ordered by one of dimensions
+ * directly from the index without extra sort step we need some
+ * representation-independent coordinate getter. This function implements it.
+ */
+ Datum
+ cube_coord_llur(PG_FUNCTION_ARGS)
+ {
+ NDBOX *cube = PG_GETARG_NDBOX(0);
+ int coord = PG_GETARG_INT16(1);
+
+ if ((coord > 0) && (coord <= DIM(cube)))
+ {
+ if IS_POINT(cube)
+ PG_RETURN_FLOAT8( (cube)->x[coord-1] );
+ else
+ PG_RETURN_FLOAT8( Min((cube)->x[coord-1], (cube)->x[coord-1+DIM(cube)]) );
+ }
+ else if ((coord > DIM(cube)) && (coord <= 2*DIM(cube)))
+ {
+ if IS_POINT(cube)
+ PG_RETURN_FLOAT8( (cube)->x[(coord-1)%DIM(cube)] );
+ else
+ PG_RETURN_FLOAT8( Max((cube)->x[coord-1], (cube)->x[coord-1-DIM(cube)]) );
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
+ errmsg("Cube index out of bounds")));
+ }
+ }
+
/* Increase or decrease box size by a radius in at least n dimensions. */
Datum
cube_enlarge(PG_FUNCTION_ARGS)
diff --git a/contrib/cube/cube.control b/contrib/cube/cube.control
new file mode 100644
index ddc8d2e..f84e6c5
*** a/contrib/cube/cube.control
--- b/contrib/cube/cube.control
***************
*** 1,5 ****
# cube extension
comment = 'data type for multidimensional cubes'
! default_version = '1.0'
module_pathname = '$libdir/cube'
relocatable = true
--- 1,5 ----
# cube extension
comment = 'data type for multidimensional cubes'
! default_version = '1.1'
module_pathname = '$libdir/cube'
relocatable = true
diff --git a/contrib/cube/cubedata.h b/contrib/cube/cubedata.h
new file mode 100644
index 59c23de..7eaac39
*** a/contrib/cube/cubedata.h
--- b/contrib/cube/cubedata.h
*************** typedef struct NDBOX
*** 47,52 ****
--- 47,57 ----
#define PG_GETARG_NDBOX(x) DatumGetNDBOX(PG_GETARG_DATUM(x))
#define PG_RETURN_NDBOX(x) PG_RETURN_POINTER(x)
+ #define CubeKNNDistanceCoord 15 /* ~> */
+ #define CubeKNNDistanceTaxicab 16 /* <#> */
+ #define CubeKNNDistanceEuclid 17 /* <-> */
+ #define CubeKNNDistanceChebyshev 18 /* <=> */
+
/* in cubescan.l */
extern int cube_yylex(void);
extern void cube_yyerror(NDBOX **result, const char *message) pg_attribute_noreturn();
diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out
new file mode 100644
index ca9555e..4b2d135
*** a/contrib/cube/expected/cube.out
--- b/contrib/cube/expected/cube.out
*************** SELECT cube_size('(42,137)'::cube);
*** 1381,1386 ****
--- 1381,1531 ----
0
(1 row)
+ -- Test of distances
+ --
+ SELECT cube_distance('(1,1)'::cube, '(4,5)'::cube);
+ cube_distance
+ ---------------
+ 5
+ (1 row)
+
+ SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e;
+ d_e
+ -----
+ 5
+ (1 row)
+
+ SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube);
+ distance_chebyshev
+ --------------------
+ 4
+ (1 row)
+
+ SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c;
+ d_c
+ -----
+ 4
+ (1 row)
+
+ SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube);
+ distance_taxicab
+ ------------------
+ 7
+ (1 row)
+
+ SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t;
+ d_t
+ -----
+ 7
+ (1 row)
+
+ -- zero for overlapping
+ SELECT cube_distance('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ cube_distance
+ ---------------
+ 0
+ (1 row)
+
+ SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ distance_chebyshev
+ --------------------
+ 0
+ (1 row)
+
+ SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ distance_taxicab
+ ------------------
+ 0
+ (1 row)
+
+ -- coordinate access
+ SELECT cube(array[10,20,30], array[40,50,60])->1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])->1;
+ ?column?
+ ----------
+ 40
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])->6;
+ ?column?
+ ----------
+ 60
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])->0;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->7;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->-1;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->-6;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30])->3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[10,20,30])->6;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[10,20,30])->-6;
+ ERROR: Cube index out of bounds
+ -- "normalized" coordinate access
+ SELECT cube(array[10,20,30], array[40,50,60])~>1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])~>2;
+ ?column?
+ ----------
+ 20
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>2;
+ ?column?
+ ----------
+ 20
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])~>3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>0;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[40,50,60], array[10,20,30])~>4;
+ ?column?
+ ----------
+ 40
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
+ ERROR: Cube index out of bounds
-- Load some example data and build the index
--
CREATE TABLE test_cube (c cube);
*************** SELECT * FROM test_cube WHERE c && '(300
*** 1407,1409 ****
--- 1552,1710 ----
(2424, 160),(2424, 81)
(5 rows)
+ -- kNN with index
+ SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------------------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (948, 1201),(907, 1156) | 772.000647668122
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (5 rows)
+
+ SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (948, 1201),(907, 1156) | 656
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (5 rows)
+
+ SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (948, 1201),(907, 1156) | 1063
+ (5 rows)
+
+ -- kNN-based sorting
+ SELECT * FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by 1st coordinate of lower left corner
+ c
+ ---------------------------
+ (54, 38679),(3, 38602)
+ (83, 10271),(15, 10265)
+ (122, 46832),(64, 46762)
+ (167, 17214),(92, 17184)
+ (161, 24465),(107, 24374)
+ (162, 26040),(120, 25963)
+ (154, 4019),(138, 3990)
+ (259, 1850),(175, 1820)
+ (207, 40886),(179, 40879)
+ (288, 49588),(204, 49571)
+ (270, 32616),(226, 32607)
+ (318, 31489),(235, 31404)
+ (337, 455),(240, 359)
+ (270, 29508),(264, 29440)
+ (369, 1457),(278, 1409)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by 2nd coordinate or upper right corner
+ c
+ ---------------------------
+ (30333, 50),(30273, 6)
+ (43301, 75),(43227, 43)
+ (19650, 142),(19630, 51)
+ (2424, 160),(2424, 81)
+ (3449, 171),(3354, 108)
+ (18037, 155),(17941, 109)
+ (28511, 208),(28479, 114)
+ (19946, 217),(19941, 118)
+ (16906, 191),(16816, 139)
+ (759, 187),(662, 163)
+ (22684, 266),(22656, 181)
+ (24423, 255),(24360, 213)
+ (45989, 249),(45910, 222)
+ (11399, 377),(11360, 294)
+ (12162, 389),(12103, 309)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>1 DESC LIMIT 15; -- descending by 1st coordinate of lower left corner
+ c
+ -------------------------------
+ (50027, 49230),(49951, 49214)
+ (49980, 35004),(49937, 34963)
+ (49985, 6436),(49927, 6338)
+ (49999, 27218),(49908, 27176)
+ (49954, 1340),(49905, 1294)
+ (49944, 25163),(49902, 25153)
+ (49981, 34876),(49898, 34786)
+ (49957, 43390),(49897, 43384)
+ (49853, 18504),(49848, 18503)
+ (49902, 41752),(49818, 41746)
+ (49907, 30225),(49810, 30158)
+ (49843, 5175),(49808, 5145)
+ (49887, 24274),(49805, 24184)
+ (49847, 7128),(49798, 7067)
+ (49820, 7990),(49771, 7967)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>4 DESC LIMIT 15; -- descending by 2nd coordinate or upper right corner
+ c
+ -------------------------------
+ (36311, 50073),(36258, 49987)
+ (30746, 50040),(30727, 49992)
+ (2168, 50012),(2108, 49914)
+ (21551, 49983),(21492, 49885)
+ (17954, 49975),(17865, 49915)
+ (3531, 49962),(3463, 49934)
+ (19128, 49932),(19112, 49849)
+ (31287, 49923),(31236, 49913)
+ (43925, 49912),(43888, 49878)
+ (29261, 49910),(29247, 49818)
+ (14913, 49873),(14849, 49836)
+ (20007, 49858),(19921, 49778)
+ (38266, 49852),(38233, 49844)
+ (37595, 49849),(37581, 49834)
+ (46151, 49848),(46058, 49830)
+ (15 rows)
+
+ -- same thing for index with points
+ CREATE TABLE test_point(c cube);
+ INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube);
+ CREATE INDEX ON test_point USING gist(c);
+ SELECT * FROM test_point ORDER BY c~>1, c~>2 LIMIT 15; -- ascending by 1st then by 2nd coordinate
+ c
+ --------------------------
+ (54, 38679, 3, 38602)
+ (83, 10271, 15, 10265)
+ (122, 46832, 64, 46762)
+ (154, 4019, 138, 3990)
+ (161, 24465, 107, 24374)
+ (162, 26040, 120, 25963)
+ (167, 17214, 92, 17184)
+ (207, 40886, 179, 40879)
+ (259, 1850, 175, 1820)
+ (270, 29508, 264, 29440)
+ (270, 32616, 226, 32607)
+ (288, 49588, 204, 49571)
+ (318, 31489, 235, 31404)
+ (326, 18837, 285, 18817)
+ (337, 455, 240, 359)
+ (15 rows)
+
+ SELECT * FROM test_point ORDER BY c~>4 DESC LIMIT 15; -- descending by 1st coordinate
+ c
+ ------------------------------
+ (30746, 50040, 30727, 49992)
+ (36311, 50073, 36258, 49987)
+ (3531, 49962, 3463, 49934)
+ (17954, 49975, 17865, 49915)
+ (2168, 50012, 2108, 49914)
+ (31287, 49923, 31236, 49913)
+ (21551, 49983, 21492, 49885)
+ (43925, 49912, 43888, 49878)
+ (19128, 49932, 19112, 49849)
+ (38266, 49852, 38233, 49844)
+ (14913, 49873, 14849, 49836)
+ (37595, 49849, 37581, 49834)
+ (46151, 49848, 46058, 49830)
+ (29261, 49910, 29247, 49818)
+ (19233, 49824, 19185, 49794)
+ (15 rows)
+
diff --git a/contrib/cube/expected/cube_1.out b/contrib/cube/expected/cube_1.out
new file mode 100644
index c07d61d..7178088
*** a/contrib/cube/expected/cube_1.out
--- b/contrib/cube/expected/cube_1.out
*************** SELECT cube_size('(42,137)'::cube);
*** 1381,1386 ****
--- 1381,1531 ----
0
(1 row)
+ -- Test of distances
+ --
+ SELECT cube_distance('(1,1)'::cube, '(4,5)'::cube);
+ cube_distance
+ ---------------
+ 5
+ (1 row)
+
+ SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e;
+ d_e
+ -----
+ 5
+ (1 row)
+
+ SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube);
+ distance_chebyshev
+ --------------------
+ 4
+ (1 row)
+
+ SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c;
+ d_c
+ -----
+ 4
+ (1 row)
+
+ SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube);
+ distance_taxicab
+ ------------------
+ 7
+ (1 row)
+
+ SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t;
+ d_t
+ -----
+ 7
+ (1 row)
+
+ -- zero for overlapping
+ SELECT cube_distance('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ cube_distance
+ ---------------
+ 0
+ (1 row)
+
+ SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ distance_chebyshev
+ --------------------
+ 0
+ (1 row)
+
+ SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ distance_taxicab
+ ------------------
+ 0
+ (1 row)
+
+ -- coordinate access
+ SELECT cube(array[10,20,30], array[40,50,60])->1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])->1;
+ ?column?
+ ----------
+ 40
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])->6;
+ ?column?
+ ----------
+ 60
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])->0;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->7;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->-1;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->-6;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30])->3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[10,20,30])->6;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[10,20,30])->-6;
+ ERROR: Cube index out of bounds
+ -- "normalized" coordinate access
+ SELECT cube(array[10,20,30], array[40,50,60])~>1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])~>2;
+ ?column?
+ ----------
+ 20
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>2;
+ ?column?
+ ----------
+ 20
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])~>3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>0;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[40,50,60], array[10,20,30])~>4;
+ ?column?
+ ----------
+ 40
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
+ ERROR: Cube index out of bounds
-- Load some example data and build the index
--
CREATE TABLE test_cube (c cube);
*************** SELECT * FROM test_cube WHERE c && '(300
*** 1407,1409 ****
--- 1552,1710 ----
(2424, 160),(2424, 81)
(5 rows)
+ -- kNN with index
+ SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------------------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (948, 1201),(907, 1156) | 772.000647668122
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (5 rows)
+
+ SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (948, 1201),(907, 1156) | 656
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (5 rows)
+
+ SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (948, 1201),(907, 1156) | 1063
+ (5 rows)
+
+ -- kNN-based sorting
+ SELECT * FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by 1st coordinate of lower left corner
+ c
+ ---------------------------
+ (54, 38679),(3, 38602)
+ (83, 10271),(15, 10265)
+ (122, 46832),(64, 46762)
+ (167, 17214),(92, 17184)
+ (161, 24465),(107, 24374)
+ (162, 26040),(120, 25963)
+ (154, 4019),(138, 3990)
+ (259, 1850),(175, 1820)
+ (207, 40886),(179, 40879)
+ (288, 49588),(204, 49571)
+ (270, 32616),(226, 32607)
+ (318, 31489),(235, 31404)
+ (337, 455),(240, 359)
+ (270, 29508),(264, 29440)
+ (369, 1457),(278, 1409)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by 2nd coordinate or upper right corner
+ c
+ ---------------------------
+ (30333, 50),(30273, 6)
+ (43301, 75),(43227, 43)
+ (19650, 142),(19630, 51)
+ (2424, 160),(2424, 81)
+ (3449, 171),(3354, 108)
+ (18037, 155),(17941, 109)
+ (28511, 208),(28479, 114)
+ (19946, 217),(19941, 118)
+ (16906, 191),(16816, 139)
+ (759, 187),(662, 163)
+ (22684, 266),(22656, 181)
+ (24423, 255),(24360, 213)
+ (45989, 249),(45910, 222)
+ (11399, 377),(11360, 294)
+ (12162, 389),(12103, 309)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>1 DESC LIMIT 15; -- descending by 1st coordinate of lower left corner
+ c
+ -------------------------------
+ (50027, 49230),(49951, 49214)
+ (49980, 35004),(49937, 34963)
+ (49985, 6436),(49927, 6338)
+ (49999, 27218),(49908, 27176)
+ (49954, 1340),(49905, 1294)
+ (49944, 25163),(49902, 25153)
+ (49981, 34876),(49898, 34786)
+ (49957, 43390),(49897, 43384)
+ (49853, 18504),(49848, 18503)
+ (49902, 41752),(49818, 41746)
+ (49907, 30225),(49810, 30158)
+ (49843, 5175),(49808, 5145)
+ (49887, 24274),(49805, 24184)
+ (49847, 7128),(49798, 7067)
+ (49820, 7990),(49771, 7967)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>4 DESC LIMIT 15; -- descending by 2nd coordinate or upper right corner
+ c
+ -------------------------------
+ (36311, 50073),(36258, 49987)
+ (30746, 50040),(30727, 49992)
+ (2168, 50012),(2108, 49914)
+ (21551, 49983),(21492, 49885)
+ (17954, 49975),(17865, 49915)
+ (3531, 49962),(3463, 49934)
+ (19128, 49932),(19112, 49849)
+ (31287, 49923),(31236, 49913)
+ (43925, 49912),(43888, 49878)
+ (29261, 49910),(29247, 49818)
+ (14913, 49873),(14849, 49836)
+ (20007, 49858),(19921, 49778)
+ (38266, 49852),(38233, 49844)
+ (37595, 49849),(37581, 49834)
+ (46151, 49848),(46058, 49830)
+ (15 rows)
+
+ -- same thing for index with points
+ CREATE TABLE test_point(c cube);
+ INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube);
+ CREATE INDEX ON test_point USING gist(c);
+ SELECT * FROM test_point ORDER BY c~>1, c~>2 LIMIT 15; -- ascending by 1st then by 2nd coordinate
+ c
+ --------------------------
+ (54, 38679, 3, 38602)
+ (83, 10271, 15, 10265)
+ (122, 46832, 64, 46762)
+ (154, 4019, 138, 3990)
+ (161, 24465, 107, 24374)
+ (162, 26040, 120, 25963)
+ (167, 17214, 92, 17184)
+ (207, 40886, 179, 40879)
+ (259, 1850, 175, 1820)
+ (270, 29508, 264, 29440)
+ (270, 32616, 226, 32607)
+ (288, 49588, 204, 49571)
+ (318, 31489, 235, 31404)
+ (326, 18837, 285, 18817)
+ (337, 455, 240, 359)
+ (15 rows)
+
+ SELECT * FROM test_point ORDER BY c~>4 DESC LIMIT 15; -- descending by 1st coordinate
+ c
+ ------------------------------
+ (30746, 50040, 30727, 49992)
+ (36311, 50073, 36258, 49987)
+ (3531, 49962, 3463, 49934)
+ (17954, 49975, 17865, 49915)
+ (2168, 50012, 2108, 49914)
+ (31287, 49923, 31236, 49913)
+ (21551, 49983, 21492, 49885)
+ (43925, 49912, 43888, 49878)
+ (19128, 49932, 19112, 49849)
+ (38266, 49852, 38233, 49844)
+ (14913, 49873, 14849, 49836)
+ (37595, 49849, 37581, 49834)
+ (46151, 49848, 46058, 49830)
+ (29261, 49910, 29247, 49818)
+ (19233, 49824, 19185, 49794)
+ (15 rows)
+
diff --git a/contrib/cube/expected/cube_2.out b/contrib/cube/expected/cube_2.out
new file mode 100644
index 3767d0e..a6c7d36
*** a/contrib/cube/expected/cube_2.out
--- b/contrib/cube/expected/cube_2.out
*************** SELECT cube_size('(42,137)'::cube);
*** 1381,1386 ****
--- 1381,1531 ----
0
(1 row)
+ -- Test of distances
+ --
+ SELECT cube_distance('(1,1)'::cube, '(4,5)'::cube);
+ cube_distance
+ ---------------
+ 5
+ (1 row)
+
+ SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e;
+ d_e
+ -----
+ 5
+ (1 row)
+
+ SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube);
+ distance_chebyshev
+ --------------------
+ 4
+ (1 row)
+
+ SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c;
+ d_c
+ -----
+ 4
+ (1 row)
+
+ SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube);
+ distance_taxicab
+ ------------------
+ 7
+ (1 row)
+
+ SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t;
+ d_t
+ -----
+ 7
+ (1 row)
+
+ -- zero for overlapping
+ SELECT cube_distance('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ cube_distance
+ ---------------
+ 0
+ (1 row)
+
+ SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ distance_chebyshev
+ --------------------
+ 0
+ (1 row)
+
+ SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ distance_taxicab
+ ------------------
+ 0
+ (1 row)
+
+ -- coordinate access
+ SELECT cube(array[10,20,30], array[40,50,60])->1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])->1;
+ ?column?
+ ----------
+ 40
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])->6;
+ ?column?
+ ----------
+ 60
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])->0;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->7;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->-1;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->-6;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30])->3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[10,20,30])->6;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[10,20,30])->-6;
+ ERROR: Cube index out of bounds
+ -- "normalized" coordinate access
+ SELECT cube(array[10,20,30], array[40,50,60])~>1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])~>2;
+ ?column?
+ ----------
+ 20
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>2;
+ ?column?
+ ----------
+ 20
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])~>3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>0;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[40,50,60], array[10,20,30])~>4;
+ ?column?
+ ----------
+ 40
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
+ ERROR: Cube index out of bounds
-- Load some example data and build the index
--
CREATE TABLE test_cube (c cube);
*************** SELECT * FROM test_cube WHERE c && '(300
*** 1407,1409 ****
--- 1552,1710 ----
(2424, 160),(2424, 81)
(5 rows)
+ -- kNN with index
+ SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------------------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (948, 1201),(907, 1156) | 772.000647668122
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (5 rows)
+
+ SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (948, 1201),(907, 1156) | 656
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (5 rows)
+
+ SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (948, 1201),(907, 1156) | 1063
+ (5 rows)
+
+ -- kNN-based sorting
+ SELECT * FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by 1st coordinate of lower left corner
+ c
+ ---------------------------
+ (54, 38679),(3, 38602)
+ (83, 10271),(15, 10265)
+ (122, 46832),(64, 46762)
+ (167, 17214),(92, 17184)
+ (161, 24465),(107, 24374)
+ (162, 26040),(120, 25963)
+ (154, 4019),(138, 3990)
+ (259, 1850),(175, 1820)
+ (207, 40886),(179, 40879)
+ (288, 49588),(204, 49571)
+ (270, 32616),(226, 32607)
+ (318, 31489),(235, 31404)
+ (337, 455),(240, 359)
+ (270, 29508),(264, 29440)
+ (369, 1457),(278, 1409)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by 2nd coordinate or upper right corner
+ c
+ ---------------------------
+ (30333, 50),(30273, 6)
+ (43301, 75),(43227, 43)
+ (19650, 142),(19630, 51)
+ (2424, 160),(2424, 81)
+ (3449, 171),(3354, 108)
+ (18037, 155),(17941, 109)
+ (28511, 208),(28479, 114)
+ (19946, 217),(19941, 118)
+ (16906, 191),(16816, 139)
+ (759, 187),(662, 163)
+ (22684, 266),(22656, 181)
+ (24423, 255),(24360, 213)
+ (45989, 249),(45910, 222)
+ (11399, 377),(11360, 294)
+ (12162, 389),(12103, 309)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>1 DESC LIMIT 15; -- descending by 1st coordinate of lower left corner
+ c
+ -------------------------------
+ (50027, 49230),(49951, 49214)
+ (49980, 35004),(49937, 34963)
+ (49985, 6436),(49927, 6338)
+ (49999, 27218),(49908, 27176)
+ (49954, 1340),(49905, 1294)
+ (49944, 25163),(49902, 25153)
+ (49981, 34876),(49898, 34786)
+ (49957, 43390),(49897, 43384)
+ (49853, 18504),(49848, 18503)
+ (49902, 41752),(49818, 41746)
+ (49907, 30225),(49810, 30158)
+ (49843, 5175),(49808, 5145)
+ (49887, 24274),(49805, 24184)
+ (49847, 7128),(49798, 7067)
+ (49820, 7990),(49771, 7967)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>4 DESC LIMIT 15; -- descending by 2nd coordinate or upper right corner
+ c
+ -------------------------------
+ (36311, 50073),(36258, 49987)
+ (30746, 50040),(30727, 49992)
+ (2168, 50012),(2108, 49914)
+ (21551, 49983),(21492, 49885)
+ (17954, 49975),(17865, 49915)
+ (3531, 49962),(3463, 49934)
+ (19128, 49932),(19112, 49849)
+ (31287, 49923),(31236, 49913)
+ (43925, 49912),(43888, 49878)
+ (29261, 49910),(29247, 49818)
+ (14913, 49873),(14849, 49836)
+ (20007, 49858),(19921, 49778)
+ (38266, 49852),(38233, 49844)
+ (37595, 49849),(37581, 49834)
+ (46151, 49848),(46058, 49830)
+ (15 rows)
+
+ -- same thing for index with points
+ CREATE TABLE test_point(c cube);
+ INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube);
+ CREATE INDEX ON test_point USING gist(c);
+ SELECT * FROM test_point ORDER BY c~>1, c~>2 LIMIT 15; -- ascending by 1st then by 2nd coordinate
+ c
+ --------------------------
+ (54, 38679, 3, 38602)
+ (83, 10271, 15, 10265)
+ (122, 46832, 64, 46762)
+ (154, 4019, 138, 3990)
+ (161, 24465, 107, 24374)
+ (162, 26040, 120, 25963)
+ (167, 17214, 92, 17184)
+ (207, 40886, 179, 40879)
+ (259, 1850, 175, 1820)
+ (270, 29508, 264, 29440)
+ (270, 32616, 226, 32607)
+ (288, 49588, 204, 49571)
+ (318, 31489, 235, 31404)
+ (326, 18837, 285, 18817)
+ (337, 455, 240, 359)
+ (15 rows)
+
+ SELECT * FROM test_point ORDER BY c~>4 DESC LIMIT 15; -- descending by 1st coordinate
+ c
+ ------------------------------
+ (30746, 50040, 30727, 49992)
+ (36311, 50073, 36258, 49987)
+ (3531, 49962, 3463, 49934)
+ (17954, 49975, 17865, 49915)
+ (2168, 50012, 2108, 49914)
+ (31287, 49923, 31236, 49913)
+ (21551, 49983, 21492, 49885)
+ (43925, 49912, 43888, 49878)
+ (19128, 49932, 19112, 49849)
+ (38266, 49852, 38233, 49844)
+ (14913, 49873, 14849, 49836)
+ (37595, 49849, 37581, 49834)
+ (46151, 49848, 46058, 49830)
+ (29261, 49910, 29247, 49818)
+ (19233, 49824, 19185, 49794)
+ (15 rows)
+
diff --git a/contrib/cube/expected/cube_3.out b/contrib/cube/expected/cube_3.out
new file mode 100644
index 2aa42be..f671128
*** a/contrib/cube/expected/cube_3.out
--- b/contrib/cube/expected/cube_3.out
*************** SELECT cube_size('(42,137)'::cube);
*** 1381,1386 ****
--- 1381,1531 ----
0
(1 row)
+ -- Test of distances
+ --
+ SELECT cube_distance('(1,1)'::cube, '(4,5)'::cube);
+ cube_distance
+ ---------------
+ 5
+ (1 row)
+
+ SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e;
+ d_e
+ -----
+ 5
+ (1 row)
+
+ SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube);
+ distance_chebyshev
+ --------------------
+ 4
+ (1 row)
+
+ SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c;
+ d_c
+ -----
+ 4
+ (1 row)
+
+ SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube);
+ distance_taxicab
+ ------------------
+ 7
+ (1 row)
+
+ SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t;
+ d_t
+ -----
+ 7
+ (1 row)
+
+ -- zero for overlapping
+ SELECT cube_distance('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ cube_distance
+ ---------------
+ 0
+ (1 row)
+
+ SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ distance_chebyshev
+ --------------------
+ 0
+ (1 row)
+
+ SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ distance_taxicab
+ ------------------
+ 0
+ (1 row)
+
+ -- coordinate access
+ SELECT cube(array[10,20,30], array[40,50,60])->1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])->1;
+ ?column?
+ ----------
+ 40
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])->6;
+ ?column?
+ ----------
+ 60
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])->0;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->7;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->-1;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30], array[40,50,60])->-6;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[10,20,30])->3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[10,20,30])->6;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[10,20,30])->-6;
+ ERROR: Cube index out of bounds
+ -- "normalized" coordinate access
+ SELECT cube(array[10,20,30], array[40,50,60])~>1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>1;
+ ?column?
+ ----------
+ 10
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])~>2;
+ ?column?
+ ----------
+ 20
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>2;
+ ?column?
+ ----------
+ 20
+ (1 row)
+
+ SELECT cube(array[10,20,30], array[40,50,60])~>3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>3;
+ ?column?
+ ----------
+ 30
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>0;
+ ERROR: Cube index out of bounds
+ SELECT cube(array[40,50,60], array[10,20,30])~>4;
+ ?column?
+ ----------
+ 40
+ (1 row)
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
+ ERROR: Cube index out of bounds
-- Load some example data and build the index
--
CREATE TABLE test_cube (c cube);
*************** SELECT * FROM test_cube WHERE c && '(300
*** 1407,1409 ****
--- 1552,1710 ----
(2424, 160),(2424, 81)
(5 rows)
+ -- kNN with index
+ SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------------------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (948, 1201),(907, 1156) | 772.000647668122
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (5 rows)
+
+ SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (948, 1201),(907, 1156) | 656
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (5 rows)
+
+ SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5;
+ c | dist
+ -------------------------+------
+ (337, 455),(240, 359) | 0
+ (759, 187),(662, 163) | 162
+ (1444, 403),(1346, 344) | 846
+ (369, 1457),(278, 1409) | 909
+ (948, 1201),(907, 1156) | 1063
+ (5 rows)
+
+ -- kNN-based sorting
+ SELECT * FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by 1st coordinate of lower left corner
+ c
+ ---------------------------
+ (54, 38679),(3, 38602)
+ (83, 10271),(15, 10265)
+ (122, 46832),(64, 46762)
+ (167, 17214),(92, 17184)
+ (161, 24465),(107, 24374)
+ (162, 26040),(120, 25963)
+ (154, 4019),(138, 3990)
+ (259, 1850),(175, 1820)
+ (207, 40886),(179, 40879)
+ (288, 49588),(204, 49571)
+ (270, 32616),(226, 32607)
+ (318, 31489),(235, 31404)
+ (337, 455),(240, 359)
+ (270, 29508),(264, 29440)
+ (369, 1457),(278, 1409)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by 2nd coordinate or upper right corner
+ c
+ ---------------------------
+ (30333, 50),(30273, 6)
+ (43301, 75),(43227, 43)
+ (19650, 142),(19630, 51)
+ (2424, 160),(2424, 81)
+ (3449, 171),(3354, 108)
+ (18037, 155),(17941, 109)
+ (28511, 208),(28479, 114)
+ (19946, 217),(19941, 118)
+ (16906, 191),(16816, 139)
+ (759, 187),(662, 163)
+ (22684, 266),(22656, 181)
+ (24423, 255),(24360, 213)
+ (45989, 249),(45910, 222)
+ (11399, 377),(11360, 294)
+ (12162, 389),(12103, 309)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>1 DESC LIMIT 15; -- descending by 1st coordinate of lower left corner
+ c
+ -------------------------------
+ (50027, 49230),(49951, 49214)
+ (49980, 35004),(49937, 34963)
+ (49985, 6436),(49927, 6338)
+ (49999, 27218),(49908, 27176)
+ (49954, 1340),(49905, 1294)
+ (49944, 25163),(49902, 25153)
+ (49981, 34876),(49898, 34786)
+ (49957, 43390),(49897, 43384)
+ (49853, 18504),(49848, 18503)
+ (49902, 41752),(49818, 41746)
+ (49907, 30225),(49810, 30158)
+ (49843, 5175),(49808, 5145)
+ (49887, 24274),(49805, 24184)
+ (49847, 7128),(49798, 7067)
+ (49820, 7990),(49771, 7967)
+ (15 rows)
+
+ SELECT * FROM test_cube ORDER BY c~>4 DESC LIMIT 15; -- descending by 2nd coordinate or upper right corner
+ c
+ -------------------------------
+ (36311, 50073),(36258, 49987)
+ (30746, 50040),(30727, 49992)
+ (2168, 50012),(2108, 49914)
+ (21551, 49983),(21492, 49885)
+ (17954, 49975),(17865, 49915)
+ (3531, 49962),(3463, 49934)
+ (19128, 49932),(19112, 49849)
+ (31287, 49923),(31236, 49913)
+ (43925, 49912),(43888, 49878)
+ (29261, 49910),(29247, 49818)
+ (14913, 49873),(14849, 49836)
+ (20007, 49858),(19921, 49778)
+ (38266, 49852),(38233, 49844)
+ (37595, 49849),(37581, 49834)
+ (46151, 49848),(46058, 49830)
+ (15 rows)
+
+ -- same thing for index with points
+ CREATE TABLE test_point(c cube);
+ INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube);
+ CREATE INDEX ON test_point USING gist(c);
+ SELECT * FROM test_point ORDER BY c~>1, c~>2 LIMIT 15; -- ascending by 1st then by 2nd coordinate
+ c
+ --------------------------
+ (54, 38679, 3, 38602)
+ (83, 10271, 15, 10265)
+ (122, 46832, 64, 46762)
+ (154, 4019, 138, 3990)
+ (161, 24465, 107, 24374)
+ (162, 26040, 120, 25963)
+ (167, 17214, 92, 17184)
+ (207, 40886, 179, 40879)
+ (259, 1850, 175, 1820)
+ (270, 29508, 264, 29440)
+ (270, 32616, 226, 32607)
+ (288, 49588, 204, 49571)
+ (318, 31489, 235, 31404)
+ (326, 18837, 285, 18817)
+ (337, 455, 240, 359)
+ (15 rows)
+
+ SELECT * FROM test_point ORDER BY c~>4 DESC LIMIT 15; -- descending by 1st coordinate
+ c
+ ------------------------------
+ (30746, 50040, 30727, 49992)
+ (36311, 50073, 36258, 49987)
+ (3531, 49962, 3463, 49934)
+ (17954, 49975, 17865, 49915)
+ (2168, 50012, 2108, 49914)
+ (31287, 49923, 31236, 49913)
+ (21551, 49983, 21492, 49885)
+ (43925, 49912, 43888, 49878)
+ (19128, 49932, 19112, 49849)
+ (38266, 49852, 38233, 49844)
+ (14913, 49873, 14849, 49836)
+ (37595, 49849, 37581, 49834)
+ (46151, 49848, 46058, 49830)
+ (29261, 49910, 29247, 49818)
+ (19233, 49824, 19185, 49794)
+ (15 rows)
+
diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql
new file mode 100644
index d58974c..c968a3e
*** a/contrib/cube/sql/cube.sql
--- b/contrib/cube/sql/cube.sql
*************** SELECT cube_inter('(1,2,3)'::cube, '(5,6
*** 325,330 ****
--- 325,365 ----
SELECT cube_size('(4,8),(15,16)'::cube);
SELECT cube_size('(42,137)'::cube);
+ -- Test of distances
+ --
+ SELECT cube_distance('(1,1)'::cube, '(4,5)'::cube);
+ SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e;
+ SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube);
+ SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c;
+ SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube);
+ SELECT '(1,1)'::cube <#> '(4,5)'::cube as d_t;
+ -- zero for overlapping
+ SELECT cube_distance('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ SELECT distance_chebyshev('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ SELECT distance_taxicab('(2,2),(10,10)'::cube, '(0,0),(5,5)'::cube);
+ -- coordinate access
+ SELECT cube(array[10,20,30], array[40,50,60])->1;
+ SELECT cube(array[40,50,60], array[10,20,30])->1;
+ SELECT cube(array[10,20,30], array[40,50,60])->6;
+ SELECT cube(array[10,20,30], array[40,50,60])->0;
+ SELECT cube(array[10,20,30], array[40,50,60])->7;
+ SELECT cube(array[10,20,30], array[40,50,60])->-1;
+ SELECT cube(array[10,20,30], array[40,50,60])->-6;
+ SELECT cube(array[10,20,30])->3;
+ SELECT cube(array[10,20,30])->6;
+ SELECT cube(array[10,20,30])->-6;
+ -- "normalized" coordinate access
+ SELECT cube(array[10,20,30], array[40,50,60])~>1;
+ SELECT cube(array[40,50,60], array[10,20,30])~>1;
+ SELECT cube(array[10,20,30], array[40,50,60])~>2;
+ SELECT cube(array[40,50,60], array[10,20,30])~>2;
+ SELECT cube(array[10,20,30], array[40,50,60])~>3;
+ SELECT cube(array[40,50,60], array[10,20,30])~>3;
+
+ SELECT cube(array[40,50,60], array[10,20,30])~>0;
+ SELECT cube(array[40,50,60], array[10,20,30])~>4;
+ SELECT cube(array[40,50,60], array[10,20,30])~>(-1);
+
-- Load some example data and build the index
--
CREATE TABLE test_cube (c cube);
*************** SELECT * FROM test_cube WHERE c && '(300
*** 336,338 ****
--- 371,392 ----
-- Test sorting
SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c;
+
+ -- kNN with index
+ SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
+ SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5;
+ SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5;
+
+ -- kNN-based sorting
+ SELECT * FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by 1st coordinate of lower left corner
+ SELECT * FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by 2nd coordinate or upper right corner
+ SELECT * FROM test_cube ORDER BY c~>1 DESC LIMIT 15; -- descending by 1st coordinate of lower left corner
+ SELECT * FROM test_cube ORDER BY c~>4 DESC LIMIT 15; -- descending by 2nd coordinate or upper right corner
+
+ -- same thing for index with points
+ CREATE TABLE test_point(c cube);
+ INSERT INTO test_point(SELECT cube(array[c->1,c->2,c->3,c->4]) FROM test_cube);
+ CREATE INDEX ON test_point USING gist(c);
+ SELECT * FROM test_point ORDER BY c~>1, c~>2 LIMIT 15; -- ascending by 1st then by 2nd coordinate
+ SELECT * FROM test_point ORDER BY c~>4 DESC LIMIT 15; -- descending by 1st coordinate
+
diff --git a/doc/src/sgml/cube.sgml b/doc/src/sgml/cube.sgml
new file mode 100644
index 0a226ca..5a1cc8b
*** a/doc/src/sgml/cube.sgml
--- b/doc/src/sgml/cube.sgml
***************
*** 71,80 ****
! It does not matter which order the opposite corners of a cube are
! entered in. The cube> functions
! automatically swap values if needed to create a uniform
! lower left — upper right> internal representation.
--- 71,77 ----
! When corners coincide cube stores only one corner along with a special flag in order to reduce size wasted.
***************
*** 131,136 ****
--- 128,146 ----
a <@ b>
The cube a is contained in the cube b.
+
+
+ a -> n>
+ Get n-th coordinate of cube.
+
+
+
+ a ~> n>
+
+ Get n-th coordinate in 'normalized' cube representation. Noramlization
+ means coordinate rearrangement to form (lower left, upper right).
+
+
***************
*** 144,149 ****
--- 154,240 ----
+ GiST index can be used to retrieve nearest neighbours via several metric
+ operators. As always any of them can be used as ordinary function.
+
+
+
+ Cube GiST-kNN Operators
+
+
+
+ Operator
+ Description
+
+
+
+
+ a <-> b>
+ Euclidean distance between a and b
+
+
+
+ a <#> b>
+ Taxicab (L-1 metric) distance between a and b
+
+
+
+ a <=> b>
+ Chebyshev (L-inf metric) distance between a and b
+
+
+
+
+
+
+ Selection of nearing neigbours can be done in the following way:
+
+
+ SELECT c FROM test
+ ORDER BY cube(array[0.5,0.5,0.5])<->c
+ LIMIT 1;
+
+
+
+
+ Also kNN framework allows us to cheat with metrics in order to get results
+ sorted by selected coodinate directly from the index without extra sorting
+ step. That technique significantly faster on small values of LIMIT, however
+ with bigger values of LIMIT planner will switch automatically to standart
+ index scan and sort.
+ That behavior can be achieved using coordinate operator
+ (cube c)~>(int offset).
+
+
+ => select cube(array[0.41,0.42,0.43])~>2 as coord;
+ coord
+ -------
+ 0.42
+ (1 row)
+
+
+
+ So using that operator as kNN metric we can obtain cubes sorted by it's
+ coordinate.
+
+
+ To get cubes ordered by first coordinate of lower left corner ascending
+ one can use the following query:
+
+
+ SELECT c FROM test ORDER BY c~>1 LIMIT 5;
+
+
+ And to get cubes descending by first coordinate of upper right corner
+ of 2d-cube:
+
+
+ SELECT c FROM test ORDER BY c~>3 DESC LIMIT 5;
+
+
+
+
+
The standard B-tree operators are also provided, for example