diff --git a/contrib/cube/Makefile b/contrib/cube/Makefile index dfb0d806e4b9..ff08d17903fc 100644 --- a/contrib/cube/Makefile +++ b/contrib/cube/Makefile @@ -9,7 +9,7 @@ OBJS = \ EXTENSION = cube DATA = cube--1.2.sql cube--1.2--1.3.sql cube--1.3--1.4.sql cube--1.4--1.5.sql \ - cube--1.1--1.2.sql cube--1.0--1.1.sql + cube--1.1--1.2.sql cube--1.0--1.1.sql cube--1.5--1.6.sql PGFILEDESC = "cube - multidimensional cube data type" HEADERS = cubedata.h diff --git a/contrib/cube/cube--1.5--1.6.sql b/contrib/cube/cube--1.5--1.6.sql new file mode 100644 index 000000000000..9eb21f174e24 --- /dev/null +++ b/contrib/cube/cube--1.5--1.6.sql @@ -0,0 +1,56 @@ +/* contrib/cube/cube--1.5--1.6.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION cube UPDATE TO '1.6'" to load this file. \quit + +CREATE FUNCTION cube_add(cube, cube) +RETURNS cube +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube_sub(cube, cube) +RETURNS cube +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube_mul_cf(cube, float8) +RETURNS cube +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube_mul_fc(float8, cube) +RETURNS cube +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube_div(cube, float8) +RETURNS cube +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Add coordinate-wise binary operators + +CREATE OPERATOR + ( + LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_add, + COMMUTATOR = '+' +); + +CREATE OPERATOR - ( + LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_sub +); + +-- Add coordinate-wise binary operators with scalars + +CREATE OPERATOR / ( + LEFTARG = cube, RIGHTARG = float8, PROCEDURE = cube_div +); + +CREATE OPERATOR * ( + LEFTARG = cube, RIGHTARG = float8, PROCEDURE = cube_mul_cf, + COMMUTATOR = '*' +); + +CREATE OPERATOR * ( + LEFTARG = float8, RIGHTARG = cube, PROCEDURE = cube_mul_fc, + COMMUTATOR = '*' +); diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c index 8d3654ab7aaf..47e568cd9589 100644 --- a/contrib/cube/cube.c +++ b/contrib/cube/cube.c @@ -91,6 +91,11 @@ 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); +PG_FUNCTION_INFO_V1(cube_add); +PG_FUNCTION_INFO_V1(cube_sub); +PG_FUNCTION_INFO_V1(cube_div); +PG_FUNCTION_INFO_V1(cube_mul_cf); +PG_FUNCTION_INFO_V1(cube_mul_fc); /* ** For internal use only @@ -109,6 +114,8 @@ bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strate */ static double distance_1D(double a1, double a2, double b1, double b2); static bool cube_is_point_internal(NDBOX *cube); +static NDBOX *cube_binop_helper(NDBOX *a, NDBOX *b); +static NDBOX *cube_alloc_shape(NDBOX *a); /***************************************************************************** @@ -1911,3 +1918,124 @@ cube_c_f8_f8(PG_FUNCTION_ARGS) PG_FREE_IF_COPY(cube, 0); PG_RETURN_NDBOX_P(result); } + +static NDBOX * +cube_alloc_shape(NDBOX *a) { + NDBOX *result; + int dim = DIM(a); + int size; + + if (IS_POINT(a)) { + size = POINT_SIZE(dim); + result = (NDBOX *) palloc0(size); + SET_POINT_BIT(result); + } else { + size = CUBE_SIZE(dim); + result = (NDBOX *) palloc0(size); + } + + SET_VARSIZE(result, size); + SET_DIM(result, dim); + + return result; +} + +NDBOX * +cube_binop_helper(NDBOX *a, NDBOX *b) +{ + if (DIM(a) != DIM(b)) + ereport(ERROR, + (errcode(ERRCODE_CARDINALITY_VIOLATION), + errmsg("cubes have different lengths: %d != %d", DIM(a), DIM(b)))); + + if (IS_POINT(a) != IS_POINT(b)) + ereport(ERROR, + (errcode(ERRCODE_DATA_EXCEPTION), + errmsg("it's POINTless to add these cubes: %d != %d", IS_POINT(a), IS_POINT(b)))); + + return cube_alloc_shape(a); +} + +/* + * Function returns coordinate-wise sum of cubes. + */ +Datum +cube_add(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0); + NDBOX *b = PG_GETARG_NDBOX_P(1); + NDBOX *result = cube_binop_helper(a, b); + int i; + int n = DIM(a) * (IS_POINT(a) ? 1 : 2); + + for (i = 0; i < n; i++) + result->x[i] = a->x[i] + b->x[i]; + + PG_RETURN_NDBOX_P(result); +} + +/* + * Function returns coordinate-wise difference of cubes. + */ +Datum +cube_sub(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0); + NDBOX *b = PG_GETARG_NDBOX_P(1); + NDBOX *result = cube_binop_helper(a, b); + int i; + int n = DIM(a) * (IS_POINT(a) ? 1 : 2); + + for (i = 0; i < n; i++) + result->x[i] = a->x[i] - b->x[i]; + + PG_RETURN_NDBOX_P(result); +} + +/* + * Functions return scaled cube. + */ +Datum +cube_div(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0); + double s = PG_GETARG_FLOAT8(1); + NDBOX *result = cube_alloc_shape(a); + int i; + int n = DIM(a) * (IS_POINT(a) ? 1 : 2); + + for (i = 0; i < n; i++) + result->x[i] = a->x[i] / s; + + PG_RETURN_NDBOX_P(result); +} + +Datum +cube_mul_cf(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0); + double s = PG_GETARG_FLOAT8(1); + NDBOX *result = cube_alloc_shape(a); + int i; + int n = DIM(a) * (IS_POINT(a) ? 1 : 2); + + for (i = 0; i < n; i++) + result->x[i] = a->x[i] * s; + + PG_RETURN_NDBOX_P(result); +} + +Datum +cube_mul_fc(PG_FUNCTION_ARGS) +{ + double s = PG_GETARG_FLOAT8(0); + NDBOX *a = PG_GETARG_NDBOX_P(1); + NDBOX *result = cube_alloc_shape(a); + int i; + int n = DIM(a) * (IS_POINT(a) ? 1 : 2); + + for (i = 0; i < n; i++) + result->x[i] = a->x[i] * s; + + PG_RETURN_NDBOX_P(result); +} diff --git a/contrib/cube/cube.control b/contrib/cube/cube.control index 50427ec1170f..7797f7e08d4d 100644 --- a/contrib/cube/cube.control +++ b/contrib/cube/cube.control @@ -1,6 +1,6 @@ # cube extension comment = 'data type for multidimensional cubes' -default_version = '1.5' +default_version = '1.6' module_pathname = '$libdir/cube' relocatable = true trusted = true diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out index 47787c50bd97..698750955de2 100644 --- a/contrib/cube/expected/cube.out +++ b/contrib/cube/expected/cube.out @@ -1973,3 +1973,64 @@ SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upp (15 rows) RESET enable_indexscan; +-- Test of binary operators +SELECT '(-7,7)'::cube + '(-1,1)'::cube; + ?column? +---------- + (-8, 8) +(1 row) + +SELECT '(-7,7)'::cube - '(-1,1)'::cube; + ?column? +---------- + (-6, 6) +(1 row) + +SELECT '(-1,2)'::cube * 2; + ?column? +---------- + (-2, 4) +(1 row) + +SELECT '(-2,4)'::cube / 2; + ?column? +---------- + (-1, 2) +(1 row) + +SELECT 2 * '(-1,2)'::cube; + ?column? +---------- + (-2, 4) +(1 row) + +SELECT '(-7,7),(2,9)'::cube + '(-1,1),(5,12)'::cube; + ?column? +----------------- + (-8, 8),(7, 21) +(1 row) + +SELECT '(-7,7),(2,9)'::cube - '(-1,1),(5,12)'::cube; + ?column? +------------------ + (-6, 6),(-3, -3) +(1 row) + +SELECT '(-1,2),(2,9)'::cube * 2; + ?column? +----------------- + (-2, 4),(4, 18) +(1 row) + +SELECT '(-2,4),(3,7)'::cube / 2; + ?column? +-------------------- + (-1, 2),(1.5, 3.5) +(1 row) + +SELECT 2 * '(-1,2),(2,9)'::cube; + ?column? +----------------- + (-2, 4),(4, 18) +(1 row) + diff --git a/contrib/cube/meson.build b/contrib/cube/meson.build index fd3c057f4692..32d88a0416e8 100644 --- a/contrib/cube/meson.build +++ b/contrib/cube/meson.build @@ -40,6 +40,7 @@ install_data( 'cube--1.2--1.3.sql', 'cube--1.3--1.4.sql', 'cube--1.4--1.5.sql', + 'cube--1.5--1.6.sql', kwargs: contrib_data_args, ) diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql index eec90d21ee3b..e819eacbfe80 100644 --- a/contrib/cube/sql/cube.sql +++ b/contrib/cube/sql/cube.sql @@ -436,3 +436,15 @@ SELECT c~>(-2), c FROM test_cube ORDER BY c~>(-2) LIMIT 15; -- descending by rig SELECT c~>(-3), c FROM test_cube ORDER BY c~>(-3) LIMIT 15; -- descending by lower bound SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upper bound RESET enable_indexscan; + +-- Test of binary operators +SELECT '(-7,7)'::cube + '(-1,1)'::cube; +SELECT '(-7,7)'::cube - '(-1,1)'::cube; +SELECT '(-1,2)'::cube * 2; +SELECT '(-2,4)'::cube / 2; +SELECT 2 * '(-1,2)'::cube; +SELECT '(-7,7),(2,9)'::cube + '(-1,1),(5,12)'::cube; +SELECT '(-7,7),(2,9)'::cube - '(-1,1),(5,12)'::cube; +SELECT '(-1,2),(2,9)'::cube * 2; +SELECT '(-2,4),(3,7)'::cube / 2; +SELECT 2 * '(-1,2),(2,9)'::cube; diff --git a/doc/src/sgml/cube.sgml b/doc/src/sgml/cube.sgml index 0fb708074867..19355a1041fa 100644 --- a/doc/src/sgml/cube.sgml +++ b/doc/src/sgml/cube.sgml @@ -218,6 +218,56 @@ Computes the Chebyshev (L-inf metric) distance between the two cubes. + + + + cube + cube + cube + + + Computes the coordinate-wise sum of two cubes. + + + + + + cube - cube + cube + + + Computes the coordinate-wise difference of two cubes. + + + + + + cube * float8 + cube + + + Computes the coordinate-wise multiplication of a cube by a scalar value. + + + + + + float8 * cube + cube + + + Computes the coordinate-wise multiplication of a cube by a scalar value. + + + + + + cube / float8 + cube + + + Computes the coordinate-wise division of a cube by a scalar value. + +