diff options
Diffstat (limited to 'contrib/cube')
-rw-r--r-- | contrib/cube/.gitignore | 6 | ||||
-rw-r--r-- | contrib/cube/CHANGES | 130 | ||||
-rw-r--r-- | contrib/cube/Makefile | 40 | ||||
-rw-r--r-- | contrib/cube/cube--1.0--1.1.sql | 59 | ||||
-rw-r--r-- | contrib/cube/cube--1.1--1.2.sql | 75 | ||||
-rw-r--r-- | contrib/cube/cube--1.2--1.3.sql | 12 | ||||
-rw-r--r-- | contrib/cube/cube--1.2.sql | 378 | ||||
-rw-r--r-- | contrib/cube/cube--1.3--1.4.sql | 58 | ||||
-rw-r--r-- | contrib/cube/cube.c | 1852 | ||||
-rw-r--r-- | contrib/cube/cube.control | 6 | ||||
-rw-r--r-- | contrib/cube/cubedata.h | 69 | ||||
-rw-r--r-- | contrib/cube/cubeparse.c | 1719 | ||||
-rw-r--r-- | contrib/cube/cubeparse.y | 269 | ||||
-rw-r--r-- | contrib/cube/cubescan.c | 2115 | ||||
-rw-r--r-- | contrib/cube/cubescan.l | 121 | ||||
-rw-r--r-- | contrib/cube/data/test_cube.data | 3100 | ||||
-rw-r--r-- | contrib/cube/expected/cube.out | 1950 | ||||
-rw-r--r-- | contrib/cube/expected/cube_sci.out | 106 | ||||
-rw-r--r-- | contrib/cube/sql/cube.sql | 432 | ||||
-rw-r--r-- | contrib/cube/sql/cube_sci.sql | 22 |
20 files changed, 12519 insertions, 0 deletions
diff --git a/contrib/cube/.gitignore b/contrib/cube/.gitignore new file mode 100644 index 0000000..cb4c989 --- /dev/null +++ b/contrib/cube/.gitignore @@ -0,0 +1,6 @@ +/cubeparse.c +/cubescan.c +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/contrib/cube/CHANGES b/contrib/cube/CHANGES new file mode 100644 index 0000000..7c5590c --- /dev/null +++ b/contrib/cube/CHANGES @@ -0,0 +1,130 @@ +******************************************************************************** +Changes that were made in July 2006 by Joshua Reich I. +******************************************************************************** + +Code Cleanup: + +Update the calling convention for all external facing functions. By external +facing, I mean all functions that are directly referenced in cube.sql. Prior +to my update, all functions used the older V0 calling convention. They now +use V1. + +New Functions: + +cube(float[]), which makes a zero volume cube from a float array + +cube(float[], float[]), which allows the user to create a cube from +two float arrays; one for the upper right and one for the lower left +coordinate. + +cube_subset(cube, int4[]), to allow you to reorder or choose a subset of +dimensions from a cube, using index values specified in the array. + +******************************************************************************** +Changes that were made in August/September 2002 by Bruno Wolff III. +******************************************************************************** + +Note that this was based on a 7.3 development version and changes may not +directly work with earlier versions. + +I fixed a bug in cubescan.pl that prevented signed numbers with no digits +before a decimal point from being accepted. This was submitted as a separate +patch and may already be applied. + +cube_inter should really return NULL if the two cubes don't overlap. However +this requires changing to the new calling sequence and I don't know enough +about how to do it to make the change. + +I changed all floats to doubles except for g_cube_penalty which I don't +think can be changed to return double. This might cause the penalty to +overflow sooner than one might expect, but overflow could have happened +even with floats. + +I changed the output format (in cube_out) to use %.16g instead of %g, since the +default is only 6 digits of precision. + +I changed all of the functions declared with (isstrict) to use the current +method of declaring this. + +I changed all of the externally visible functions to be immutable which +they are. I don't think this matters for the gist functions and didn't +try to declare them immutable in case there was something tricky about them +that I don't understand. + +I changed the regression tests to use some larger exponents to test output +in exponential form. 1e7 was too small for this. + +I added some regression tests to check for 16 digits of precision. This +may or may not be a good idea. + +I got rid of the swap_corners function. It created scratch boxes that +were iterated through and deleted. This is slower than just getting the +larger or smaller coordinate as needed, since swap_corners was doing the +same thing with the overhead of a function call and memory allocation. + +I added memset calls to zero out newly allocated NDBOXes as the documentation +on functions indicates should be done. This still doesn't allow a hash +index for equality since there are multiple representations of the +same cube. + +I got rid of a call to cube_same in cube_lt and cube_gt since the test +was redundant with other checks being made. The call to cube_same would +only be faster if most of the time you were comparing equivalent cubes. + +In cube_lt and cube_gt, the second (UR) for loop for comparing +extra coordinates to 0 had the wrong range. + +Note that the cube_distance function wasn't mentioned in the README.cube file. + +I added regression tests for the cube_distance function. + +I added the following new functions: +cube +cube_dim +cube_ll_coord +cube_ur_coord +cube_is_point +cube_enlarge + +cube takes text input and returns a cube. This is useful for making cubes +from computed strings. + +cube_dim returns the number of dimensions stored in the data structure +for a cube. This is useful for constraints on the dimensions of a cube. + +cube_ll_coord returns the nth coordinate value for the lower left corner +of a cube. This is useful for doing coordinate transformations. + +cube_ur_coord returns the nth coordinate value for the upper right corner +of a cube. This is useful for doing coordinate transformations. + +cube_is_point returns true if a cube is also a point. This is true when the +two defining corners are the same. + +cube_enlarge increases the size of a cube by a specified radius in at least +n dimensions. If the radius is negative the box is shrunk instead. This +is useful for creating bounding boxes around a point for searching for +nearby points. All defined dimensions are changed by the radius. If n +is greater than the number of defined dimensions and the cube is being +increased (r >= 0) then 0 is used as the base for the extra coordinates. +LL coordinates are decreased by r and UR coordinates are increased by r. If a +LL coordinate is increased to larger than the corresponding UR coordinate +(this can only happen when r < 0) than both coordinates are set to their +average. + +I added regression tests for the new functions. + +I added documentation for cube_distance and the new functions to README.cube +as well as making a few other minor changes. + +I changed create function to create or replace function in the install +script. + +I limited the number of dimensions allowed in cube_enlarge and cube_in +to 100 to make it harder for people to mess up the database. The constant +is defined in cubedata.h and can be increased if you need something larger. + +I added grant statements to the install script to make the functions +executable to everyone. + +Bruno Wolff III <bruno@wolff.to> diff --git a/contrib/cube/Makefile b/contrib/cube/Makefile new file mode 100644 index 0000000..54f609d --- /dev/null +++ b/contrib/cube/Makefile @@ -0,0 +1,40 @@ +# contrib/cube/Makefile + +MODULE_big = cube +OBJS = \ + $(WIN32RES) \ + cube.o \ + cubeparse.o + +EXTENSION = cube +DATA = cube--1.2.sql cube--1.2--1.3.sql cube--1.3--1.4.sql \ + cube--1.1--1.2.sql cube--1.0--1.1.sql +PGFILEDESC = "cube - multidimensional cube data type" + +HEADERS = cubedata.h + +REGRESS = cube cube_sci + +EXTRA_CLEAN = y.tab.c y.tab.h + +SHLIB_LINK += $(filter -lm, $(LIBS)) + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/cube +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif + + +# cubescan is compiled as part of cubeparse +cubeparse.o: cubescan.c + +distprep: cubeparse.c cubescan.c + +maintainer-clean: + rm -f cubeparse.c cubescan.c 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 0000000..fbe61e7 --- /dev/null +++ b/contrib/cube/cube--1.0--1.1.sql @@ -0,0 +1,59 @@ +/* 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.1--1.2.sql b/contrib/cube/cube--1.1--1.2.sql new file mode 100644 index 0000000..76aba23 --- /dev/null +++ b/contrib/cube/cube--1.1--1.2.sql @@ -0,0 +1,75 @@ +/* contrib/cube/cube--1.1--1.2.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION cube UPDATE TO '1.2'" to load this file. \quit + +-- Update procedure signatures the hard way. +-- We use to_regprocedure() so that query doesn't fail if run against 9.6beta1 definitions, +-- wherein the signatures have been updated already. In that case to_regprocedure() will +-- return NULL and no updates will happen. +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); + +UPDATE pg_catalog.pg_proc SET + proargtypes = pg_catalog.array_to_string(newtypes::pg_catalog.oid[], ' ')::pg_catalog.oidvector, + pronargs = pg_catalog.array_length(newtypes, 1) +FROM (VALUES +(NULL::pg_catalog.text, NULL::pg_catalog.text[]), -- establish column types +('g_cube_consistent(internal,SCH.cube,int4,oid,internal)', '{internal,SCH.cube,int2,oid,internal}'), +('g_cube_distance(internal,SCH.cube,smallint,oid)', '{internal,SCH.cube,smallint,oid,internal}') +) AS update_data (oldproc, newtypestext), +LATERAL ( + SELECT array_agg(replace(typ, 'SCH', my_schema)::regtype) as newtypes FROM unnest(newtypestext) typ +) ls +WHERE oid = to_regprocedure(my_schema || '.' || replace(oldproc, 'SCH', my_schema)); + +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; + +ALTER FUNCTION cube_in(cstring) PARALLEL SAFE; +ALTER FUNCTION cube(float8[], float8[]) PARALLEL SAFE; +ALTER FUNCTION cube(float8[]) PARALLEL SAFE; +ALTER FUNCTION cube_out(cube) PARALLEL SAFE; +ALTER FUNCTION cube_eq(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_ne(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_lt(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_gt(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_le(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_ge(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_cmp(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_contains(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_contained(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_overlap(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_union(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_inter(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_size(cube) PARALLEL SAFE; +ALTER FUNCTION cube_subset(cube, int4[]) PARALLEL SAFE; +ALTER FUNCTION cube_distance(cube, cube) PARALLEL SAFE; +ALTER FUNCTION distance_chebyshev(cube, cube) PARALLEL SAFE; +ALTER FUNCTION distance_taxicab(cube, cube) PARALLEL SAFE; +ALTER FUNCTION cube_dim(cube) PARALLEL SAFE; +ALTER FUNCTION cube_ll_coord(cube, int4) PARALLEL SAFE; +ALTER FUNCTION cube_ur_coord(cube, int4) PARALLEL SAFE; +ALTER FUNCTION cube_coord(cube, int4) PARALLEL SAFE; +ALTER FUNCTION cube_coord_llur(cube, int4) PARALLEL SAFE; +ALTER FUNCTION cube(float8) PARALLEL SAFE; +ALTER FUNCTION cube(float8, float8) PARALLEL SAFE; +ALTER FUNCTION cube(cube, float8) PARALLEL SAFE; +ALTER FUNCTION cube(cube, float8, float8) PARALLEL SAFE; +ALTER FUNCTION cube_is_point(cube) PARALLEL SAFE; +ALTER FUNCTION cube_enlarge(cube, float8, int4) PARALLEL SAFE; +ALTER FUNCTION g_cube_consistent(internal, cube, smallint, oid, internal) PARALLEL SAFE; +ALTER FUNCTION g_cube_compress(internal) PARALLEL SAFE; +ALTER FUNCTION g_cube_decompress(internal) PARALLEL SAFE; +ALTER FUNCTION g_cube_penalty(internal, internal, internal) PARALLEL SAFE; +ALTER FUNCTION g_cube_picksplit(internal, internal) PARALLEL SAFE; +ALTER FUNCTION g_cube_union(internal, internal) PARALLEL SAFE; +ALTER FUNCTION g_cube_same(cube, cube, internal) PARALLEL SAFE; +ALTER FUNCTION g_cube_distance(internal, cube, smallint, oid, internal) PARALLEL SAFE; diff --git a/contrib/cube/cube--1.2--1.3.sql b/contrib/cube/cube--1.2--1.3.sql new file mode 100644 index 0000000..a688f19 --- /dev/null +++ b/contrib/cube/cube--1.2--1.3.sql @@ -0,0 +1,12 @@ +/* contrib/cube/cube--1.2--1.3.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION cube UPDATE TO '1.3'" to load this file. \quit + +ALTER OPERATOR <= (cube, cube) SET ( + RESTRICT = scalarlesel, JOIN = scalarlejoinsel +); + +ALTER OPERATOR >= (cube, cube) SET ( + RESTRICT = scalargesel, JOIN = scalargejoinsel +); diff --git a/contrib/cube/cube--1.2.sql b/contrib/cube/cube--1.2.sql new file mode 100644 index 0000000..dea2614 --- /dev/null +++ b/contrib/cube/cube--1.2.sql @@ -0,0 +1,378 @@ +/* contrib/cube/cube--1.2.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 PARALLEL SAFE; + +CREATE FUNCTION cube(float8[], float8[]) RETURNS cube +AS 'MODULE_PATHNAME', 'cube_a_f8_f8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube(float8[]) RETURNS cube +AS 'MODULE_PATHNAME', 'cube_a_f8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube_out(cube) +RETURNS cstring +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +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 PARALLEL SAFE; + +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 PARALLEL SAFE; + +COMMENT ON FUNCTION cube_ne(cube, cube) IS 'different'; + +CREATE FUNCTION cube_lt(cube, cube) +RETURNS bool +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +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 PARALLEL SAFE; + +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 PARALLEL SAFE; + +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 PARALLEL SAFE; + +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 PARALLEL SAFE; + +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 PARALLEL SAFE; + +COMMENT ON FUNCTION cube_contains(cube, cube) IS 'contains'; + +CREATE FUNCTION cube_contained(cube, cube) +RETURNS bool +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +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 PARALLEL SAFE; + +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 PARALLEL SAFE; + +CREATE FUNCTION cube_inter(cube, cube) +RETURNS cube +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube_size(cube) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + + +-- Misc N-dimensional functions + +CREATE FUNCTION cube_subset(cube, int4[]) +RETURNS cube +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- proximity routines + +CREATE FUNCTION cube_distance(cube, cube) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION distance_chebyshev(cube, cube) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION distance_taxicab(cube, cube) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Extracting elements functions + +CREATE FUNCTION cube_dim(cube) +RETURNS int4 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube_ll_coord(cube, int4) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube_ur_coord(cube, int4) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube_coord(cube, int4) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube_coord_llur(cube, int4) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube(float8) RETURNS cube +AS 'MODULE_PATHNAME', 'cube_f8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube(float8, float8) RETURNS cube +AS 'MODULE_PATHNAME', 'cube_f8_f8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube(cube, float8) RETURNS cube +AS 'MODULE_PATHNAME', 'cube_c_f8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION cube(cube, float8, float8) RETURNS cube +AS 'MODULE_PATHNAME', 'cube_c_f8_f8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Test if cube is also a point + +CREATE FUNCTION cube_is_point(cube) +RETURNS bool +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- 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 PARALLEL SAFE; + +-- +-- 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,smallint,oid,internal) +RETURNS bool +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION g_cube_compress(internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION g_cube_decompress(internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION g_cube_penalty(internal,internal,internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION g_cube_picksplit(internal, internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION g_cube_union(internal, internal) +RETURNS cube +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION g_cube_same(cube, cube, internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION g_cube_distance (internal, cube, smallint, oid, internal) +RETURNS float8 +AS 'MODULE_PATHNAME' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- 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, smallint, 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, internal); diff --git a/contrib/cube/cube--1.3--1.4.sql b/contrib/cube/cube--1.3--1.4.sql new file mode 100644 index 0000000..4162939 --- /dev/null +++ b/contrib/cube/cube--1.3--1.4.sql @@ -0,0 +1,58 @@ +/* contrib/cube/cube--1.3--1.4.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION cube UPDATE TO '1.4'" to load this file. \quit + +-- +-- Get rid of unnecessary compress and decompress support functions. +-- +-- To be allowed to drop the opclass entry for a support function, +-- we must change the entry's dependency type from 'internal' to 'auto', +-- as though it were a loose member of the opfamily rather than being +-- bound into a particular opclass. There's no SQL command for that, +-- so fake it with a manual update on pg_depend. +-- +DO LANGUAGE plpgsql +$$ +DECLARE + my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema()); + old_path pg_catalog.text := pg_catalog.current_setting('search_path'); +BEGIN +-- for safety, transiently set search_path to just pg_catalog+pg_temp +PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true); + +UPDATE pg_catalog.pg_depend +SET deptype = 'a' +WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass + AND objid = + (SELECT objid + FROM pg_catalog.pg_depend + WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass + AND refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass + AND (refobjid = (my_schema || '.g_cube_compress(pg_catalog.internal)')::pg_catalog.regprocedure)) + AND refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass + AND deptype = 'i'; + +UPDATE pg_catalog.pg_depend +SET deptype = 'a' +WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass + AND objid = + (SELECT objid + FROM pg_catalog.pg_depend + WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass + AND refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass + AND (refobjid = (my_schema || '.g_cube_decompress(pg_catalog.internal)')::pg_catalog.regprocedure)) + AND refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass + AND deptype = 'i'; + +PERFORM pg_catalog.set_config('search_path', old_path, true); +END +$$; + +ALTER OPERATOR FAMILY gist_cube_ops USING gist drop function 3 (cube); +ALTER EXTENSION cube DROP function g_cube_compress(pg_catalog.internal); +DROP FUNCTION g_cube_compress(pg_catalog.internal); + +ALTER OPERATOR FAMILY gist_cube_ops USING gist drop function 4 (cube); +ALTER EXTENSION cube DROP function g_cube_decompress(pg_catalog.internal); +DROP FUNCTION g_cube_decompress(pg_catalog.internal); diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c new file mode 100644 index 0000000..6f810b2 --- /dev/null +++ b/contrib/cube/cube.c @@ -0,0 +1,1852 @@ +/****************************************************************************** + contrib/cube/cube.c + + 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 + format for these routines is dictated by Postgres architecture. +******************************************************************************/ + +#include "postgres.h" + +#include <math.h> + +#include "access/gist.h" +#include "access/stratnum.h" +#include "cubedata.h" +#include "utils/array.h" +#include "utils/float.h" + +PG_MODULE_MAGIC; + +/* + * Taken from the intarray contrib header + */ +#define ARRPTR(x) ( (double *) ARR_DATA_PTR(x) ) +#define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x)) + +/* +** Input/Output routines +*/ +PG_FUNCTION_INFO_V1(cube_in); +PG_FUNCTION_INFO_V1(cube_a_f8_f8); +PG_FUNCTION_INFO_V1(cube_a_f8); +PG_FUNCTION_INFO_V1(cube_out); +PG_FUNCTION_INFO_V1(cube_f8); +PG_FUNCTION_INFO_V1(cube_f8_f8); +PG_FUNCTION_INFO_V1(cube_c_f8); +PG_FUNCTION_INFO_V1(cube_c_f8_f8); +PG_FUNCTION_INFO_V1(cube_dim); +PG_FUNCTION_INFO_V1(cube_ll_coord); +PG_FUNCTION_INFO_V1(cube_ur_coord); +PG_FUNCTION_INFO_V1(cube_coord); +PG_FUNCTION_INFO_V1(cube_coord_llur); +PG_FUNCTION_INFO_V1(cube_subset); + +/* +** GiST support methods +*/ + +PG_FUNCTION_INFO_V1(g_cube_consistent); +PG_FUNCTION_INFO_V1(g_cube_compress); +PG_FUNCTION_INFO_V1(g_cube_decompress); +PG_FUNCTION_INFO_V1(g_cube_penalty); +PG_FUNCTION_INFO_V1(g_cube_picksplit); +PG_FUNCTION_INFO_V1(g_cube_union); +PG_FUNCTION_INFO_V1(g_cube_same); +PG_FUNCTION_INFO_V1(g_cube_distance); + +/* +** B-tree support functions +*/ +PG_FUNCTION_INFO_V1(cube_eq); +PG_FUNCTION_INFO_V1(cube_ne); +PG_FUNCTION_INFO_V1(cube_lt); +PG_FUNCTION_INFO_V1(cube_gt); +PG_FUNCTION_INFO_V1(cube_le); +PG_FUNCTION_INFO_V1(cube_ge); +PG_FUNCTION_INFO_V1(cube_cmp); + +/* +** R-tree support functions +*/ + +PG_FUNCTION_INFO_V1(cube_contains); +PG_FUNCTION_INFO_V1(cube_contained); +PG_FUNCTION_INFO_V1(cube_overlap); +PG_FUNCTION_INFO_V1(cube_union); +PG_FUNCTION_INFO_V1(cube_inter); +PG_FUNCTION_INFO_V1(cube_size); + +/* +** 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); + +/* +** 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 functions +*/ +static double distance_1D(double a1, double a2, double b1, double b2); +static bool cube_is_point_internal(NDBOX *cube); + + +/***************************************************************************** + * Input/Output functions + *****************************************************************************/ + +/* NdBox = [(lowerleft),(upperright)] */ +/* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */ +Datum +cube_in(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + NDBOX *result; + + cube_scanner_init(str); + + if (cube_yyparse(&result) != 0) + cube_yyerror(&result, "cube parser failed"); + + cube_scanner_finish(); + + PG_RETURN_NDBOX_P(result); +} + + +/* +** Allows the construction of a cube from 2 float[]'s +*/ +Datum +cube_a_f8_f8(PG_FUNCTION_ARGS) +{ + ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0); + ArrayType *ll = PG_GETARG_ARRAYTYPE_P(1); + NDBOX *result; + int i; + int dim; + int size; + bool point; + double *dur, + *dll; + + if (array_contains_nulls(ur) || array_contains_nulls(ll)) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), + errmsg("cannot work with arrays containing NULLs"))); + + dim = ARRNELEMS(ur); + if (dim > CUBE_MAX_DIM) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("can't extend cube"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + + 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); + + /* Check if it's a point */ + point = true; + for (i = 0; i < dim; i++) + { + if (dur[i] != dll[i]) + { + point = false; + break; + } + } + + size = point ? POINT_SIZE(dim) : CUBE_SIZE(dim); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, dim); + + for (i = 0; i < dim; i++) + result->x[i] = dur[i]; + + if (!point) + { + for (i = 0; i < dim; i++) + result->x[i + dim] = dll[i]; + } + else + SET_POINT_BIT(result); + + PG_RETURN_NDBOX_P(result); +} + +/* +** Allows the construction of a zero-volume cube from a float[] +*/ +Datum +cube_a_f8(PG_FUNCTION_ARGS) +{ + ArrayType *ur = PG_GETARG_ARRAYTYPE_P(0); + NDBOX *result; + int i; + int dim; + int size; + double *dur; + + if (array_contains_nulls(ur)) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), + errmsg("cannot work with arrays containing NULLs"))); + + dim = ARRNELEMS(ur); + if (dim > CUBE_MAX_DIM) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("array is too long"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + + dur = ARRPTR(ur); + + size = POINT_SIZE(dim); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, dim); + SET_POINT_BIT(result); + + for (i = 0; i < dim; i++) + result->x[i] = dur[i]; + + PG_RETURN_NDBOX_P(result); +} + +Datum +cube_subset(PG_FUNCTION_ARGS) +{ + NDBOX *c = PG_GETARG_NDBOX_P(0); + ArrayType *idx = PG_GETARG_ARRAYTYPE_P(1); + NDBOX *result; + int size, + dim, + i; + int *dx; + + if (array_contains_nulls(idx)) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), + errmsg("cannot work with arrays containing NULLs"))); + + dx = (int32 *) ARR_DATA_PTR(idx); + + dim = ARRNELEMS(idx); + if (dim > CUBE_MAX_DIM) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("array is too long"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + + size = IS_POINT(c) ? POINT_SIZE(dim) : CUBE_SIZE(dim); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, dim); + + if (IS_POINT(c)) + SET_POINT_BIT(result); + + for (i = 0; i < dim; i++) + { + if ((dx[i] <= 0) || (dx[i] > DIM(c))) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), + errmsg("Index out of bounds"))); + result->x[i] = c->x[dx[i] - 1]; + if (!IS_POINT(c)) + result->x[i + dim] = c->x[dx[i] + DIM(c) - 1]; + } + + PG_FREE_IF_COPY(c, 0); + PG_RETURN_NDBOX_P(result); +} + +Datum +cube_out(PG_FUNCTION_ARGS) +{ + NDBOX *cube = PG_GETARG_NDBOX_P(0); + StringInfoData buf; + int dim = DIM(cube); + int i; + + initStringInfo(&buf); + + appendStringInfoChar(&buf, '('); + for (i = 0; i < dim; i++) + { + if (i > 0) + appendStringInfoString(&buf, ", "); + appendStringInfoString(&buf, float8out_internal(LL_COORD(cube, i))); + } + appendStringInfoChar(&buf, ')'); + + if (!cube_is_point_internal(cube)) + { + appendStringInfoString(&buf, ",("); + for (i = 0; i < dim; i++) + { + if (i > 0) + appendStringInfoString(&buf, ", "); + appendStringInfoString(&buf, float8out_internal(UR_COORD(cube, i))); + } + appendStringInfoChar(&buf, ')'); + } + + PG_FREE_IF_COPY(cube, 0); + PG_RETURN_CSTRING(buf.data); +} + + +/***************************************************************************** + * GiST functions + *****************************************************************************/ + +/* +** The GiST Consistent method for boxes +** Should return false if for all data items x below entry, +** the predicate x op query == false, where op is the oper +** corresponding to strategy in the pg_amop table. +*/ +Datum +g_cube_consistent(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + NDBOX *query = PG_GETARG_NDBOX_P(1); + StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); + + /* Oid subtype = PG_GETARG_OID(3); */ + bool *recheck = (bool *) PG_GETARG_POINTER(4); + bool res; + + /* All cases served by this function are exact */ + *recheck = false; + + /* + * if entry is not leaf, use g_cube_internal_consistent, else use + * g_cube_leaf_consistent + */ + if (GIST_LEAF(entry)) + res = g_cube_leaf_consistent(DatumGetNDBOXP(entry->key), + query, strategy); + else + res = g_cube_internal_consistent(DatumGetNDBOXP(entry->key), + query, strategy); + + PG_FREE_IF_COPY(query, 1); + PG_RETURN_BOOL(res); +} + + +/* +** The GiST Union method for boxes +** returns the minimal bounding box that encloses all the entries in entryvec +*/ +Datum +g_cube_union(PG_FUNCTION_ARGS) +{ + GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); + int *sizep = (int *) PG_GETARG_POINTER(1); + NDBOX *out = (NDBOX *) NULL; + NDBOX *tmp; + int i; + + tmp = DatumGetNDBOXP(entryvec->vector[0].key); + + /* + * sizep = sizeof(NDBOX); -- NDBOX has variable size + */ + *sizep = VARSIZE(tmp); + + for (i = 1; i < entryvec->n; i++) + { + out = g_cube_binary_union(tmp, + DatumGetNDBOXP(entryvec->vector[i].key), + sizep); + tmp = out; + } + + PG_RETURN_POINTER(out); +} + +/* +** GiST Compress and Decompress methods for boxes +** do not do anything. +*/ + +Datum +g_cube_compress(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(PG_GETARG_DATUM(0)); +} + +Datum +g_cube_decompress(PG_FUNCTION_ARGS) +{ + GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + NDBOX *key = DatumGetNDBOXP(entry->key); + + if (key != DatumGetNDBOXP(entry->key)) + { + GISTENTRY *retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); + + gistentryinit(*retval, PointerGetDatum(key), + entry->rel, entry->page, + entry->offset, false); + PG_RETURN_POINTER(retval); + } + PG_RETURN_POINTER(entry); +} + + +/* +** The GiST Penalty method for boxes +** As in the R-tree paper, we use change in area as our penalty metric +*/ +Datum +g_cube_penalty(PG_FUNCTION_ARGS) +{ + GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); + GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1); + float *result = (float *) PG_GETARG_POINTER(2); + NDBOX *ud; + double tmp1, + tmp2; + + ud = cube_union_v0(DatumGetNDBOXP(origentry->key), + DatumGetNDBOXP(newentry->key)); + rt_cube_size(ud, &tmp1); + rt_cube_size(DatumGetNDBOXP(origentry->key), &tmp2); + *result = (float) (tmp1 - tmp2); + + PG_RETURN_FLOAT8(*result); +} + + + +/* +** The GiST PickSplit method for boxes +** We use Guttman's poly time split algorithm +*/ +Datum +g_cube_picksplit(PG_FUNCTION_ARGS) +{ + GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); + GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); + OffsetNumber i, + j; + NDBOX *datum_alpha, + *datum_beta; + NDBOX *datum_l, + *datum_r; + NDBOX *union_d, + *union_dl, + *union_dr; + NDBOX *inter_d; + bool firsttime; + double size_alpha, + size_beta, + size_union, + size_inter; + double size_waste, + waste; + double size_l, + size_r; + int nbytes; + OffsetNumber seed_1 = 1, + seed_2 = 2; + OffsetNumber *left, + *right; + OffsetNumber maxoff; + + maxoff = entryvec->n - 2; + nbytes = (maxoff + 2) * sizeof(OffsetNumber); + v->spl_left = (OffsetNumber *) palloc(nbytes); + v->spl_right = (OffsetNumber *) palloc(nbytes); + + firsttime = true; + waste = 0.0; + + for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) + { + datum_alpha = DatumGetNDBOXP(entryvec->vector[i].key); + for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j)) + { + datum_beta = DatumGetNDBOXP(entryvec->vector[j].key); + + /* compute the wasted space by unioning these guys */ + /* size_waste = size_union - size_inter; */ + union_d = cube_union_v0(datum_alpha, datum_beta); + rt_cube_size(union_d, &size_union); + inter_d = DatumGetNDBOXP(DirectFunctionCall2(cube_inter, + entryvec->vector[i].key, + entryvec->vector[j].key)); + rt_cube_size(inter_d, &size_inter); + size_waste = size_union - size_inter; + + /* + * are these a more promising split than what we've already seen? + */ + + if (size_waste > waste || firsttime) + { + waste = size_waste; + seed_1 = i; + seed_2 = j; + firsttime = false; + } + } + } + + left = v->spl_left; + v->spl_nleft = 0; + right = v->spl_right; + v->spl_nright = 0; + + datum_alpha = DatumGetNDBOXP(entryvec->vector[seed_1].key); + datum_l = cube_union_v0(datum_alpha, datum_alpha); + rt_cube_size(datum_l, &size_l); + datum_beta = DatumGetNDBOXP(entryvec->vector[seed_2].key); + datum_r = cube_union_v0(datum_beta, datum_beta); + rt_cube_size(datum_r, &size_r); + + /* + * Now split up the regions between the two seeds. An important property + * of this split algorithm is that the split vector v has the indices of + * items to be split in order in its left and right vectors. We exploit + * this property by doing a merge in the code that actually splits the + * page. + * + * For efficiency, we also place the new index tuple in this loop. This is + * handled at the very end, when we have placed all the existing tuples + * and i == maxoff + 1. + */ + + maxoff = OffsetNumberNext(maxoff); + for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) + { + /* + * If we've already decided where to place this item, just put it on + * the right list. Otherwise, we need to figure out which page needs + * the least enlargement in order to store the item. + */ + + if (i == seed_1) + { + *left++ = i; + v->spl_nleft++; + continue; + } + else if (i == seed_2) + { + *right++ = i; + v->spl_nright++; + continue; + } + + /* okay, which page needs least enlargement? */ + datum_alpha = DatumGetNDBOXP(entryvec->vector[i].key); + union_dl = cube_union_v0(datum_l, datum_alpha); + union_dr = cube_union_v0(datum_r, datum_alpha); + rt_cube_size(union_dl, &size_alpha); + rt_cube_size(union_dr, &size_beta); + + /* pick which page to add it to */ + if (size_alpha - size_l < size_beta - size_r) + { + datum_l = union_dl; + size_l = size_alpha; + *left++ = i; + v->spl_nleft++; + } + else + { + datum_r = union_dr; + size_r = size_beta; + *right++ = i; + v->spl_nright++; + } + } + *left = *right = FirstOffsetNumber; /* sentinel value */ + + v->spl_ldatum = PointerGetDatum(datum_l); + v->spl_rdatum = PointerGetDatum(datum_r); + + PG_RETURN_POINTER(v); +} + +/* +** Equality method +*/ +Datum +g_cube_same(PG_FUNCTION_ARGS) +{ + NDBOX *b1 = PG_GETARG_NDBOX_P(0); + NDBOX *b2 = PG_GETARG_NDBOX_P(1); + bool *result = (bool *) PG_GETARG_POINTER(2); + + if (cube_cmp_v0(b1, b2) == 0) + *result = true; + else + *result = false; + + PG_RETURN_NDBOX_P(result); +} + +/* +** SUPPORT ROUTINES +*/ +bool +g_cube_leaf_consistent(NDBOX *key, + NDBOX *query, + StrategyNumber strategy) +{ + bool retval; + + switch (strategy) + { + case RTOverlapStrategyNumber: + retval = cube_overlap_v0(key, query); + break; + case RTSameStrategyNumber: + retval = (cube_cmp_v0(key, query) == 0); + break; + case RTContainsStrategyNumber: + case RTOldContainsStrategyNumber: + retval = cube_contains_v0(key, query); + break; + case RTContainedByStrategyNumber: + case RTOldContainedByStrategyNumber: + retval = cube_contains_v0(query, key); + break; + default: + retval = false; + } + return retval; +} + +bool +g_cube_internal_consistent(NDBOX *key, + NDBOX *query, + StrategyNumber strategy) +{ + bool retval; + + switch (strategy) + { + case RTOverlapStrategyNumber: + retval = (bool) cube_overlap_v0(key, query); + break; + case RTSameStrategyNumber: + case RTContainsStrategyNumber: + case RTOldContainsStrategyNumber: + retval = (bool) cube_contains_v0(key, query); + break; + case RTContainedByStrategyNumber: + case RTOldContainedByStrategyNumber: + retval = (bool) cube_overlap_v0(key, query); + break; + default: + retval = false; + } + return retval; +} + +NDBOX * +g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep) +{ + NDBOX *retval; + + retval = cube_union_v0(r1, r2); + *sizep = VARSIZE(retval); + + return retval; +} + + +/* cube_union_v0 */ +NDBOX * +cube_union_v0(NDBOX *a, NDBOX *b) +{ + int i; + NDBOX *result; + int dim; + int size; + + /* trivial case */ + if (a == b) + return a; + + /* swap the arguments if needed, so that 'a' is always larger than 'b' */ + if (DIM(a) < DIM(b)) + { + NDBOX *tmp = b; + + b = a; + a = tmp; + } + dim = DIM(a); + + size = CUBE_SIZE(dim); + result = palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, dim); + + /* First compute the union of the dimensions present in both args */ + for (i = 0; i < DIM(b); i++) + { + result->x[i] = Min(Min(LL_COORD(a, i), UR_COORD(a, i)), + Min(LL_COORD(b, i), UR_COORD(b, i))); + result->x[i + DIM(a)] = Max(Max(LL_COORD(a, i), UR_COORD(a, i)), + Max(LL_COORD(b, i), UR_COORD(b, i))); + } + /* continue on the higher dimensions only present in 'a' */ + for (; i < DIM(a); i++) + { + result->x[i] = Min(0, + Min(LL_COORD(a, i), UR_COORD(a, i)) + ); + result->x[i + dim] = Max(0, + Max(LL_COORD(a, i), UR_COORD(a, i)) + ); + } + + /* + * Check if the result was in fact a point, and set the flag in the datum + * accordingly. (we don't bother to repalloc it smaller) + */ + if (cube_is_point_internal(result)) + { + size = POINT_SIZE(dim); + SET_VARSIZE(result, size); + SET_POINT_BIT(result); + } + + return result; +} + +Datum +cube_union(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0); + NDBOX *b = PG_GETARG_NDBOX_P(1); + NDBOX *res; + + res = cube_union_v0(a, b); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + PG_RETURN_NDBOX_P(res); +} + +/* cube_inter */ +Datum +cube_inter(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0); + NDBOX *b = PG_GETARG_NDBOX_P(1); + NDBOX *result; + bool swapped = false; + int i; + int dim; + int size; + + /* swap the arguments if needed, so that 'a' is always larger than 'b' */ + if (DIM(a) < DIM(b)) + { + NDBOX *tmp = b; + + b = a; + a = tmp; + swapped = true; + } + dim = DIM(a); + + size = CUBE_SIZE(dim); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, dim); + + /* First compute intersection of the dimensions present in both args */ + for (i = 0; i < DIM(b); i++) + { + result->x[i] = Max(Min(LL_COORD(a, i), UR_COORD(a, i)), + Min(LL_COORD(b, i), UR_COORD(b, i))); + result->x[i + DIM(a)] = Min(Max(LL_COORD(a, i), UR_COORD(a, i)), + Max(LL_COORD(b, i), UR_COORD(b, i))); + } + /* continue on the higher dimensions only present in 'a' */ + for (; i < DIM(a); i++) + { + result->x[i] = Max(0, + Min(LL_COORD(a, i), UR_COORD(a, i)) + ); + result->x[i + DIM(a)] = Min(0, + Max(LL_COORD(a, i), UR_COORD(a, i)) + ); + } + + /* + * Check if the result was in fact a point, and set the flag in the datum + * accordingly. (we don't bother to repalloc it smaller) + */ + if (cube_is_point_internal(result)) + { + size = POINT_SIZE(dim); + result = repalloc(result, size); + SET_VARSIZE(result, size); + SET_POINT_BIT(result); + } + + 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); + } + + /* + * Is it OK to return a non-null intersection for non-overlapping boxes? + */ + PG_RETURN_NDBOX_P(result); +} + +/* cube_size */ +Datum +cube_size(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0); + double result; + + rt_cube_size(a, &result); + PG_FREE_IF_COPY(a, 0); + PG_RETURN_FLOAT8(result); +} + +void +rt_cube_size(NDBOX *a, double *size) +{ + double result; + int i; + + if (a == (NDBOX *) NULL) + { + /* special case for GiST */ + result = 0.0; + } + else if (IS_POINT(a) || DIM(a) == 0) + { + /* necessarily has zero size */ + result = 0.0; + } + else + { + result = 1.0; + for (i = 0; i < DIM(a); i++) + result *= Abs(UR_COORD(a, i) - LL_COORD(a, i)); + } + *size = result; +} + +/* make up a metric in which one box will be 'lower' than the other + -- this can be useful for sorting and to determine uniqueness */ +int32 +cube_cmp_v0(NDBOX *a, NDBOX *b) +{ + int i; + int dim; + + dim = Min(DIM(a), DIM(b)); + + /* compare the common dimensions */ + for (i = 0; i < dim; i++) + { + if (Min(LL_COORD(a, i), UR_COORD(a, i)) > + Min(LL_COORD(b, i), UR_COORD(b, i))) + return 1; + if (Min(LL_COORD(a, i), UR_COORD(a, i)) < + Min(LL_COORD(b, i), UR_COORD(b, i))) + return -1; + } + for (i = 0; i < dim; i++) + { + if (Max(LL_COORD(a, i), UR_COORD(a, i)) > + Max(LL_COORD(b, i), UR_COORD(b, i))) + return 1; + if (Max(LL_COORD(a, i), UR_COORD(a, i)) < + Max(LL_COORD(b, i), UR_COORD(b, i))) + return -1; + } + + /* compare extra dimensions to zero */ + if (DIM(a) > DIM(b)) + { + for (i = dim; i < DIM(a); i++) + { + if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0) + return 1; + if (Min(LL_COORD(a, i), UR_COORD(a, i)) < 0) + return -1; + } + for (i = dim; i < DIM(a); i++) + { + if (Max(LL_COORD(a, i), UR_COORD(a, i)) > 0) + return 1; + if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0) + return -1; + } + + /* + * if all common dimensions are equal, the cube with more dimensions + * wins + */ + return 1; + } + if (DIM(a) < DIM(b)) + { + for (i = dim; i < DIM(b); i++) + { + if (Min(LL_COORD(b, i), UR_COORD(b, i)) > 0) + return -1; + if (Min(LL_COORD(b, i), UR_COORD(b, i)) < 0) + return 1; + } + for (i = dim; i < DIM(b); i++) + { + if (Max(LL_COORD(b, i), UR_COORD(b, i)) > 0) + return -1; + if (Max(LL_COORD(b, i), UR_COORD(b, i)) < 0) + return 1; + } + + /* + * if all common dimensions are equal, the cube with more dimensions + * wins + */ + return -1; + } + + /* They're really equal */ + return 0; +} + +Datum +cube_cmp(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(1); + int32 res; + + res = cube_cmp_v0(a, b); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + PG_RETURN_INT32(res); +} + + +Datum +cube_eq(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(1); + int32 res; + + res = cube_cmp_v0(a, b); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + PG_RETURN_BOOL(res == 0); +} + + +Datum +cube_ne(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(1); + int32 res; + + res = cube_cmp_v0(a, b); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + PG_RETURN_BOOL(res != 0); +} + + +Datum +cube_lt(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(1); + int32 res; + + res = cube_cmp_v0(a, b); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + PG_RETURN_BOOL(res < 0); +} + + +Datum +cube_gt(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(1); + int32 res; + + res = cube_cmp_v0(a, b); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + PG_RETURN_BOOL(res > 0); +} + + +Datum +cube_le(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(1); + int32 res; + + res = cube_cmp_v0(a, b); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + PG_RETURN_BOOL(res <= 0); +} + + +Datum +cube_ge(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(1); + int32 res; + + res = cube_cmp_v0(a, b); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + PG_RETURN_BOOL(res >= 0); +} + + +/* Contains */ +/* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */ +bool +cube_contains_v0(NDBOX *a, NDBOX *b) +{ + int i; + + if ((a == NULL) || (b == NULL)) + return false; + + if (DIM(a) < DIM(b)) + { + /* + * the further comparisons will make sense if the excess dimensions of + * (b) were zeroes Since both UL and UR coordinates must be zero, we + * can check them all without worrying about which is which. + */ + for (i = DIM(a); i < DIM(b); i++) + { + if (LL_COORD(b, i) != 0) + return false; + if (UR_COORD(b, i) != 0) + return false; + } + } + + /* Can't care less about the excess dimensions of (a), if any */ + for (i = 0; i < Min(DIM(a), DIM(b)); i++) + { + if (Min(LL_COORD(a, i), UR_COORD(a, i)) > + Min(LL_COORD(b, i), UR_COORD(b, i))) + return false; + if (Max(LL_COORD(a, i), UR_COORD(a, i)) < + Max(LL_COORD(b, i), UR_COORD(b, i))) + return false; + } + + return true; +} + +Datum +cube_contains(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(1); + bool res; + + res = cube_contains_v0(a, b); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + PG_RETURN_BOOL(res); +} + +/* Contained */ +/* Box(A) Contained by Box(B) IFF Box(B) Contains Box(A) */ +Datum +cube_contained(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(1); + bool res; + + res = cube_contains_v0(b, a); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + PG_RETURN_BOOL(res); +} + +/* Overlap */ +/* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */ +bool +cube_overlap_v0(NDBOX *a, NDBOX *b) +{ + int i; + + if ((a == NULL) || (b == NULL)) + return false; + + /* swap the box pointers if needed */ + if (DIM(a) < DIM(b)) + { + NDBOX *tmp = b; + + b = a; + a = tmp; + } + + /* compare within the dimensions of (b) */ + for (i = 0; i < DIM(b); i++) + { + if (Min(LL_COORD(a, i), UR_COORD(a, i)) > Max(LL_COORD(b, i), UR_COORD(b, i))) + return false; + if (Max(LL_COORD(a, i), UR_COORD(a, i)) < Min(LL_COORD(b, i), UR_COORD(b, i))) + return false; + } + + /* compare to zero those dimensions in (a) absent in (b) */ + for (i = DIM(b); i < DIM(a); i++) + { + if (Min(LL_COORD(a, i), UR_COORD(a, i)) > 0) + return false; + if (Max(LL_COORD(a, i), UR_COORD(a, i)) < 0) + return false; + } + + return true; +} + + +Datum +cube_overlap(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(1); + bool res; + + res = cube_overlap_v0(a, b); + + PG_FREE_IF_COPY(a, 0); + PG_FREE_IF_COPY(b, 1); + 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 + distance between overlapping projections, this metric coincides with the + "common sense" geometric distance */ +Datum +cube_distance(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(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 = distance_1D(LL_COORD(a, i), UR_COORD(a, i), LL_COORD(b, i), UR_COORD(b, i)); + distance += d * d; + } + + /* compute distance to zero for those dimensions in (a) absent in (b) */ + for (i = DIM(b); i < DIM(a); i++) + { + d = distance_1D(LL_COORD(a, i), UR_COORD(a, i), 0.0, 0.0); + distance += d * 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(sqrt(distance)); +} + +Datum +distance_taxicab(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0), + *b = PG_GETARG_NDBOX_P(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_P(0), + *b = PG_GETARG_NDBOX_P(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 = DatumGetNDBOXP(entry->key); + double retval; + + if (strategy == CubeKNNDistanceCoord) + { + /* + * Handle ordering by ~> operator. See comments of cube_coord_llur() + * for details + */ + int coord = PG_GETARG_INT32(1); + bool isLeaf = GistPageIsLeaf(entry->page); + bool inverse = false; + + /* 0 is the only unsupported coordinate value */ + if (coord == 0) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), + errmsg("zero cube index is not defined"))); + + /* Return inversed value for negative coordinate */ + if (coord < 0) + { + coord = -coord; + inverse = true; + } + + if (coord <= 2 * DIM(cube)) + { + /* dimension index */ + int index = (coord - 1) / 2; + + /* whether this is upper bound (lower bound otherwise) */ + bool upper = ((coord - 1) % 2 == 1); + + if (IS_POINT(cube)) + { + retval = cube->x[index]; + } + else + { + if (isLeaf) + { + /* For leaf just return required upper/lower bound */ + if (upper) + retval = Max(cube->x[index], cube->x[index + DIM(cube)]); + else + retval = Min(cube->x[index], cube->x[index + DIM(cube)]); + } + else + { + /* + * For non-leaf we should always return lower bound, + * because even upper bound of a child in the subtree can + * be as small as our lower bound. For inversed case we + * return upper bound because it becomes lower bound for + * inversed value. + */ + if (!inverse) + retval = Min(cube->x[index], cube->x[index + DIM(cube)]); + else + retval = Max(cube->x[index], cube->x[index + DIM(cube)]); + } + } + } + else + { + retval = 0.0; + } + + /* Inverse return value if needed */ + if (inverse) + retval = -retval; + } + else + { + NDBOX *query = PG_GETARG_NDBOX_P(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, "unrecognized cube strategy number: %d", strategy); + retval = 0; /* keep compiler quiet */ + break; + } + } + PG_RETURN_FLOAT8(retval); +} + +static double +distance_1D(double a1, double a2, double b1, double b2) +{ + /* interval (a) is entirely on the left of (b) */ + if ((a1 <= b1) && (a2 <= b1) && (a1 <= b2) && (a2 <= b2)) + return (Min(b1, b2) - Max(a1, a2)); + + /* interval (a) is entirely on the right of (b) */ + if ((a1 > b1) && (a2 > b1) && (a1 > b2) && (a2 > b2)) + return (Min(a1, a2) - Max(b1, b2)); + + /* the rest are all sorts of intersections */ + return 0.0; +} + +/* Test if a box is also a point */ +Datum +cube_is_point(PG_FUNCTION_ARGS) +{ + NDBOX *cube = PG_GETARG_NDBOX_P(0); + bool result; + + result = cube_is_point_internal(cube); + PG_FREE_IF_COPY(cube, 0); + PG_RETURN_BOOL(result); +} + +static bool +cube_is_point_internal(NDBOX *cube) +{ + int i; + + if (IS_POINT(cube)) + return true; + + /* + * Even if the point-flag is not set, all the lower-left coordinates might + * match the upper-right coordinates, so that the value is in fact a + * point. Such values don't arise with current code - the point flag is + * always set if appropriate - but they might be present on-disk in + * clusters upgraded from pre-9.4 versions. + */ + for (i = 0; i < DIM(cube); i++) + { + if (LL_COORD(cube, i) != UR_COORD(cube, i)) + return false; + } + return true; +} + +/* Return dimensions in use in the data structure */ +Datum +cube_dim(PG_FUNCTION_ARGS) +{ + NDBOX *c = PG_GETARG_NDBOX_P(0); + int dim = DIM(c); + + PG_FREE_IF_COPY(c, 0); + PG_RETURN_INT32(dim); +} + +/* Return a specific normalized LL coordinate */ +Datum +cube_ll_coord(PG_FUNCTION_ARGS) +{ + NDBOX *c = PG_GETARG_NDBOX_P(0); + int n = PG_GETARG_INT32(1); + double result; + + if (DIM(c) >= n && n > 0) + result = Min(LL_COORD(c, n - 1), UR_COORD(c, n - 1)); + else + result = 0; + + PG_FREE_IF_COPY(c, 0); + PG_RETURN_FLOAT8(result); +} + +/* Return a specific normalized UR coordinate */ +Datum +cube_ur_coord(PG_FUNCTION_ARGS) +{ + NDBOX *c = PG_GETARG_NDBOX_P(0); + int n = PG_GETARG_INT32(1); + double result; + + if (DIM(c) >= n && n > 0) + result = Max(LL_COORD(c, n - 1), UR_COORD(c, n - 1)); + else + result = 0; + + PG_FREE_IF_COPY(c, 0); + 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_P(0); + int coord = PG_GETARG_INT32(1); + + if (coord <= 0 || coord > 2 * DIM(cube)) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), + errmsg("cube index %d is out of bounds", coord))); + + if (IS_POINT(cube)) + PG_RETURN_FLOAT8(cube->x[(coord - 1) % DIM(cube)]); + else + PG_RETURN_FLOAT8(cube->x[coord - 1]); +} + + +/*---- + * This function works like cube_coord(), but rearranges coordinates in the + * way suitable to support coordinate ordering using KNN-GiST. For historical + * reasons this 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 in order to get cubes ordered by one of dimensions from the index + * without explicit sort step we need this representation-independent coordinate + * getter. Moreover, indexed dataset may contain cubes of different dimensions + * number. Accordingly, this coordinate getter should be able to return + * lower/upper bound for particular dimension independently on number of cube + * dimensions. Also, KNN-GiST supports only ascending sorting. In order to + * support descending sorting, this function returns inverse of value when + * negative coordinate is given. + * + * Long story short, this function uses following meaning of coordinates: + * # (2 * N - 1) -- lower bound of Nth dimension, + * # (2 * N) -- upper bound of Nth dimension, + * # - (2 * N - 1) -- negative of lower bound of Nth dimension, + * # - (2 * N) -- negative of upper bound of Nth dimension. + * + * When given coordinate exceeds number of cube dimensions, then 0 returned + * (reproducing logic of GiST indexing of variable-length cubes). + */ +Datum +cube_coord_llur(PG_FUNCTION_ARGS) +{ + NDBOX *cube = PG_GETARG_NDBOX_P(0); + int coord = PG_GETARG_INT32(1); + bool inverse = false; + float8 result; + + /* 0 is the only unsupported coordinate value */ + if (coord == 0) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), + errmsg("zero cube index is not defined"))); + + /* Return inversed value for negative coordinate */ + if (coord < 0) + { + coord = -coord; + inverse = true; + } + + if (coord <= 2 * DIM(cube)) + { + /* dimension index */ + int index = (coord - 1) / 2; + + /* whether this is upper bound (lower bound otherwise) */ + bool upper = ((coord - 1) % 2 == 1); + + if (IS_POINT(cube)) + { + result = cube->x[index]; + } + else + { + if (upper) + result = Max(cube->x[index], cube->x[index + DIM(cube)]); + else + result = Min(cube->x[index], cube->x[index + DIM(cube)]); + } + } + else + { + /* + * Return zero if coordinate is out of bound. That reproduces logic + * of how cubes with low dimension number are expanded during GiST + * indexing. + */ + result = 0.0; + } + + /* Inverse value if needed */ + if (inverse) + result = -result; + + PG_RETURN_FLOAT8(result); +} + +/* Increase or decrease box size by a radius in at least n dimensions. */ +Datum +cube_enlarge(PG_FUNCTION_ARGS) +{ + NDBOX *a = PG_GETARG_NDBOX_P(0); + double r = PG_GETARG_FLOAT8(1); + int32 n = PG_GETARG_INT32(2); + NDBOX *result; + int dim = 0; + int size; + int i, + j; + + if (n > CUBE_MAX_DIM) + n = CUBE_MAX_DIM; + if (r > 0 && n > 0) + dim = n; + if (DIM(a) > dim) + dim = DIM(a); + + size = CUBE_SIZE(dim); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, dim); + + for (i = 0, j = dim; i < DIM(a); i++, j++) + { + if (LL_COORD(a, i) >= UR_COORD(a, i)) + { + result->x[i] = UR_COORD(a, i) - r; + result->x[j] = LL_COORD(a, i) + r; + } + else + { + result->x[i] = LL_COORD(a, i) - r; + result->x[j] = UR_COORD(a, i) + r; + } + if (result->x[i] > result->x[j]) + { + result->x[i] = (result->x[i] + result->x[j]) / 2; + result->x[j] = result->x[i]; + } + } + /* dim > a->dim only if r > 0 */ + for (; i < dim; i++, j++) + { + result->x[i] = -r; + result->x[j] = r; + } + + /* + * Check if the result was in fact a point, and set the flag in the datum + * accordingly. (we don't bother to repalloc it smaller) + */ + if (cube_is_point_internal(result)) + { + size = POINT_SIZE(dim); + SET_VARSIZE(result, size); + SET_POINT_BIT(result); + } + + PG_FREE_IF_COPY(a, 0); + PG_RETURN_NDBOX_P(result); +} + +/* Create a one dimensional box with identical upper and lower coordinates */ +Datum +cube_f8(PG_FUNCTION_ARGS) +{ + double x = PG_GETARG_FLOAT8(0); + NDBOX *result; + int size; + + size = POINT_SIZE(1); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, 1); + SET_POINT_BIT(result); + result->x[0] = x; + + PG_RETURN_NDBOX_P(result); +} + +/* Create a one dimensional box */ +Datum +cube_f8_f8(PG_FUNCTION_ARGS) +{ + double x0 = PG_GETARG_FLOAT8(0); + double x1 = PG_GETARG_FLOAT8(1); + NDBOX *result; + int size; + + if (x0 == x1) + { + size = POINT_SIZE(1); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, 1); + SET_POINT_BIT(result); + result->x[0] = x0; + } + else + { + size = CUBE_SIZE(1); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, 1); + result->x[0] = x0; + result->x[1] = x1; + } + + PG_RETURN_NDBOX_P(result); +} + +/* Add a dimension to an existing cube with the same values for the new + coordinate */ +Datum +cube_c_f8(PG_FUNCTION_ARGS) +{ + NDBOX *cube = PG_GETARG_NDBOX_P(0); + double x = PG_GETARG_FLOAT8(1); + NDBOX *result; + int size; + int i; + + if (DIM(cube) + 1 > CUBE_MAX_DIM) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("can't extend cube"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + + if (IS_POINT(cube)) + { + size = POINT_SIZE((DIM(cube) + 1)); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, DIM(cube) + 1); + SET_POINT_BIT(result); + for (i = 0; i < DIM(cube); i++) + result->x[i] = cube->x[i]; + result->x[DIM(result) - 1] = x; + } + else + { + size = CUBE_SIZE((DIM(cube) + 1)); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, DIM(cube) + 1); + for (i = 0; i < DIM(cube); i++) + { + result->x[i] = cube->x[i]; + result->x[DIM(result) + i] = cube->x[DIM(cube) + i]; + } + result->x[DIM(result) - 1] = x; + result->x[2 * DIM(result) - 1] = x; + } + + PG_FREE_IF_COPY(cube, 0); + PG_RETURN_NDBOX_P(result); +} + +/* Add a dimension to an existing cube */ +Datum +cube_c_f8_f8(PG_FUNCTION_ARGS) +{ + NDBOX *cube = PG_GETARG_NDBOX_P(0); + double x1 = PG_GETARG_FLOAT8(1); + double x2 = PG_GETARG_FLOAT8(2); + NDBOX *result; + int size; + int i; + + if (DIM(cube) + 1 > CUBE_MAX_DIM) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("can't extend cube"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + + if (IS_POINT(cube) && (x1 == x2)) + { + size = POINT_SIZE((DIM(cube) + 1)); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, DIM(cube) + 1); + SET_POINT_BIT(result); + for (i = 0; i < DIM(cube); i++) + result->x[i] = cube->x[i]; + result->x[DIM(result) - 1] = x1; + } + else + { + size = CUBE_SIZE((DIM(cube) + 1)); + result = (NDBOX *) palloc0(size); + SET_VARSIZE(result, size); + SET_DIM(result, DIM(cube) + 1); + for (i = 0; i < DIM(cube); i++) + { + result->x[i] = LL_COORD(cube, i); + result->x[DIM(result) + i] = UR_COORD(cube, i); + } + result->x[DIM(result) - 1] = x1; + result->x[2 * DIM(result) - 1] = x2; + } + + PG_FREE_IF_COPY(cube, 0); + PG_RETURN_NDBOX_P(result); +} diff --git a/contrib/cube/cube.control b/contrib/cube/cube.control new file mode 100644 index 0000000..3e238fc --- /dev/null +++ b/contrib/cube/cube.control @@ -0,0 +1,6 @@ +# cube extension +comment = 'data type for multidimensional cubes' +default_version = '1.4' +module_pathname = '$libdir/cube' +relocatable = true +trusted = true diff --git a/contrib/cube/cubedata.h b/contrib/cube/cubedata.h new file mode 100644 index 0000000..dbe7d4f --- /dev/null +++ b/contrib/cube/cubedata.h @@ -0,0 +1,69 @@ +/* contrib/cube/cubedata.h */ + +/* + * This limit is pretty arbitrary, but don't make it so large that you + * risk overflow in sizing calculations. + */ +#define CUBE_MAX_DIM (100) + +typedef struct NDBOX +{ + /* varlena header (do not touch directly!) */ + int32 vl_len_; + + /*---------- + * Header contains info about NDBOX. For binary compatibility with old + * versions, it is defined as "unsigned int". + * + * Following information is stored: + * + * bits 0-7 : number of cube dimensions; + * bits 8-30 : unused, initialize to zero; + * bit 31 : point flag. If set, the upper right coordinates are not + * stored, and are implicitly the same as the lower left + * coordinates. + *---------- + */ + unsigned int header; + + /* + * The lower left coordinates for each dimension come first, followed by + * upper right coordinates unless the point flag is set. + */ + double x[FLEXIBLE_ARRAY_MEMBER]; +} NDBOX; + +/* NDBOX access macros */ +#define POINT_BIT 0x80000000 +#define DIM_MASK 0x7fffffff + +#define IS_POINT(cube) ( ((cube)->header & POINT_BIT) != 0 ) +#define SET_POINT_BIT(cube) ( (cube)->header |= POINT_BIT ) +#define DIM(cube) ( (cube)->header & DIM_MASK ) +#define SET_DIM(cube, _dim) ( (cube)->header = ((cube)->header & ~DIM_MASK) | (_dim) ) + +#define LL_COORD(cube, i) ( (cube)->x[i] ) +#define UR_COORD(cube, i) ( IS_POINT(cube) ? (cube)->x[i] : (cube)->x[(i) + DIM(cube)] ) + +#define POINT_SIZE(_dim) (offsetof(NDBOX, x) + sizeof(double)*(_dim)) +#define CUBE_SIZE(_dim) (offsetof(NDBOX, x) + sizeof(double)*(_dim)*2) + +/* fmgr interface macros */ +#define DatumGetNDBOXP(x) ((NDBOX *) PG_DETOAST_DATUM(x)) +#define PG_GETARG_NDBOX_P(x) DatumGetNDBOXP(PG_GETARG_DATUM(x)) +#define PG_RETURN_NDBOX_P(x) PG_RETURN_POINTER(x) + +/* GiST operator strategy numbers */ +#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(); +extern void cube_scanner_init(const char *str); +extern void cube_scanner_finish(void); + +/* in cubeparse.y */ +extern int cube_yyparse(NDBOX **result); diff --git a/contrib/cube/cubeparse.c b/contrib/cube/cubeparse.c new file mode 100644 index 0000000..95a05c7 --- /dev/null +++ b/contrib/cube/cubeparse.c @@ -0,0 +1,1719 @@ +/* A Bison parser, made by GNU Bison 3.3.2. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Undocumented macros, especially those whose name start with YY_, + are private implementation details. Do not rely on them. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.3.2" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + +/* Substitute the variable and function names. */ +#define yyparse cube_yyparse +#define yylex cube_yylex +#define yyerror cube_yyerror +#define yydebug cube_yydebug +#define yynerrs cube_yynerrs + +#define yylval cube_yylval +#define yychar cube_yychar + +/* First part of user prologue. */ +#line 1 "cubeparse.y" /* yacc.c:337 */ + +/* contrib/cube/cubeparse.y */ + +/* NdBox = [(lowerleft),(upperright)] */ +/* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */ + +#include "postgres.h" + +#include "cubedata.h" +#include "utils/float.h" + +/* All grammar constructs return strings */ +#define YYSTYPE char * + +/* + * Bison doesn't allocate anything that needs to live across parser calls, + * so we can easily have it use palloc instead of malloc. This prevents + * memory leaks if we error out during parsing. Note this only works with + * bison >= 2.0. However, in bison 1.875 the default is to use alloca() + * if possible, so there's not really much problem anyhow, at least if + * you're building with gcc. + */ +#define YYMALLOC palloc +#define YYFREE pfree + +static char *scanbuf; +static int scanbuflen; + +static int item_count(const char *s, char delim); +static NDBOX *write_box(int dim, char *str1, char *str2); +static NDBOX *write_point_as_box(int dim, char *str); + + +#line 112 "cubeparse.c" /* yacc.c:337 */ +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + + +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int cube_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + CUBEFLOAT = 258, + O_PAREN = 259, + C_PAREN = 260, + O_BRACKET = 261, + C_BRACKET = 262, + COMMA = 263 + }; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + +extern YYSTYPE cube_yylval; + +int cube_yyparse (NDBOX **result); + + + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 10 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 17 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 9 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 4 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 9 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 19 + +#define YYUNDEFTOK 2 +#define YYMAXUTOK 263 + +/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, with out-of-bounds checking. */ +#define YYTRANSLATE(YYX) \ + ((unsigned) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint8 yyrline[] = +{ + 0, 46, 46, 73, 100, 118, 137, 141, 147, 153 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "CUBEFLOAT", "O_PAREN", "C_PAREN", + "O_BRACKET", "C_BRACKET", "COMMA", "$accept", "box", "paren_list", + "list", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263 +}; +# endif + +#define YYPACT_NINF -4 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-4))) + +#define YYTABLE_NINF -1 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int8 yypact[] = +{ + -2, -4, 0, 3, 10, 4, 5, -4, 1, 6, + -4, 3, 12, -4, 3, -4, -4, 9, -4 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 8, 0, 0, 0, 4, 5, 7, 0, 0, + 1, 0, 0, 6, 0, 3, 9, 0, 2 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -4, -4, -3, 15 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 4, 5, 6 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_uint8 yytable[] = +{ + 9, 1, 2, 1, 3, 7, 13, 2, 15, 12, + 10, 17, 11, 12, 14, 16, 18, 8 +}; + +static const yytype_uint8 yycheck[] = +{ + 3, 3, 4, 3, 6, 5, 5, 4, 11, 8, + 0, 14, 8, 8, 8, 3, 7, 2 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 4, 6, 10, 11, 12, 5, 12, 11, + 0, 8, 8, 5, 8, 11, 3, 11, 7 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 9, 10, 10, 10, 10, 11, 11, 12, 12 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 5, 3, 1, 1, 3, 2, 1, 3 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ + do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (result, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ + while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, result); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*-----------------------------------. +| Print this symbol's value on YYO. | +`-----------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, NDBOX **result) +{ + FILE *yyoutput = yyo; + YYUSE (yyoutput); + YYUSE (result); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyo, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*---------------------------. +| Print this symbol on YYO. | +`---------------------------*/ + +static void +yy_symbol_print (FILE *yyo, int yytype, YYSTYPE const * const yyvaluep, NDBOX **result) +{ + YYFPRINTF (yyo, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyo, yytype, yyvaluep, result); + YYFPRINTF (yyo, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, NDBOX **result) +{ + unsigned long yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &yyvsp[(yyi + 1) - (yynrhs)] + , result); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, result); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + else + goto append; + + append: + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return (YYSIZE_T) (yystpcpy (yyres, yystr) - yyres); +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) + yysize = yysize1; + else + return 2; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: /* Avoid compiler warnings. */ + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) + yysize = yysize1; + else + return 2; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, NDBOX **result) +{ + YYUSE (yyvaluep); + YYUSE (result); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (NDBOX **result) +{ + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + + +/*------------------------------------------------------------. +| yynewstate -- push a new state, which is found in yystate. | +`------------------------------------------------------------*/ +yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + +/*--------------------------------------------------------------------. +| yynewstate -- set current state (the top of the stack) to yystate. | +`--------------------------------------------------------------------*/ +yysetstate: + *yyssp = (yytype_int16) yystate; + + if (yyss + yystacksize - 1 <= yyssp) +#if !defined yyoverflow && !defined YYSTACK_RELOCATE + goto yyexhaustedlab; +#else + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = (YYSIZE_T) (yyssp - yyss + 1); + +# if defined yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + yyss = yyss1; + yyvs = yyvs1; + } +# else /* defined YYSTACK_RELOCATE */ + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } +#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 47 "cubeparse.y" /* yacc.c:1652 */ + { + int dim; + + dim = item_count(yyvsp[-3], ','); + if (item_count(yyvsp[-1], ',') != dim) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("Different point dimensions in (%s) and (%s).", + yyvsp[-3], yyvsp[-1]))); + YYABORT; + } + if (dim > CUBE_MAX_DIM) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + YYABORT; + } + + *result = write_box( dim, yyvsp[-3], yyvsp[-1] ); + } +#line 1268 "cubeparse.c" /* yacc.c:1652 */ + break; + + case 3: +#line 74 "cubeparse.y" /* yacc.c:1652 */ + { + int dim; + + dim = item_count(yyvsp[-2], ','); + if (item_count(yyvsp[0], ',') != dim) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("Different point dimensions in (%s) and (%s).", + yyvsp[-2], yyvsp[0]))); + YYABORT; + } + if (dim > CUBE_MAX_DIM) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + YYABORT; + } + + *result = write_box( dim, yyvsp[-2], yyvsp[0] ); + } +#line 1298 "cubeparse.c" /* yacc.c:1652 */ + break; + + case 4: +#line 101 "cubeparse.y" /* yacc.c:1652 */ + { + int dim; + + dim = item_count(yyvsp[0], ','); + if (dim > CUBE_MAX_DIM) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + YYABORT; + } + + *result = write_point_as_box(dim, yyvsp[0]); + } +#line 1319 "cubeparse.c" /* yacc.c:1652 */ + break; + + case 5: +#line 119 "cubeparse.y" /* yacc.c:1652 */ + { + int dim; + + dim = item_count(yyvsp[0], ','); + if (dim > CUBE_MAX_DIM) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + YYABORT; + } + + *result = write_point_as_box(dim, yyvsp[0]); + } +#line 1340 "cubeparse.c" /* yacc.c:1652 */ + break; + + case 6: +#line 138 "cubeparse.y" /* yacc.c:1652 */ + { + yyval = yyvsp[-1]; + } +#line 1348 "cubeparse.c" /* yacc.c:1652 */ + break; + + case 7: +#line 142 "cubeparse.y" /* yacc.c:1652 */ + { + yyval = pstrdup(""); + } +#line 1356 "cubeparse.c" /* yacc.c:1652 */ + break; + + case 8: +#line 148 "cubeparse.y" /* yacc.c:1652 */ + { + /* alloc enough space to be sure whole list will fit */ + yyval = palloc(scanbuflen + 1); + strcpy(yyval, yyvsp[0]); + } +#line 1366 "cubeparse.c" /* yacc.c:1652 */ + break; + + case 9: +#line 154 "cubeparse.y" /* yacc.c:1652 */ + { + yyval = yyvsp[-2]; + strcat(yyval, ","); + strcat(yyval, yyvsp[0]); + } +#line 1376 "cubeparse.c" /* yacc.c:1652 */ + break; + + +#line 1380 "cubeparse.c" /* yacc.c:1652 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + { + const int yylhs = yyr1[yyn] - YYNTOKENS; + const int yyi = yypgoto[yylhs] + *yyssp; + yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp + ? yytable[yyi] + : yydefgoto[yylhs]); + } + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (result, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (result, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, result); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + /* Pacify compilers when the user code never invokes YYERROR and the + label yyerrorlab therefore never appears in user code. */ + if (0) + YYERROR; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, result); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (result, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + + +/*-----------------------------------------------------. +| yyreturn -- parsing is finished, return the result. | +`-----------------------------------------------------*/ +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, result); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, result); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 161 "cubeparse.y" /* yacc.c:1918 */ + + +/* This assumes the string has been normalized by productions above */ +static int +item_count(const char *s, char delim) +{ + int nitems = 0; + + if (s[0] != '\0') + { + nitems++; + while ((s = strchr(s, delim)) != NULL) + { + nitems++; + s++; + } + } + return nitems; +} + +static NDBOX * +write_box(int dim, char *str1, char *str2) +{ + NDBOX *bp; + char *s; + char *endptr; + int i; + int size = CUBE_SIZE(dim); + bool point = true; + + bp = palloc0(size); + SET_VARSIZE(bp, size); + SET_DIM(bp, dim); + + s = str1; + i = 0; + if (dim > 0) + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); + while ((s = strchr(s, ',')) != NULL) + { + s++; + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); + } + Assert(i == dim); + + s = str2; + if (dim > 0) + { + bp->x[i] = float8in_internal(s, &endptr, "cube", str2); + /* code this way to do right thing with NaN */ + point &= (bp->x[i] == bp->x[0]); + i++; + } + while ((s = strchr(s, ',')) != NULL) + { + s++; + bp->x[i] = float8in_internal(s, &endptr, "cube", str2); + point &= (bp->x[i] == bp->x[i - dim]); + i++; + } + Assert(i == dim * 2); + + if (point) + { + /* + * The value turned out to be a point, ie. all the upper-right + * coordinates were equal to the lower-left coordinates. Resize the + * cube we constructed. Note: we don't bother to repalloc() it + * smaller, as it's unlikely that the tiny amount of memory freed + * that way would be useful, and the output is always short-lived. + */ + size = POINT_SIZE(dim); + SET_VARSIZE(bp, size); + SET_POINT_BIT(bp); + } + + return bp; +} + +static NDBOX * +write_point_as_box(int dim, char *str) +{ + NDBOX *bp; + int i, + size; + char *s; + char *endptr; + + size = POINT_SIZE(dim); + bp = palloc0(size); + SET_VARSIZE(bp, size); + SET_DIM(bp, dim); + SET_POINT_BIT(bp); + + s = str; + i = 0; + if (dim > 0) + bp->x[i++] = float8in_internal(s, &endptr, "cube", str); + while ((s = strchr(s, ',')) != NULL) + { + s++; + bp->x[i++] = float8in_internal(s, &endptr, "cube", str); + } + Assert(i == dim); + + return bp; +} + +#include "cubescan.c" diff --git a/contrib/cube/cubeparse.y b/contrib/cube/cubeparse.y new file mode 100644 index 0000000..deb2efd --- /dev/null +++ b/contrib/cube/cubeparse.y @@ -0,0 +1,269 @@ +%{ +/* contrib/cube/cubeparse.y */ + +/* NdBox = [(lowerleft),(upperright)] */ +/* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */ + +#include "postgres.h" + +#include "cubedata.h" +#include "utils/float.h" + +/* All grammar constructs return strings */ +#define YYSTYPE char * + +/* + * Bison doesn't allocate anything that needs to live across parser calls, + * so we can easily have it use palloc instead of malloc. This prevents + * memory leaks if we error out during parsing. Note this only works with + * bison >= 2.0. However, in bison 1.875 the default is to use alloca() + * if possible, so there's not really much problem anyhow, at least if + * you're building with gcc. + */ +#define YYMALLOC palloc +#define YYFREE pfree + +static char *scanbuf; +static int scanbuflen; + +static int item_count(const char *s, char delim); +static NDBOX *write_box(int dim, char *str1, char *str2); +static NDBOX *write_point_as_box(int dim, char *str); + +%} + +/* BISON Declarations */ +%parse-param {NDBOX **result} +%expect 0 +%name-prefix="cube_yy" + +%token CUBEFLOAT O_PAREN C_PAREN O_BRACKET C_BRACKET COMMA +%start box + +/* Grammar follows */ +%% + +box: O_BRACKET paren_list COMMA paren_list C_BRACKET + { + int dim; + + dim = item_count($2, ','); + if (item_count($4, ',') != dim) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("Different point dimensions in (%s) and (%s).", + $2, $4))); + YYABORT; + } + if (dim > CUBE_MAX_DIM) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + YYABORT; + } + + *result = write_box( dim, $2, $4 ); + } + + | paren_list COMMA paren_list + { + int dim; + + dim = item_count($1, ','); + if (item_count($3, ',') != dim) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("Different point dimensions in (%s) and (%s).", + $1, $3))); + YYABORT; + } + if (dim > CUBE_MAX_DIM) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + YYABORT; + } + + *result = write_box( dim, $1, $3 ); + } + + | paren_list + { + int dim; + + dim = item_count($1, ','); + if (dim > CUBE_MAX_DIM) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + YYABORT; + } + + *result = write_point_as_box(dim, $1); + } + + | list + { + int dim; + + dim = item_count($1, ','); + if (dim > CUBE_MAX_DIM) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + errdetail("A cube cannot have more than %d dimensions.", + CUBE_MAX_DIM))); + YYABORT; + } + + *result = write_point_as_box(dim, $1); + } + ; + +paren_list: O_PAREN list C_PAREN + { + $$ = $2; + } + | O_PAREN C_PAREN + { + $$ = pstrdup(""); + } + ; + +list: CUBEFLOAT + { + /* alloc enough space to be sure whole list will fit */ + $$ = palloc(scanbuflen + 1); + strcpy($$, $1); + } + | list COMMA CUBEFLOAT + { + $$ = $1; + strcat($$, ","); + strcat($$, $3); + } + ; + +%% + +/* This assumes the string has been normalized by productions above */ +static int +item_count(const char *s, char delim) +{ + int nitems = 0; + + if (s[0] != '\0') + { + nitems++; + while ((s = strchr(s, delim)) != NULL) + { + nitems++; + s++; + } + } + return nitems; +} + +static NDBOX * +write_box(int dim, char *str1, char *str2) +{ + NDBOX *bp; + char *s; + char *endptr; + int i; + int size = CUBE_SIZE(dim); + bool point = true; + + bp = palloc0(size); + SET_VARSIZE(bp, size); + SET_DIM(bp, dim); + + s = str1; + i = 0; + if (dim > 0) + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); + while ((s = strchr(s, ',')) != NULL) + { + s++; + bp->x[i++] = float8in_internal(s, &endptr, "cube", str1); + } + Assert(i == dim); + + s = str2; + if (dim > 0) + { + bp->x[i] = float8in_internal(s, &endptr, "cube", str2); + /* code this way to do right thing with NaN */ + point &= (bp->x[i] == bp->x[0]); + i++; + } + while ((s = strchr(s, ',')) != NULL) + { + s++; + bp->x[i] = float8in_internal(s, &endptr, "cube", str2); + point &= (bp->x[i] == bp->x[i - dim]); + i++; + } + Assert(i == dim * 2); + + if (point) + { + /* + * The value turned out to be a point, ie. all the upper-right + * coordinates were equal to the lower-left coordinates. Resize the + * cube we constructed. Note: we don't bother to repalloc() it + * smaller, as it's unlikely that the tiny amount of memory freed + * that way would be useful, and the output is always short-lived. + */ + size = POINT_SIZE(dim); + SET_VARSIZE(bp, size); + SET_POINT_BIT(bp); + } + + return bp; +} + +static NDBOX * +write_point_as_box(int dim, char *str) +{ + NDBOX *bp; + int i, + size; + char *s; + char *endptr; + + size = POINT_SIZE(dim); + bp = palloc0(size); + SET_VARSIZE(bp, size); + SET_DIM(bp, dim); + SET_POINT_BIT(bp); + + s = str; + i = 0; + if (dim > 0) + bp->x[i++] = float8in_internal(s, &endptr, "cube", str); + while ((s = strchr(s, ',')) != NULL) + { + s++; + bp->x[i++] = float8in_internal(s, &endptr, "cube", str); + } + Assert(i == dim); + + return bp; +} + +#include "cubescan.c" diff --git a/contrib/cube/cubescan.c b/contrib/cube/cubescan.c new file mode 100644 index 0000000..0226564 --- /dev/null +++ b/contrib/cube/cubescan.c @@ -0,0 +1,2115 @@ +#line 2 "cubescan.c" + +#line 4 "cubescan.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define yy_create_buffer cube_yy_create_buffer +#define yy_delete_buffer cube_yy_delete_buffer +#define yy_scan_buffer cube_yy_scan_buffer +#define yy_scan_string cube_yy_scan_string +#define yy_scan_bytes cube_yy_scan_bytes +#define yy_init_buffer cube_yy_init_buffer +#define yy_flush_buffer cube_yy_flush_buffer +#define yy_load_buffer_state cube_yy_load_buffer_state +#define yy_switch_to_buffer cube_yy_switch_to_buffer +#define yypush_buffer_state cube_yypush_buffer_state +#define yypop_buffer_state cube_yypop_buffer_state +#define yyensure_buffer_stack cube_yyensure_buffer_stack +#define yy_flex_debug cube_yy_flex_debug +#define yyin cube_yyin +#define yyleng cube_yyleng +#define yylex cube_yylex +#define yylineno cube_yylineno +#define yyout cube_yyout +#define yyrestart cube_yyrestart +#define yytext cube_yytext +#define yywrap cube_yywrap +#define yyalloc cube_yyalloc +#define yyrealloc cube_yyrealloc +#define yyfree cube_yyfree + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define cube_yy_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer cube_yy_create_buffer +#endif + +#ifdef yy_delete_buffer +#define cube_yy_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer cube_yy_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define cube_yy_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer cube_yy_scan_buffer +#endif + +#ifdef yy_scan_string +#define cube_yy_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string cube_yy_scan_string +#endif + +#ifdef yy_scan_bytes +#define cube_yy_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes cube_yy_scan_bytes +#endif + +#ifdef yy_init_buffer +#define cube_yy_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer cube_yy_init_buffer +#endif + +#ifdef yy_flush_buffer +#define cube_yy_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer cube_yy_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define cube_yy_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state cube_yy_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define cube_yy_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer cube_yy_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define cube_yypush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state cube_yypush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define cube_yypop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state cube_yypop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define cube_yyensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack cube_yyensure_buffer_stack +#endif + +#ifdef yylex +#define cube_yylex_ALREADY_DEFINED +#else +#define yylex cube_yylex +#endif + +#ifdef yyrestart +#define cube_yyrestart_ALREADY_DEFINED +#else +#define yyrestart cube_yyrestart +#endif + +#ifdef yylex_init +#define cube_yylex_init_ALREADY_DEFINED +#else +#define yylex_init cube_yylex_init +#endif + +#ifdef yylex_init_extra +#define cube_yylex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra cube_yylex_init_extra +#endif + +#ifdef yylex_destroy +#define cube_yylex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy cube_yylex_destroy +#endif + +#ifdef yyget_debug +#define cube_yyget_debug_ALREADY_DEFINED +#else +#define yyget_debug cube_yyget_debug +#endif + +#ifdef yyset_debug +#define cube_yyset_debug_ALREADY_DEFINED +#else +#define yyset_debug cube_yyset_debug +#endif + +#ifdef yyget_extra +#define cube_yyget_extra_ALREADY_DEFINED +#else +#define yyget_extra cube_yyget_extra +#endif + +#ifdef yyset_extra +#define cube_yyset_extra_ALREADY_DEFINED +#else +#define yyset_extra cube_yyset_extra +#endif + +#ifdef yyget_in +#define cube_yyget_in_ALREADY_DEFINED +#else +#define yyget_in cube_yyget_in +#endif + +#ifdef yyset_in +#define cube_yyset_in_ALREADY_DEFINED +#else +#define yyset_in cube_yyset_in +#endif + +#ifdef yyget_out +#define cube_yyget_out_ALREADY_DEFINED +#else +#define yyget_out cube_yyget_out +#endif + +#ifdef yyset_out +#define cube_yyset_out_ALREADY_DEFINED +#else +#define yyset_out cube_yyset_out +#endif + +#ifdef yyget_leng +#define cube_yyget_leng_ALREADY_DEFINED +#else +#define yyget_leng cube_yyget_leng +#endif + +#ifdef yyget_text +#define cube_yyget_text_ALREADY_DEFINED +#else +#define yyget_text cube_yyget_text +#endif + +#ifdef yyget_lineno +#define cube_yyget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno cube_yyget_lineno +#endif + +#ifdef yyset_lineno +#define cube_yyset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno cube_yyset_lineno +#endif + +#ifdef yywrap +#define cube_yywrap_ALREADY_DEFINED +#else +#define yywrap cube_yywrap +#endif + +#ifdef yyalloc +#define cube_yyalloc_ALREADY_DEFINED +#else +#define yyalloc cube_yyalloc +#endif + +#ifdef yyrealloc +#define cube_yyrealloc_ALREADY_DEFINED +#else +#define yyrealloc cube_yyrealloc +#endif + +#ifdef yyfree +#define cube_yyfree_ALREADY_DEFINED +#else +#define yyfree cube_yyfree +#endif + +#ifdef yytext +#define cube_yytext_ALREADY_DEFINED +#else +#define yytext cube_yytext +#endif + +#ifdef yyleng +#define cube_yyleng_ALREADY_DEFINED +#else +#define yyleng cube_yyleng +#endif + +#ifdef yyin +#define cube_yyin_ALREADY_DEFINED +#else +#define yyin cube_yyin +#endif + +#ifdef yyout +#define cube_yyout_ALREADY_DEFINED +#else +#define yyout cube_yyout +#endif + +#ifdef yy_flex_debug +#define cube_yy_flex_debug_ALREADY_DEFINED +#else +#define yy_flex_debug cube_yy_flex_debug +#endif + +#ifdef yylineno +#define cube_yylineno_ALREADY_DEFINED +#else +#define yylineno cube_yylineno +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = NULL; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart ( FILE *input_file ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); +void yy_delete_buffer ( YY_BUFFER_STATE b ); +void yy_flush_buffer ( YY_BUFFER_STATE b ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state ( void ); + +static void yyensure_buffer_stack ( void ); +static void yy_load_buffer_state ( void ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); + +void *yyalloc ( yy_size_t ); +void *yyrealloc ( void *, yy_size_t ); +void yyfree ( void * ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define cube_yywrap() (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +FILE *yyin = NULL, *yyout = NULL; + +typedef int yy_state_type; + +extern int yylineno; +int yylineno = 1; + +extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state ( void ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); +static int yy_get_next_buffer ( void ); +static void yynoreturn yy_fatal_error ( const char* msg ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; +#define YY_NUM_RULES 11 +#define YY_END_OF_BUFFER 12 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[37] = + { 0, + 0, 0, 12, 10, 9, 9, 6, 7, 10, 8, + 10, 1, 10, 10, 4, 5, 9, 0, 1, 0, + 1, 1, 0, 0, 0, 1, 0, 1, 2, 3, + 0, 0, 0, 0, 2, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 1, 1, 1, 1, 1, 4, + 5, 1, 6, 7, 6, 8, 1, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, + 1, 1, 1, 1, 10, 1, 1, 1, 11, 12, + 1, 1, 13, 1, 1, 1, 1, 14, 1, 1, + 1, 1, 1, 15, 1, 1, 1, 1, 16, 1, + 17, 1, 18, 1, 1, 1, 10, 1, 1, 1, + + 11, 12, 1, 1, 13, 1, 1, 1, 1, 14, + 1, 1, 1, 1, 1, 15, 1, 1, 1, 1, + 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[19] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1 + } ; + +static const flex_int16_t yy_base[37] = + { 0, + 0, 0, 53, 54, 17, 19, 54, 54, 15, 54, + 43, 21, 37, 40, 54, 54, 23, 40, 0, 34, + 22, 25, 29, 35, 32, 28, 36, 35, 30, 54, + 28, 28, 25, 11, 54, 54 + } ; + +static const flex_int16_t yy_def[37] = + { 0, + 36, 1, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 12, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 0 + } ; + +static const flex_int16_t yy_nxt[73] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 4, + 4, 4, 13, 14, 4, 4, 15, 16, 17, 17, + 17, 17, 18, 19, 17, 17, 35, 20, 22, 19, + 21, 23, 23, 26, 27, 23, 26, 28, 23, 34, + 33, 32, 31, 28, 28, 30, 29, 24, 21, 25, + 24, 21, 36, 3, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36 + } ; + +static const flex_int16_t yy_chk[73] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, + 6, 6, 9, 9, 17, 17, 34, 9, 12, 12, + 21, 12, 21, 22, 23, 22, 26, 23, 26, 33, + 32, 31, 29, 28, 27, 25, 24, 20, 18, 14, + 13, 11, 3, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "cubescan.l" +#line 2 "cubescan.l" +/* + * A scanner for EMP-style numeric ranges + * contrib/cube/cubescan.l + */ + +/* LCOV_EXCL_START */ + +/* No reason to constrain amount of data slurped */ +#define YY_READ_BUF_SIZE 16777216 + +/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */ +#undef fprintf +#define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg) + +static void +fprintf_to_ereport(const char *fmt, const char *msg) +{ + ereport(ERROR, (errmsg_internal("%s", msg))); +} + +/* Handles to the buffer that the lexer uses internally */ +static YY_BUFFER_STATE scanbufhandle; +/* this is now declared in cubeparse.y: */ +/* static char *scanbuf; */ +/* static int scanbuflen; */ +#line 754 "cubescan.c" +#define YY_NO_INPUT 1 +#line 756 "cubescan.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals ( void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( void ); + +int yyget_debug ( void ); + +void yyset_debug ( int debug_flag ); + +YY_EXTRA_TYPE yyget_extra ( void ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in ( void ); + +void yyset_in ( FILE * _in_str ); + +FILE *yyget_out ( void ); + +void yyset_out ( FILE * _out_str ); + + int yyget_leng ( void ); + +char *yyget_text ( void ); + +int yyget_lineno ( void ); + +void yyset_lineno ( int _line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( void ); +#else +extern int yywrap ( void ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * ); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( void ); +#else +static int input ( void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + { +#line 46 "cubescan.l" + + +#line 974 "cubescan.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 37 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 36 ); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 48 "cubescan.l" +yylval = yytext; return CUBEFLOAT; + YY_BREAK +case 2: +YY_RULE_SETUP +#line 49 "cubescan.l" +yylval = yytext; return CUBEFLOAT; + YY_BREAK +case 3: +YY_RULE_SETUP +#line 50 "cubescan.l" +yylval = yytext; return CUBEFLOAT; + YY_BREAK +case 4: +YY_RULE_SETUP +#line 51 "cubescan.l" +yylval = "("; return O_BRACKET; + YY_BREAK +case 5: +YY_RULE_SETUP +#line 52 "cubescan.l" +yylval = ")"; return C_BRACKET; + YY_BREAK +case 6: +YY_RULE_SETUP +#line 53 "cubescan.l" +yylval = "("; return O_PAREN; + YY_BREAK +case 7: +YY_RULE_SETUP +#line 54 "cubescan.l" +yylval = ")"; return C_PAREN; + YY_BREAK +case 8: +YY_RULE_SETUP +#line 55 "cubescan.l" +yylval = ","; return COMMA; + YY_BREAK +case 9: +/* rule 9 can match eol */ +YY_RULE_SETUP +#line 56 "cubescan.l" +/* discard spaces */ + YY_BREAK +case 10: +YY_RULE_SETUP +#line 57 "cubescan.l" +return yytext[0]; /* alert parser of the garbage */ + YY_BREAK +case 11: +YY_RULE_SETUP +#line 59 "cubescan.l" +YY_FATAL_ERROR( "flex scanner jammed" ); + YY_BREAK +#line 1083 "cubescan.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + yy_state_type yy_current_state; + char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 37 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + int yy_is_jam; + char *yy_cp = (yy_c_buf_p); + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 37 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 36); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return 0; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf ); + + yyfree( (void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr ) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg ) +{ + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param _line_number line number + * + */ +void yyset_lineno (int _line_number ) +{ + + yylineno = _line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str ) +{ + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str ) +{ + yyout = _out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int _bdebug ) +{ + yy_flex_debug = _bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = NULL; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = NULL; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n ) +{ + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s ) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 59 "cubescan.l" + + +/* LCOV_EXCL_STOP */ + +/* result is not used, but Bison expects this signature */ +void +yyerror(NDBOX **result, const char *message) +{ + if (*yytext == YY_END_OF_BUFFER_CHAR) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + /* translator: %s is typically "syntax error" */ + errdetail("%s at end of input", message))); + } + else + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + /* translator: first %s is typically "syntax error" */ + errdetail("%s at or near \"%s\"", message, yytext))); + } +} + + +/* + * Called before any actual parsing is done + */ +void +cube_scanner_init(const char *str) +{ + Size slen = strlen(str); + + /* + * Might be left over after ereport() + */ + if (YY_CURRENT_BUFFER) + yy_delete_buffer(YY_CURRENT_BUFFER); + + /* + * Make a scan buffer with special termination needed by flex. + */ + scanbuflen = slen; + scanbuf = palloc(slen + 2); + memcpy(scanbuf, str, slen); + scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR; + scanbufhandle = yy_scan_buffer(scanbuf, slen + 2); + + BEGIN(INITIAL); +} + + +/* + * Called after parsing is done to clean up after cube_scanner_init() + */ +void +cube_scanner_finish(void) +{ + yy_delete_buffer(scanbufhandle); + pfree(scanbuf); +} + diff --git a/contrib/cube/cubescan.l b/contrib/cube/cubescan.l new file mode 100644 index 0000000..bd400e3 --- /dev/null +++ b/contrib/cube/cubescan.l @@ -0,0 +1,121 @@ +%{ +/* + * A scanner for EMP-style numeric ranges + * contrib/cube/cubescan.l + */ + +/* LCOV_EXCL_START */ + +/* No reason to constrain amount of data slurped */ +#define YY_READ_BUF_SIZE 16777216 + +/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */ +#undef fprintf +#define fprintf(file, fmt, msg) fprintf_to_ereport(fmt, msg) + +static void +fprintf_to_ereport(const char *fmt, const char *msg) +{ + ereport(ERROR, (errmsg_internal("%s", msg))); +} + +/* Handles to the buffer that the lexer uses internally */ +static YY_BUFFER_STATE scanbufhandle; +/* this is now declared in cubeparse.y: */ +/* static char *scanbuf; */ +/* static int scanbuflen; */ +%} + +%option 8bit +%option never-interactive +%option nodefault +%option noinput +%option nounput +%option noyywrap +%option warn +%option prefix="cube_yy" + + +n [0-9]+ +integer [+-]?{n} +real [+-]?({n}\.{n}?|\.{n}) +float ({integer}|{real})([eE]{integer})? +infinity [+-]?[iI][nN][fF]([iI][nN][iI][tT][yY])? +NaN [nN][aA][nN] + +%% + +{float} yylval = yytext; return CUBEFLOAT; +{infinity} yylval = yytext; return CUBEFLOAT; +{NaN} yylval = yytext; return CUBEFLOAT; +\[ yylval = "("; return O_BRACKET; +\] yylval = ")"; return C_BRACKET; +\( yylval = "("; return O_PAREN; +\) yylval = ")"; return C_PAREN; +\, yylval = ","; return COMMA; +[ \t\n\r\f]+ /* discard spaces */ +. return yytext[0]; /* alert parser of the garbage */ + +%% + +/* LCOV_EXCL_STOP */ + +/* result is not used, but Bison expects this signature */ +void +yyerror(NDBOX **result, const char *message) +{ + if (*yytext == YY_END_OF_BUFFER_CHAR) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + /* translator: %s is typically "syntax error" */ + errdetail("%s at end of input", message))); + } + else + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for cube"), + /* translator: first %s is typically "syntax error" */ + errdetail("%s at or near \"%s\"", message, yytext))); + } +} + + +/* + * Called before any actual parsing is done + */ +void +cube_scanner_init(const char *str) +{ + Size slen = strlen(str); + + /* + * Might be left over after ereport() + */ + if (YY_CURRENT_BUFFER) + yy_delete_buffer(YY_CURRENT_BUFFER); + + /* + * Make a scan buffer with special termination needed by flex. + */ + scanbuflen = slen; + scanbuf = palloc(slen + 2); + memcpy(scanbuf, str, slen); + scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR; + scanbufhandle = yy_scan_buffer(scanbuf, slen + 2); + + BEGIN(INITIAL); +} + + +/* + * Called after parsing is done to clean up after cube_scanner_init() + */ +void +cube_scanner_finish(void) +{ + yy_delete_buffer(scanbufhandle); + pfree(scanbuf); +} diff --git a/contrib/cube/data/test_cube.data b/contrib/cube/data/test_cube.data new file mode 100644 index 0000000..d67cd12 --- /dev/null +++ b/contrib/cube/data/test_cube.data @@ -0,0 +1,3100 @@ +(12699,9028),(12654,8987) +(22689,4680),(22614,4626) +(43263,47296),(43217,47217) +(6184,8397),(6182,8379) +(863,28537),(788,28456) +(33783,4733),(33746,4693) +(40456,47134),(40426,47087) +(45950,8153),(45887,8060) +(33433,36474),(33399,36460) +(41106,22017),(41086,21962) +(19214,36781),(19179,36767) +(11582,40823),(11498,40737) +(35565,5404),(35546,5360) +(26489,17387),(26405,17356) +(30874,13849),(30796,13814) +(38255,1619),(38227,1593) +(4445,32006),(4405,31914) +(3923,32921),(3876,32913) +(36054,39464),(36032,39434) +(46540,6780),(46524,6758) +(12184,45811),(12118,45787) +(13198,17090),(13143,17051) +(30939,44578),(30865,44486) +(12502,4939),(12431,4902) +(3250,1108),(3169,1063) +(34029,41240),(33976,41180) +(47057,44018),(46967,43927) +(699,10114),(686,10058) +(5925,26020),(5845,25979) +(9462,39388),(9382,39388) +(270,32616),(226,32607) +(3959,49145),(3861,49115) +(207,40886),(179,40879) +(48480,43312),(48412,43233) +(37183,37209),(37161,37110) +(13576,13505),(13521,13487) +(5877,1037),(5818,1036) +(6777,16694),(6776,16692) +(49362,13905),(49299,13845) +(29356,14606),(29313,14562) +(5492,6976),(5441,6971) +(288,49588),(204,49571) +(36698,37213),(36682,37158) +(718,41336),(645,41272) +(8725,23369),(8660,23333) +(40115,9894),(40025,9818) +(40051,41181),(40015,41153) +(5739,1740),(5715,1731) +(25120,27935),(25054,27876) +(27475,46084),(27447,46003) +(33197,3252),(33161,3245) +(10892,15691),(10869,15662) +(39012,44712),(38995,44640) +(4506,6484),(4458,6459) +(13970,26316),(13964,26236) +(28009,28104),(27968,28030) +(5991,27613),(5906,27607) +(23649,6338),(23610,6314) +(25942,10008),(25911,9928) +(25651,29943),(25590,29906) +(24555,40334),(24546,40330) +(46870,43762),(46789,43709) +(20030,2752),(19945,2687) +(30758,26754),(30718,26678) +(4320,44673),(4286,44625) +(1011,15576),(939,15574) +(41936,40699),(41854,40655) +(20594,19002),(20561,18995) +(9388,41056),(9325,41042) +(34771,46693),(34751,46645) +(49398,46359),(49332,46357) +(23115,35380),(23036,35306) +(46305,34840),(46283,34765) +(16768,21692),(16691,21647) +(28695,3128),(28654,3112) +(22182,7107),(22107,7074) +(14567,1210),(14468,1139) +(14156,37139),(14136,37119) +(33500,38351),(33477,38286) +(39983,41981),(39944,41954) +(26773,20824),(26719,20813) +(42516,22947),(42460,22932) +(26127,10701),(26044,10650) +(17808,13803),(17724,13710) +(14913,49873),(14849,49836) +(37013,820),(36955,736) +(39071,1399),(39022,1381) +(9785,42546),(9687,42540) +(13423,14066),(13354,14052) +(3417,14558),(3336,14478) +(25212,46368),(25128,46316) +(10124,39848),(10027,39820) +(39722,39226),(39656,39162) +(6298,28101),(6250,28076) +(45852,5846),(45809,5750) +(48292,4885),(48290,4841) +(18905,4454),(18894,4424) +(18965,43474),(18902,43444) +(39843,28239),(39761,28199) +(18087,44660),(18019,44632) +(33886,10382),(33794,10286) +(38383,13163),(38362,13092) +(18861,25050),(18842,24965) +(29887,14326),(29806,14274) +(18733,11644),(18698,11644) +(5119,37952),(5089,37950) +(16191,34884),(16149,34864) +(29544,1104),(29496,1062) +(27740,41555),(27701,41540) +(4672,4087),(4633,4060) +(45441,38994),(45377,38958) +(3272,1176),(3232,1146) +(12820,26606),(12790,26575) +(30910,7590),(30877,7512) +(42476,39152),(42377,39127) +(6562,38490),(6542,38447) +(30046,20332),(29988,20259) +(40723,15950),(40671,15949) +(4945,46857),(4908,46817) +(47986,16882),(47963,16877) +(9842,22339),(9805,22305) +(29831,23169),(29818,23122) +(12322,34404),(12250,34312) +(22846,11091),(22759,10992) +(47627,2424),(47603,2397) +(18375,43632),(18347,43577) +(40441,974),(40394,965) +(34260,10573),(34194,10522) +(32914,9549),(32828,9503) +(49023,37827),(48978,37799) +(22183,10691),(22111,10669) +(38036,15828),(38014,15759) +(34604,16801),(34508,16746) +(26737,29997),(26675,29976) +(47375,40298),(47293,40210) +(771,2661),(732,2649) +(28514,25659),(28504,25577) +(13438,46494),(13376,46455) +(7187,17877),(7125,17786) +(49957,43390),(49897,43384) +(26543,20067),(26482,20057) +(16416,29803),(16385,29724) +(36353,7484),(36286,7414) +(26498,3377),(26415,3358) +(28990,32205),(28936,32193) +(45005,3842),(45001,3816) +(21672,23566),(21603,23566) +(33360,43465),(33302,43429) +(29884,9544),(29838,9520) +(5599,15012),(5596,14930) +(22396,21481),(22344,21422) +(24810,14955),(24780,14887) +(47114,18866),(47081,18784) +(39013,39245),(38953,39237) +(12863,40534),(12803,40529) +(351,37068),(310,37019) +(12916,34327),(12891,34240) +(49191,2694),(49170,2628) +(24127,38407),(24050,38325) +(3264,23053),(3213,23007) +(8172,30385),(8144,30336) +(19630,35716),(19573,35640) +(42554,5148),(42521,5117) +(42168,33453),(42136,33426) +(17732,32093),(17666,32057) +(1039,16626),(1037,16587) +(21287,7757),(21265,7679) +(47063,8260),(47039,8225) +(38645,16238),(38561,16204) +(18258,25358),(18196,25341) +(30458,1742),(30458,1695) +(35147,9273),(35121,9233) +(7670,16625),(7642,16545) +(49503,23432),(49484,23383) +(31089,23146),(31062,23093) +(47758,2734),(47670,2703) +(35276,1027),(35259,972) +(26337,17603),(26313,17579) +(35649,16777),(35626,16777) +(42454,5105),(42362,5101) +(21682,24951),(21646,24920) +(48383,25174),(48303,25156) +(14672,3532),(14601,3460) +(22570,22587),(22515,22512) +(23566,25623),(23484,25573) +(9530,24542),(9504,24459) +(41271,451),(41236,401) +(5556,37528),(5502,37527) +(12479,25042),(12447,24991) +(16568,22916),(16499,22864) +(42700,13084),(42676,12992) +(35523,40973),(35504,40932) +(32948,16962),(32857,16901) +(7808,13469),(7712,13469) +(13920,35203),(13870,35131) +(22731,31563),(22658,31557) +(22909,43956),(22900,43857) +(33077,35080),(33074,35030) +(48064,29307),(48022,29280) +(20232,46682),(20212,46613) +(29949,16790),(29867,16711) +(30260,32029),(30180,31979) +(17184,34503),(17110,34482) +(16066,42687),(16039,42648) +(2947,19819),(2857,19788) +(4900,47934),(4818,47894) +(27193,19014),(27174,18976) +(15597,27948),(15590,27939) +(11090,28623),(11002,28589) +(26956,18651),(26920,18620) +(3107,47753),(3103,47711) +(6745,24151),(6711,24083) +(43923,19213),(43871,19124) +(33451,23578),(33370,23534) +(8944,20605),(8862,20601) +(14905,7536),(14892,7441) +(2412,18357),(2383,18354) +(37060,1443),(36974,1366) +(15501,6230),(15429,6190) +(30333,50),(30273,6) +(35567,9965),(35482,9912) +(49847,7128),(49798,7067) +(27685,36396),(27668,36384) +(43832,18491),(43825,18431) +(36849,34600),(36785,34589) +(2348,47938),(2307,47902) +(20473,22131),(20445,22113) +(38486,4293),(38471,4288) +(30611,30451),(30553,30400) +(3883,21299),(3819,21260) +(7696,37555),(7644,37534) +(22399,7913),(22317,7911) +(42565,38605),(42500,38598) +(36595,12151),(36500,12106) +(587,35217),(571,35123) +(5764,15300),(5764,15231) +(12003,21265),(11983,21210) +(42564,4803),(42470,4737) +(42359,36834),(42271,36746) +(44700,14680),(44658,14670) +(19690,5627),(19620,5607) +(17780,43602),(17714,43565) +(45073,3491),(45041,3434) +(35043,2136),(35017,2084) +(39653,19215),(39646,19198) +(23970,25560),(23935,25502) +(28698,49233),(28600,49223) +(30266,3605),(30245,3540) +(25538,7857),(25500,7791) +(17711,1757),(17708,1756) +(5248,594),(5190,587) +(2730,32454),(2671,32436) +(1722,49089),(1635,49067) +(40954,5743),(40921,5722) +(21382,4426),(21298,4331) +(7885,18629),(7872,18605) +(42838,6459),(42748,6451) +(8217,19894),(8207,19845) +(20489,18524),(20433,18520) +(17383,23559),(17309,23515) +(38952,38968),(38934,38913) +(44665,18137),(44636,18051) +(22416,41220),(22383,41213) +(9901,664),(9818,646) +(23475,21981),(23449,21973) +(41875,17991),(41818,17988) +(36517,47731),(36509,47713) +(37595,49849),(37581,49834) +(38771,32720),(38748,32684) +(810,38523),(736,38452) +(29695,14942),(29665,14907) +(31911,15168),(31906,15113) +(3454,36839),(3438,36831) +(4832,47554),(4820,47473) +(11590,8292),(11539,8272) +(8193,33323),(8106,33317) +(16043,14799),(16001,14710) +(19574,11395),(19514,11316) +(26290,41424),(26224,41342) +(22844,12516),(22807,12471) +(15709,49580),(15655,49553) +(13387,28084),(13379,28066) +(2780,38807),(2690,38711) +(22031,32458),(22028,32377) +(13511,3351),(13440,3297) +(14648,26473),(14614,26383) +(17798,19885),(17726,19852) +(32355,27940),(32324,27861) +(43773,21031),(43767,20985) +(15419,45759),(15403,45666) +(770,38863),(729,38806) +(21221,35619),(21183,35596) +(38924,31021),(38894,30961) +(7395,32439),(7345,32416) +(2324,25118),(2268,25074) +(2958,15089),(2935,15087) +(2424,160),(2424,81) +(12123,18644),(12099,18616) +(7459,30276),(7422,30218) +(15847,45488),(15814,45428) +(26409,29897),(26389,29863) +(12336,34322),(12279,34322) +(9440,23550),(9396,23466) +(4991,30850),(4905,30768) +(47262,11940),(47201,11939) +(30584,42868),(30555,42838) +(23144,24089),(23056,24067) +(35930,11609),(35847,11573) +(7812,17271),(7789,17203) +(17946,37554),(17878,37480) +(27356,32869),(27298,32813) +(29971,47783),(29933,47697) +(26075,46494),(25988,46451) +(39314,41366),(39289,41269) +(31708,42900),(31688,42865) +(4510,10231),(4439,10203) +(43806,8482),(43758,8446) +(45990,49694),(45927,49617) +(48815,27640),(48782,27573) +(41675,26733),(41622,26723) +(23229,7709),(23175,7693) +(48976,17733),(48962,17731) +(10686,41470),(10597,41434) +(18053,27059),(17989,27012) +(35495,25950),(35459,25912) +(41896,45014),(41881,44999) +(22654,41896),(22572,41801) +(18581,7087),(18524,6988) +(14697,22406),(14681,22311) +(40092,28122),(40043,28030) +(35844,24243),(35816,24238) +(1254,25653),(1250,25644) +(1603,21730),(1556,21640) +(33048,21779),(32991,21763) +(29979,1632),(29916,1592) +(8620,633),(8580,620) +(22992,27035),(22932,27008) +(21409,29315),(21390,29309) +(3610,44748),(3547,44699) +(20402,9318),(20343,9267) +(31001,8709),(30908,8658) +(46840,47640),(46773,47551) +(49173,4705),(49143,4630) +(5339,31657),(5251,31622) +(8644,49668),(8630,49648) +(45387,2893),(45309,2885) +(47641,31020),(47584,30941) +(40238,10636),(40208,10568) +(19247,36924),(19227,36924) +(917,19957),(827,19887) +(40967,17841),(40870,17820) +(15850,4109),(15794,4085) +(20181,30916),(20085,30870) +(161,24465),(107,24374) +(21737,49690),(21667,49663) +(10328,20911),(10232,20852) +(24187,49823),(24128,49768) +(36084,4578),(36007,4501) +(38771,31741),(38673,31674) +(2202,30102),(2111,30006) +(27322,16074),(27228,16039) +(6843,17280),(6765,17248) +(16972,39744),(16912,39700) +(10608,38741),(10553,38708) +(4917,34801),(4828,34766) +(39281,33659),(39268,33618) +(31706,7119),(31645,7063) +(3427,44006),(3422,44004) +(10134,42608),(10044,42599) +(26294,32080),(26200,32068) +(21777,34680),(21769,34606) +(23373,25957),(23314,25915) +(10710,8401),(10681,8400) +(42062,19458),(42019,19394) +(26530,43036),(26458,43004) +(3394,46081),(3360,46077) +(38743,33953),(38677,33924) +(32438,8226),(32345,8160) +(9210,27333),(9118,27301) +(19594,1600),(19568,1551) +(10003,12278),(9952,12255) +(31737,7206),(31650,7146) +(16594,15821),(16502,15759) +(28208,30296),(28189,30278) +(30602,46237),(30555,46185) +(20715,5155),(20697,5140) +(48892,35271),(48793,35210) +(3175,5590),(3113,5525) +(34220,27947),(34132,27865) +(35105,39792),(35011,39727) +(21919,27314),(21839,27286) +(23963,3723),(23917,3699) +(16312,14078),(16236,14045) +(19233,49824),(19185,49794) +(1447,11768),(1356,11699) +(17311,17709),(17224,17653) +(11962,31709),(11871,31627) +(21355,40131),(21355,40085) +(33750,35273),(33724,35180) +(38896,25539),(38879,25524) +(39569,44899),(39569,44893) +(11075,41547),(11039,41500) +(3215,12202),(3199,12127) +(46215,33458),(46132,33455) +(15121,38012),(15083,37974) +(44448,18726),(44412,18690) +(3899,38263),(3870,38262) +(13854,13353),(13786,13298) +(8252,5402),(8191,5320) +(46849,37968),(46820,37897) +(16422,13957),(16376,13897) +(47369,7665),(47353,7629) +(11982,40874),(11956,40806) +(9552,27580),(9496,27562) +(32247,19399),(32176,19337) +(32704,2169),(32635,2091) +(7471,44213),(7411,44130) +(48433,7096),(48379,7089) +(37357,6543),(37338,6452) +(30460,29624),(30433,29535) +(20350,28794),(20341,28705) +(6326,32360),(6267,32317) +(1711,47519),(1654,47430) +(49540,16510),(49521,16426) +(26975,618),(26908,579) +(24118,30880),(24020,30821) +(3675,15477),(3625,15418) +(44953,9577),(44953,9530) +(38323,7965),(38235,7910) +(6629,36482),(6579,36448) +(33953,16460),(33878,16408) +(49222,16790),(49186,16695) +(17308,16951),(17274,16904) +(14135,6888),(14077,6833) +(38617,47768),(38603,47760) +(7345,10992),(7290,10914) +(35261,42152),(35176,42096) +(28586,4809),(28544,4735) +(37521,25299),(37495,25217) +(41941,17954),(41912,17915) +(1209,46863),(1171,46863) +(20103,34947),(20048,34896) +(32716,33816),(32656,33769) +(11113,6531),(11036,6467) +(48635,7321),(48563,7262) +(28435,37059),(28349,37014) +(12311,17208),(12232,17112) +(1466,48010),(1379,48008) +(11226,11997),(11223,11925) +(46896,32540),(46821,32510) +(32661,31255),(32632,31187) +(37739,20376),(37655,20306) +(44002,43326),(43920,43257) +(30337,1023),(30271,968) +(34436,23357),(34432,23345) +(21367,8168),(21353,8091) +(36370,21611),(36369,21569) +(4152,36488),(4080,36476) +(17696,13924),(17664,13853) +(34252,19395),(34159,19316) +(12574,3072),(12573,2975) +(3995,21243),(3943,21167) +(44553,30126),(44513,30108) +(4599,45275),(4552,45254) +(33191,11404),(33176,11348) +(14245,18633),(14177,18540) +(32457,20705),(32393,20700) +(40052,10499),(40016,10457) +(29824,44065),(29785,44037) +(31613,12565),(31557,12543) +(42692,29000),(42652,28996) +(40680,22219),(40603,22140) +(33575,27661),(33488,27644) +(46194,1385),(46184,1355) +(38442,48501),(38407,48426) +(25305,21544),(25236,21523) +(15562,8226),(15561,8208) +(20844,43614),(20752,43558) +(22566,30541),(22554,30532) +(2760,47802),(2672,47789) +(25515,30745),(25433,30675) +(48382,45134),(48382,45093) +(9940,27094),(9871,27087) +(48690,44361),(48610,44338) +(18992,11585),(18899,11582) +(21551,49983),(21492,49885) +(46778,29113),(46770,29071) +(43219,9593),(43212,9548) +(40291,1248),(40224,1190) +(12687,22225),(12635,22219) +(49372,38790),(49306,38721) +(49503,46808),(49411,46798) +(24745,5162),(24732,5138) +(5046,26517),(5023,26424) +(5583,46538),(5495,46531) +(6084,35950),(6079,35895) +(3503,23096),(3437,23024) +(45275,8420),(45244,8418) +(13514,45251),(13491,45249) +(42112,2748),(42047,2668) +(7810,21907),(7806,21878) +(48378,36029),(48303,35979) +(32568,48605),(32510,48563) +(859,18915),(810,18915) +(41963,17950),(41939,17915) +(42723,8031),(42685,7955) +(19587,5965),(19556,5961) +(8713,33083),(8629,32996) +(21243,7769),(21226,7740) +(43752,43026),(43720,42944) +(7883,41311),(7859,41242) +(10178,47874),(10157,47826) +(32177,48725),(32093,48646) +(22960,2784),(22953,2774) +(25101,49159),(25087,49090) +(32142,48915),(32086,48850) +(6636,44887),(6590,44825) +(37814,11606),(37769,11578) +(2870,23198),(2820,23121) +(21025,16364),(20947,16271) +(31341,36137),(31269,36114) +(38921,7906),(38888,7831) +(6966,17259),(6922,17199) +(32426,13344),(32401,13253) +(8084,30572),(8078,30572) +(42230,47674),(42150,47603) +(20724,44854),(20724,44830) +(27471,38453),(27454,38430) +(24590,37973),(24544,37941) +(45832,26077),(45772,26031) +(9589,24239),(9582,24156) +(37484,49472),(37409,49432) +(30044,19340),(30004,19333) +(16966,14632),(16936,14572) +(9439,40491),(9403,40482) +(28945,5814),(28913,5805) +(43788,41302),(43746,41231) +(33631,43451),(33614,43354) +(17590,49396),(17510,49324) +(15173,32572),(15109,32507) +(1912,23580),(1840,23504) +(38165,16185),(38076,16154) +(6729,1179),(6637,1177) +(6994,45406),(6983,45325) +(2912,21327),(2908,21305) +(14678,14244),(14659,14222) +(29944,14959),(29898,14900) +(47432,35658),(47407,35610) +(25542,39243),(25466,39149) +(5330,7206),(5304,7165) +(24790,27196),(24695,27118) +(38806,1961),(38795,1906) +(23290,4487),(23212,4416) +(35035,24337),(34990,24297) +(5549,38948),(5549,38891) +(24558,15492),(24501,15425) +(4636,3011),(4574,2933) +(26522,39986),(26451,39940) +(33486,18424),(33410,18366) +(36638,14324),(36625,14287) +(35115,41236),(35055,41191) +(31927,16896),(31841,16806) +(5796,43937),(5697,43886) +(25681,41645),(25663,41608) +(10962,42777),(10894,42732) +(32715,11026),(32672,10991) +(45803,20406),(45710,20371) +(34730,17672),(34658,17606) +(8809,6323),(8798,6232) +(39471,23837),(39390,23749) +(34078,17435),(33987,17433) +(9133,4544),(9041,4509) +(47274,29126),(47242,29060) +(6404,28488),(6403,28475) +(48894,49751),(48846,49694) +(17324,43023),(17301,42972) +(15599,8433),(15557,8386) +(48575,10202),(48488,10175) +(27638,24428),(27608,24378) +(45277,47456),(45240,47422) +(26482,46607),(26482,46570) +(41400,33898),(41397,33802) +(49853,18504),(49848,18503) +(11528,25165),(11476,25080) +(49902,41752),(49818,41746) +(1956,47506),(1922,47424) +(21834,22058),(21802,21964) +(19414,21842),(19386,21822) +(34801,13722),(34744,13681) +(13924,29243),(13835,29160) +(47749,21986),(47664,21894) +(47051,39582),(46974,39489) +(31287,49923),(31236,49913) +(47429,8625),(47337,8585) +(46987,44364),(46901,44277) +(16158,27510),(16099,27467) +(41184,6400),(41148,6317) +(1847,42471),(1829,42426) +(14409,48602),(14320,48555) +(38137,42951),(38045,42918) +(42875,2312),(42832,2243) +(27242,30617),(27181,30535) +(24882,44559),(24812,44548) +(22021,1596),(22015,1581) +(24300,1523),(24250,1443) +(43946,35909),(43869,35868) +(816,15988),(776,15967) +(25243,9401),(25237,9332) +(27967,25958),(27928,25949) +(6575,33949),(6484,33900) +(44812,35980),(44800,35913) +(37577,13064),(37495,13019) +(30891,29967),(30814,29884) +(15829,28836),(15753,28807) +(11128,34180),(11126,34117) +(9834,12537),(9801,12508) +(4899,29069),(4809,29024) +(29370,38459),(29276,38382) +(40743,46653),(40647,46559) +(9618,2723),(9578,2631) +(32542,26837),(32515,26769) +(5625,13409),(5576,13355) +(47490,19229),(47472,19203) +(48118,40275),(48063,40203) +(19245,20549),(19227,20546) +(25312,22243),(25280,22164) +(18797,28934),(18723,28881) +(31609,49393),(31512,49366) +(26183,32888),(26135,32824) +(46198,26153),(46180,26149) +(45383,16904),(45353,16888) +(7132,11408),(7091,11338) +(48262,43227),(48236,43159) +(31722,12861),(31675,12810) +(41695,48924),(41691,48921) +(48318,12877),(48287,12802) +(12069,32241),(11978,32231) +(8395,2694),(8380,2661) +(19552,34590),(19550,34497) +(12203,26166),(12187,26143) +(35745,9571),(35654,9542) +(22384,22535),(22352,22439) +(21459,28189),(21360,28189) +(7418,7203),(7343,7182) +(39497,48412),(39413,48318) +(1058,11132),(979,11051) +(45623,31417),(45548,31381) +(23887,31921),(23876,31891) +(7797,1244),(7785,1155) +(23679,43650),(23594,43644) +(21891,30561),(21833,30485) +(4069,6870),(4019,6785) +(5134,25117),(5103,25034) +(36101,41895),(36085,41810) +(39617,39211),(39544,39191) +(37437,6604),(37434,6585) +(7749,32601),(7740,32515) +(26203,34991),(26159,34946) +(31856,39006),(31783,39003) +(45828,24767),(45788,24723) +(49836,35965),(49757,35871) +(44113,49024),(44033,48995) +(38237,22326),(38187,22253) +(45235,19087),(45190,19005) +(1588,45285),(1520,45254) +(46628,8701),(46552,8665) +(47707,18258),(47668,18250) +(9377,26162),(9325,26079) +(28331,16766),(28302,16731) +(15792,27875),(15727,27809) +(16454,1972),(16415,1967) +(21012,15828),(20972,15784) +(27465,30603),(27390,30560) +(39256,7697),(39225,7604) +(25908,32801),(25854,32770) +(25215,40109),(25201,40106) +(23280,4613),(23190,4596) +(32440,30879),(32405,30807) +(49156,4224),(49126,4126) +(20005,40423),(19911,40370) +(20978,8226),(20930,8170) +(32127,22611),(32126,22579) +(21764,26509),(21701,26455) +(32923,2834),(32914,2830) +(7499,25331),(7426,25300) +(6163,36942),(6107,36908) +(41118,14583),(41034,14486) +(21211,33369),(21208,33331) +(7899,27682),(7853,27603) +(16546,48436),(16535,48400) +(24898,40195),(24855,40174) +(43029,982),(43004,952) +(26266,7962),(26252,7950) +(11308,44367),(11210,44322) +(8902,28402),(8808,28334) +(11671,19619),(11665,19549) +(47202,23593),(47153,23505) +(21981,40220),(21905,40160) +(46721,2514),(46687,2471) +(3450,33839),(3424,33811) +(41854,45864),(41762,45792) +(40183,47816),(40114,47742) +(26119,33910),(26077,33816) +(3430,16518),(3365,16500) +(40063,32176),(40005,32166) +(38702,15253),(38679,15187) +(17719,12291),(17658,12257) +(46131,30669),(46068,30587) +(42738,10952),(42731,10907) +(8721,45155),(8650,45076) +(45317,26123),(45244,26113) +(42694,11561),(42614,11490) +(10043,12479),(10009,12391) +(27584,2345),(27578,2257) +(30889,8253),(30866,8167) +(5176,48928),(5107,48838) +(9781,21023),(9745,20976) +(32430,27908),(32404,27859) +(3984,7391),(3973,7352) +(18904,8094),(18842,8091) +(20573,5508),(20482,5496) +(7806,44368),(7753,44297) +(18875,41452),(18817,41376) +(6632,12142),(6566,12079) +(33066,17865),(33055,17854) +(45726,19628),(45714,19589) +(26971,18459),(26941,18423) +(26554,23641),(26515,23592) +(45503,1325),(45441,1231) +(11898,20164),(11880,20115) +(27868,22837),(27843,22776) +(34931,8206),(34855,8144) +(42375,33603),(42350,33539) +(3184,8308),(3129,8238) +(26667,15813),(26661,15785) +(5760,49617),(5730,49546) +(794,27001),(777,26992) +(13518,45289),(13459,45235) +(34430,29754),(34363,29736) +(37912,24574),(37880,24543) +(8130,2270),(8083,2258) +(26930,21516),(26848,21455) +(3634,33511),(3592,33489) +(33080,5036),(33035,4972) +(48389,13942),(48316,13915) +(9231,5298),(9150,5232) +(1357,10601),(1321,10548) +(35175,15295),(35091,15269) +(33917,36863),(33879,36784) +(8279,12052),(8239,12021) +(11868,19083),(11862,19034) +(24019,30777),(24006,30703) +(44619,6959),(44618,6938) +(28610,2626),(28523,2582) +(29579,41801),(29482,41775) +(23448,37609),(23396,37534) +(40676,11252),(40670,11191) +(39656,14077),(39564,13999) +(33060,31042),(33033,30950) +(11720,6816),(11654,6792) +(13775,28873),(13730,28868) +(47851,39121),(47802,39084) +(30923,40255),(30860,40199) +(44169,15070),(44085,15015) +(42574,28664),(42558,28590) +(8993,43487),(8941,43460) +(40782,11648),(40763,11631) +(18516,10143),(18423,10137) +(39068,551),(39005,491) +(39672,12000),(39575,11913) +(18508,37761),(18464,37712) +(19083,35318),(19079,35280) +(30286,13736),(30222,13672) +(7223,9164),(7132,9069) +(20764,29286),(20700,29210) +(5733,8063),(5699,8058) +(8566,43873),(8549,43797) +(22126,27444),(22062,27366) +(15105,8717),(15078,8660) +(43987,33145),(43940,33083) +(46833,38652),(46755,38612) +(47768,27202),(47681,27169) +(22792,1183),(22731,1152) +(25650,43310),(25562,43247) +(37084,20116),(37045,20057) +(47461,32556),(47423,32555) +(41225,18124),(41215,18117) +(17623,25218),(17553,25158) +(13770,21703),(13770,21700) +(48958,35441),(48870,35388) +(2976,1808),(2892,1802) +(45118,22318),(45049,22224) +(42287,26616),(42281,26560) +(25525,6327),(25468,6244) +(40756,31634),(40713,31568) +(23105,26565),(23078,26565) +(48268,39862),(48265,39827) +(41656,26254),(41567,26243) +(28062,17920),(28045,17825) +(6443,17321),(6402,17238) +(10191,45466),(10151,45447) +(18097,39706),(18043,39649) +(37592,3244),(37569,3197) +(29809,5978),(29762,5950) +(12145,11251),(12130,11202) +(37507,42999),(37446,42956) +(10820,2866),(10782,2830) +(36440,42904),(36421,42832) +(38370,3386),(38279,3311) +(9345,17279),(9313,17197) +(20477,14864),(20395,14807) +(37147,37769),(37110,37729) +(15325,36135),(15284,36053) +(29034,32897),(29009,32854) +(2116,22274),(2037,22216) +(15078,38330),(15048,38251) +(7968,33600),(7914,33573) +(832,23851),(770,23786) +(38669,4348),(38594,4344) +(8521,48573),(8425,48564) +(1060,43320),(969,43289) +(26170,10150),(26144,10069) +(32324,8539),(32285,8506) +(13121,18044),(13109,18021) +(1597,9383),(1594,9367) +(49539,35164),(49505,35065) +(39464,10295),(39409,10261) +(8921,37898),(8825,37803) +(31171,47076),(31093,47039) +(7178,41397),(7108,41304) +(16240,34832),(16162,34761) +(2829,20119),(2782,20091) +(45854,21265),(45810,21250) +(6382,12106),(6315,12030) +(22301,46291),(22291,46274) +(34142,14181),(34078,14158) +(11258,29748),(11198,29742) +(37450,6943),(37398,6882) +(41675,27207),(41643,27130) +(13578,49562),(13573,49479) +(37132,37397),(37081,37301) +(49404,37193),(49332,37170) +(33536,31809),(33444,31735) +(45990,42751),(45893,42708) +(38852,20510),(38802,20509) +(27453,15836),(27391,15802) +(9347,29004),(9284,28946) +(44871,27727),(44778,27668) +(14978,19646),(14970,19644) +(23243,47091),(23166,47080) +(45204,21431),(45167,21370) +(14082,22316),(14078,22235) +(42778,22694),(42744,22606) +(4834,25241),(4760,25196) +(20497,18110),(20494,18038) +(45738,35524),(45706,35496) +(21575,5151),(21493,5092) +(2194,10052),(2172,9960) +(47735,24472),(47682,24460) +(46740,35700),(46695,35609) +(24647,42807),(24568,42779) +(18000,30576),(17975,30506) +(48638,46630),(48544,46628) +(48508,33600),(48477,33578) +(38703,45408),(38670,45313) +(21712,15015),(21625,14956) +(5840,42007),(5768,41992) +(44011,11138),(43953,11117) +(3899,33262),(3897,33238) +(30142,23967),(30096,23927) +(36950,13226),(36908,13141) +(13130,26915),(13071,26873) +(38576,35408),(38539,35392) +(16776,46244),(16700,46176) +(38251,25969),(38168,25948) +(3512,32256),(3417,32242) +(31923,31225),(31832,31197) +(5144,4969),(5124,4937) +(34499,46164),(34430,46162) +(39432,31907),(39388,31828) +(17316,24606),(17221,24533) +(20751,49352),(20709,49323) +(41673,30418),(41623,30377) +(29026,24400),(28971,24345) +(21929,30617),(21894,30598) +(35539,12421),(35536,12355) +(24938,45583),(24870,45525) +(27442,33090),(27353,33064) +(23949,12046),(23949,12036) +(11399,377),(11360,294) +(47099,9989),(47023,9942) +(641,33118),(639,33084) +(13687,41308),(13682,41290) +(3682,17727),(3645,17660) +(13262,19396),(13185,19357) +(18791,389),(18774,366) +(12489,45384),(12403,45369) +(12065,6364),(12015,6325) +(32705,23886),(32619,23827) +(7004,37333),(6911,37240) +(28594,38078),(28530,38050) +(5805,21797),(5710,21701) +(41145,18905),(41058,18873) +(35599,10002),(35591,9956) +(5387,39087),(5326,38994) +(11703,14003),(11671,13912) +(4093,10472),(4091,10470) +(14110,49740),(14063,49695) +(4170,470),(4097,463) +(22219,17296),(22164,17221) +(2505,20879),(2446,20842) +(47235,24744),(47151,24667) +(30035,23234),(30013,23197) +(3489,11659),(3461,11607) +(38435,46322),(38429,46230) +(12315,32880),(12277,32854) +(33350,35297),(33317,35263) +(18845,37671),(18836,37589) +(24855,23554),(24783,23520) +(48251,44461),(48188,44408) +(17695,43353),(17605,43286) +(4964,21292),(4893,21270) +(33919,29907),(33852,29878) +(29139,40010),(29084,39957) +(41611,37750),(41572,37741) +(41773,34717),(41682,34700) +(8225,7424),(8221,7363) +(1785,28248),(1771,28219) +(21553,36307),(21505,36257) +(7552,18199),(7527,18119) +(14410,30977),(14349,30944) +(20940,49142),(20901,49069) +(36892,5522),(36810,5478) +(40192,20926),(40179,20926) +(44702,15182),(44641,15117) +(43431,4921),(43337,4827) +(41129,21654),(41084,21642) +(6205,42785),(6113,42722) +(23714,10224),(23666,10205) +(9318,35175),(9274,35139) +(40698,12676),(40618,12627) +(49954,1340),(49905,1294) +(32774,33062),(32763,33062) +(4336,22183),(4241,22157) +(10241,47657),(10151,47592) +(6746,16718),(6666,16634) +(26842,49694),(26839,49680) +(34870,47437),(34820,47347) +(26365,22266),(26326,22183) +(39859,932),(39829,840) +(33995,10888),(33902,10793) +(32972,22342),(32951,22340) +(19951,10161),(19932,10111) +(26779,45188),(26745,45151) +(11235,13593),(11184,13589) +(27334,20968),(27288,20953) +(9586,43102),(9488,43085) +(43935,49759),(43925,49680) +(10548,37032),(10474,36955) +(9326,14927),(9295,14848) +(41340,11312),(41311,11303) +(6500,44553),(6454,44515) +(8198,26841),(8104,26749) +(47761,34183),(47702,34140) +(43637,17912),(43577,17910) +(17623,11138),(17590,11122) +(48122,13132),(48077,13060) +(27911,39796),(27908,39777) +(1108,7918),(1080,7832) +(18776,24329),(18699,24326) +(1171,37901),(1075,37871) +(38437,33948),(38364,33907) +(1913,11593),(1817,11533) +(22684,266),(22656,181) +(13299,17075),(13241,17074) +(6924,30196),(6851,30113) +(4367,13150),(4298,13053) +(37381,6101),(37380,6046) +(10307,28383),(10270,28349) +(12283,8636),(12256,8610) +(20230,32775),(20144,32723) +(32942,12812),(32905,12714) +(46140,7138),(46140,7047) +(37235,29436),(37161,29425) +(42486,25454),(42478,25444) +(47860,46973),(47842,46961) +(41760,21026),(41662,20955) +(29663,20088),(29566,20026) +(19167,33241),(19101,33235) +(12306,37845),(12301,37803) +(11288,873),(11203,857) +(30309,5120),(30282,5060) +(46927,19737),(46856,19687) +(16664,20052),(16649,19989) +(7330,8675),(7296,8613) +(45067,45724),(44991,45631) +(45317,10862),(45218,10842) +(15012,47009),(14998,46956) +(47882,10146),(47813,10099) +(31571,46215),(31511,46148) +(32257,2619),(32187,2531) +(38924,41305),(38872,41285) +(49981,34876),(49898,34786) +(30501,35099),(30418,35011) +(45862,41438),(45854,41434) +(38448,31878),(38391,31822) +(8278,43463),(8274,43378) +(5883,30629),(5878,30564) +(49501,40346),(49447,40275) +(31651,43116),(31560,43106) +(44244,32940),(44244,32926) +(17941,18079),(17938,18035) +(9518,32524),(9470,32511) +(30707,43469),(30686,43457) +(3284,46542),(3187,46477) +(43423,29642),(43393,29602) +(19940,16825),(19877,16736) +(26194,47446),(26194,47407) +(30386,24675),(30333,24652) +(42707,44466),(42688,44456) +(43395,18525),(43320,18467) +(28346,32259),(28276,32196) +(45106,40786),(45026,40767) +(36734,20414),(36722,20363) +(37140,11569),(37099,11475) +(8967,6409),(8882,6341) +(31036,27923),(30993,27890) +(22442,47682),(22347,47663) +(32511,24029),(32482,23970) +(22593,34444),(22519,34399) +(41534,15495),(41518,15455) +(35862,19997),(35818,19928) +(31419,8323),(31404,8285) +(31036,19023),(30978,19000) +(46900,15192),(46891,15102) +(12774,9651),(12765,9604) +(49985,6436),(49927,6338) +(7184,47344),(7089,47285) +(12792,45021),(12740,45011) +(15019,27192),(14940,27096) +(35415,23106),(35381,23095) +(42129,14283),(42095,14245) +(29375,45807),(29347,45743) +(21763,24916),(21700,24889) +(47656,8794),(47579,8774) +(6139,49571),(6059,49472) +(44492,45607),(44483,45532) +(22699,4301),(22628,4240) +(27407,24241),(27335,24158) +(38424,34460),(38403,34458) +(46572,48456),(46554,48402) +(39676,29056),(39643,28981) +(4202,33076),(4107,33010) +(32499,10592),(32482,10575) +(22504,45417),(22459,45378) +(49619,40322),(49619,40268) +(14463,9305),(14426,9224) +(10070,20300),(10035,20211) +(35060,28561),(34965,28553) +(23970,47522),(23887,47428) +(46803,19155),(46790,19131) +(46151,49848),(46058,49830) +(45266,40766),(45209,40738) +(31041,32195),(31007,32110) +(41401,17245),(41334,17224) +(37445,654),(37435,602) +(45568,31904),(45508,31857) +(29326,7923),(29285,7896) +(27078,34643),(27027,34606) +(34492,43443),(34437,43345) +(34109,4307),(34083,4265) +(2755,45325),(2727,45312) +(12571,24218),(12536,24195) +(41224,2454),(41149,2445) +(711,34828),(655,34788) +(9104,18865),(9036,18850) +(3508,26816),(3456,26771) +(20159,16212),(20116,16160) +(36871,7425),(36777,7421) +(2751,45244),(2734,45222) +(35867,28071),(35769,28052) +(46878,35730),(46850,35725) +(20610,35086),(20513,35037) +(3903,32612),(3887,32517) +(9330,40226),(9289,40169) +(6338,28242),(6329,28184) +(35668,18344),(35606,18304) +(29892,48927),(29878,48879) +(26999,646),(26932,612) +(36377,38898),(36338,38847) +(40289,31459),(40236,31436) +(30377,1164),(30306,1069) +(7642,12183),(7590,12112) +(40325,1716),(40296,1662) +(36412,38787),(36318,38691) +(3967,33268),(3923,33261) +(33914,40774),(33873,40763) +(45978,41431),(45963,41332) +(39195,12546),(39120,12520) +(29962,30878),(29941,30846) +(9365,10732),(9310,10726) +(28801,23943),(28740,23885) +(28934,38858),(28928,38807) +(22126,45897),(22068,45803) +(2923,33832),(2918,33751) +(25116,2276),(25083,2272) +(31174,14546),(31144,14460) +(11728,9072),(11658,9004) +(19804,49195),(19730,49125) +(23090,28826),(23010,28787) +(33989,27553),(33947,27486) +(39702,47613),(39641,47553) +(31397,3607),(31304,3519) +(5835,9262),(5791,9226) +(40112,37022),(40038,36926) +(12346,29356),(12282,29344) +(28503,9623),(28469,9591) +(38449,43143),(38378,43066) +(36950,37311),(36905,37265) +(34824,5729),(34818,5706) +(9288,26969),(9225,26900) +(2535,42176),(2478,42159) +(29098,49051),(29085,49031) +(44759,33326),(44727,33230) +(42849,2970),(42821,2919) +(46014,27193),(45985,27151) +(14506,13713),(14417,13626) +(19342,44905),(19332,44895) +(38178,37003),(38147,36925) +(29179,27310),(29084,27288) +(42713,10158),(42671,10060) +(43336,38389),(43290,38326) +(41260,34410),(41245,34327) +(27907,2695),(27830,2596) +(16309,44972),(16222,44966) +(6230,22262),(6214,22249) +(9266,39458),(9175,39447) +(33120,33548),(33087,33538) +(43659,11416),(43599,11375) +(49707,39258),(49702,39159) +(23520,22140),(23486,22072) +(24736,46502),(24668,46412) +(7826,16851),(7730,16807) +(39114,6048),(39056,5965) +(11859,8753),(11764,8701) +(42254,48367),(42240,48328) +(26136,49185),(26056,49175) +(38395,11209),(38334,11137) +(33249,9425),(33209,9348) +(22131,38502),(22112,38460) +(5306,24344),(5267,24268) +(30292,1198),(30233,1149) +(9903,10896),(9850,10806) +(25568,22911),(25487,22868) +(22048,43391),(22043,43362) +(20852,25827),(20851,25766) +(35204,17119),(35114,17093) +(5575,43431),(5554,43410) +(17727,13623),(17678,13560) +(14721,29520),(14709,29461) +(40317,42220),(40267,42166) +(31435,31012),(31386,30931) +(40655,10103),(40645,10006) +(35783,17802),(35773,17763) +(34874,10210),(34856,10200) +(3694,14279),(3610,14239) +(27854,5493),(27799,5433) +(34913,7234),(34894,7220) +(15758,26445),(15738,26421) +(23710,7272),(23705,7270) +(33679,13468),(33628,13415) +(31271,40495),(31178,40461) +(759,187),(662,163) +(14419,40434),(14402,40381) +(45879,42933),(45814,42872) +(167,17214),(92,17184) +(9964,12210),(9958,12195) +(35834,46257),(35817,46211) +(26077,5629),(25978,5621) +(46177,44640),(46082,44544) +(44780,28753),(44707,28692) +(35491,24729),(35425,24690) +(33914,34190),(33914,34131) +(17709,33253),(17668,33227) +(45516,11888),(45423,11848) +(24497,24752),(24411,24710) +(30333,5952),(30331,5886) +(444,12587),(430,12497) +(7592,22353),(7541,22287) +(13387,37414),(13329,37318) +(21504,35227),(21449,35210) +(18533,12909),(18438,12848) +(41049,27148),(41048,27088) +(18205,12222),(18151,12140) +(18026,5164),(18026,5156) +(34104,29862),(34006,29815) +(18520,49686),(18454,49602) +(37000,41493),(36920,41424) +(43025,25711),(42986,25687) +(38620,47018),(38535,46934) +(24119,36813),(24023,36739) +(48887,26359),(48879,26302) +(47827,14625),(47810,14609) +(10792,30746),(10776,30716) +(30384,40672),(30318,40582) +(48417,22790),(48358,22746) +(14854,5819),(14785,5798) +(19142,44414),(19085,44406) +(31179,27081),(31145,27005) +(19692,8711),(19659,8642) +(39689,14082),(39603,14051) +(11181,39091),(11119,39002) +(46015,23374),(45936,23328) +(12517,49702),(12427,49690) +(21926,21137),(21841,21111) +(31956,12509),(31870,12494) +(5895,2030),(5851,2020) +(27094,5447),(27014,5377) +(35781,8717),(35780,8618) +(14012,12023),(13972,12015) +(1702,12442),(1696,12419) +(28549,5251),(28462,5248) +(26441,21007),(26360,20925) +(49820,7990),(49771,7967) +(26424,29698),(26339,29693) +(35146,6820),(35071,6817) +(15438,18788),(15435,18729) +(47115,5235),(47096,5143) +(33982,9002),(33915,8925) +(14206,37041),(14174,36955) +(24300,36616),(24232,36613) +(44658,1788),(44580,1769) +(31539,43550),(31463,43464) +(16722,9673),(16633,9652) +(44813,20573),(44733,20544) +(42114,32559),(42040,32552) +(41561,36244),(41477,36241) +(39589,33796),(39548,33716) +(20365,26770),(20329,26709) +(28511,208),(28479,114) +(10010,25524),(9930,25508) +(1549,45666),(1512,45621) +(16193,1927),(16166,1869) +(34486,11500),(34421,11401) +(14048,37944),(13994,37901) +(21692,9594),(21617,9496) +(2568,37899),(2557,37811) +(4360,24503),(4278,24443) +(50027,49230),(49951,49214) +(44849,14867),(44836,14813) +(16695,34896),(16683,34840) +(12600,35217),(12593,35129) +(23113,24009),(23030,23962) +(49907,30225),(49810,30158) +(18026,25208),(17970,25208) +(49711,39844),(49651,39790) +(5427,42682),(5357,42637) +(23901,14221),(23802,14184) +(15470,12185),(15376,12163) +(47302,34023),(47292,34001) +(24336,17418),(24315,17393) +(13948,17043),(13903,16970) +(8555,8986),(8530,8953) +(48830,6038),(48743,5986) +(48720,40687),(48623,40610) +(21161,30970),(21146,30896) +(9507,36316),(9411,36261) +(36643,18136),(36614,18106) +(1858,7457),(1851,7402) +(24452,44306),(24372,44252) +(3292,807),(3205,806) +(6845,30694),(6792,30627) +(21333,25786),(21237,25751) +(23008,22574),(22999,22511) +(8790,8893),(8772,8806) +(43333,47968),(43264,47900) +(5377,24103),(5302,24076) +(18410,23993),(18329,23907) +(24752,19126),(24713,19069) +(49772,11378),(49696,11293) +(3468,12920),(3396,12873) +(1746,40342),(1736,40333) +(49187,29737),(49139,29681) +(27657,44952),(27581,44917) +(35407,30177),(35345,30151) +(4071,40568),(4058,40544) +(25998,30513),(25965,30452) +(8195,45403),(8097,45310) +(8276,41689),(8183,41670) +(48435,28550),(48355,28455) +(8139,25449),(8136,25380) +(20302,25574),(20297,25531) +(22055,46659),(22034,46567) +(3531,49962),(3463,49934) +(46828,46938),(46739,46902) +(42294,786),(42212,739) +(8779,3292),(8761,3275) +(48146,46170),(48082,46151) +(21571,10000),(21531,9919) +(35526,26029),(35450,25945) +(38893,22225),(38865,22197) +(22189,37520),(22132,37497) +(810,43261),(751,43198) +(10352,39144),(10290,39093) +(8740,35435),(8720,35432) +(31657,13551),(31583,13484) +(39803,4019),(39755,4014) +(46353,7853),(46312,7824) +(30078,48975),(30021,48970) +(2847,32036),(2819,31966) +(25250,10147),(25165,10140) +(15643,38953),(15585,38947) +(40792,29798),(40731,29731) +(43249,26858),(43215,26835) +(47229,2199),(47201,2134) +(10052,23601),(9958,23570) +(38981,21615),(38892,21604) +(3651,45004),(3570,44917) +(21503,8261),(21409,8166) +(13518,34201),(13465,34105) +(13899,25117),(13836,25114) +(18327,17403),(18301,17349) +(19503,13648),(19483,13607) +(3554,19487),(3529,19466) +(41102,43355),(41070,43314) +(4663,45858),(4583,45765) +(3971,3023),(3931,2975) +(37124,7061),(37080,6993) +(48530,47172),(48459,47160) +(14575,29843),(14509,29750) +(43443,23124),(43357,23038) +(8864,48290),(8857,48263) +(41597,39852),(41577,39791) +(35610,33392),(35556,33353) +(36415,17906),(36328,17846) +(24919,43933),(24839,43883) +(7457,14056),(7395,14051) +(43851,4090),(43801,4080) +(43567,18468),(43471,18388) +(16711,6084),(16652,6055) +(45888,45934),(45846,45880) +(45630,9313),(45585,9248) +(27119,25969),(27094,25884) +(36155,11420),(36120,11405) +(41880,47111),(41808,47049) +(17554,20379),(17482,20374) +(38848,5936),(38763,5869) +(28324,31019),(28276,30944) +(43257,17152),(43176,17091) +(42717,24613),(42691,24527) +(16786,41486),(16763,41403) +(19259,28780),(19160,28711) +(25843,28265),(25760,28171) +(48645,34816),(48546,34755) +(7004,49289),(6976,49236) +(30261,21833),(30181,21776) +(5290,46672),(5219,46661) +(21237,31901),(21188,31849) +(23340,38537),(23253,38472) +(17269,3682),(17183,3586) +(48200,15377),(48110,15369) +(16546,22195),(16477,22142) +(21436,8460),(21378,8449) +(46598,17235),(46577,17138) +(30212,36184),(30152,36092) +(18037,155),(17941,109) +(4945,29201),(4933,29184) +(32835,18782),(32770,18750) +(34160,33104),(34120,33007) +(5151,26989),(5149,26909) +(1801,15549),(1710,15461) +(48988,34819),(48951,34764) +(20904,32547),(20856,32497) +(32654,35183),(32606,35144) +(14336,11763),(14328,11712) +(30546,23808),(30463,23773) +(6813,21006),(6781,20924) +(14199,22030),(14185,21934) +(3783,14709),(3747,14658) +(49428,47052),(49422,46973) +(29551,27682),(29470,27654) +(29170,37260),(29151,37181) +(48924,24689),(48894,24680) +(48497,34052),(48453,33966) +(21263,8203),(21242,8176) +(46537,3797),(46462,3735) +(18406,14579),(18393,14563) +(11583,16529),(11536,16471) +(10564,46257),(10478,46228) +(49769,34513),(49761,34458) +(9202,6482),(9138,6391) +(40387,37411),(40357,37360) +(11966,11802),(11888,11751) +(15551,47438),(15486,47406) +(12017,43288),(11969,43230) +(9717,22574),(9701,22495) +(35083,49443),(35075,49355) +(33857,9320),(33813,9269) +(32106,10581),(32012,10560) +(14345,12485),(14273,12424) +(24187,46416),(24175,46402) +(43854,42159),(43808,42129) +(35399,40707),(35359,40646) +(29585,25576),(29493,25556) +(24919,7829),(24911,7753) +(17049,48390),(17022,48304) +(25224,35012),(25217,34922) +(47397,20853),(47346,20779) +(17221,16558),(17181,16516) +(8669,16491),(8645,16486) +(23502,44241),(23484,44164) +(36169,37046),(36072,37010) +(44775,32394),(44763,32357) +(30685,36871),(30662,36792) +(21783,47642),(21714,47630) +(34847,27467),(34761,27372) +(43925,49912),(43888,49878) +(16455,27861),(16364,27813) +(38406,18310),(38329,18309) +(5408,9461),(5319,9426) +(41856,36900),(41784,36854) +(23723,4460),(23646,4448) +(18454,40138),(18430,40046) +(17505,36822),(17418,36763) +(36686,33534),(36641,33476) +(11347,9454),(11289,9436) +(27816,34752),(27745,34736) +(44213,8559),(44162,8461) +(45359,26789),(45315,26776) +(31249,19475),(31224,19421) +(25917,44239),(25819,44149) +(47313,40691),(47264,40685) +(40577,33848),(40513,33794) +(9606,45253),(9582,45174) +(30005,24521),(29910,24496) +(49332,35375),(49309,35299) +(12164,33871),(12075,33820) +(19598,43327),(19593,43314) +(3818,28584),(3815,28504) +(35579,8611),(35541,8604) +(8811,20986),(8750,20954) +(16139,44777),(16128,44686) +(35550,41501),(35534,41458) +(43180,11927),(43109,11891) +(45798,8465),(45711,8460) +(18196,6886),(18126,6845) +(1774,32167),(1701,32073) +(7030,40790),(7029,40711) +(11676,23009),(11665,22915) +(33990,22561),(33953,22474) +(30366,9447),(30284,9353) +(37626,32913),(37596,32853) +(7730,42561),(7665,42470) +(49347,8403),(49315,8387) +(6874,3499),(6812,3458) +(44189,16999),(44169,16964) +(6312,30167),(6231,30083) +(18932,6611),(18909,6518) +(32262,13076),(32223,13057) +(45989,249),(45910,222) +(42710,855),(42692,796) +(25562,9849),(25535,9802) +(13348,46719),(13260,46689) +(30022,42196),(30005,42160) +(22263,45954),(22243,45950) +(18918,18890),(18820,18795) +(31918,12003),(31852,11989) +(12252,39453),(12211,39398) +(40208,9789),(40194,9759) +(35943,21767),(35914,21693) +(18439,10706),(18383,10618) +(2803,18999),(2778,18925) +(14953,27444),(14875,27397) +(12587,22025),(12545,21928) +(33930,21090),(33918,21009) +(10444,2606),(10407,2553) +(28700,29782),(28665,29703) +(1402,13497),(1397,13465) +(24155,3075),(24083,3062) +(38378,1864),(38339,1849) +(29261,49910),(29247,49818) +(38139,37073),(38098,37057) +(24468,41130),(24418,41053) +(9989,1015),(9959,939) +(47001,33561),(46994,33518) +(47058,16030),(46983,16012) +(35509,1814),(35426,1748) +(3630,48019),(3597,47923) +(47781,12986),(47741,12947) +(16364,9908),(16356,9882) +(17290,41508),(17287,41410) +(42423,26477),(42349,26434) +(10039,920),(9952,833) +(16851,21338),(16846,21314) +(23104,7700),(23062,7688) +(5619,2079),(5611,2075) +(31471,49632),(31375,49549) +(25793,12526),(25783,12456) +(3935,29528),(3866,29513) +(5957,1646),(5947,1595) +(2467,22376),(2429,22349) +(43715,32673),(43664,32595) +(6726,13093),(6636,12994) +(31477,18347),(31421,18299) +(34232,36635),(34200,36552) +(49061,14516),(49008,14442) +(43996,6129),(43955,6074) +(7728,33802),(7670,33703) +(6131,36766),(6053,36749) +(35791,16361),(35696,16329) +(45759,8935),(45675,8886) +(43634,2029),(43537,1940) +(4916,32233),(4844,32181) +(46701,23508),(46623,23477) +(29590,4893),(29552,4871) +(38647,4423),(38574,4396) +(7593,25845),(7497,25751) +(8510,43552),(8432,43492) +(18791,39181),(18730,39162) +(7462,2956),(7454,2858) +(1394,26795),(1392,26780) +(16707,21993),(16609,21932) +(26838,10866),(26803,10836) +(31642,29842),(31585,29760) +(21891,3502),(21863,3406) +(13258,587),(13250,507) +(6072,47397),(6021,47369) +(16605,49730),(16579,49659) +(42830,40981),(42791,40981) +(12975,3706),(12913,3637) +(30925,21660),(30826,21649) +(1455,14229),(1410,14156) +(17583,16486),(17562,16474) +(33377,3387),(33333,3381) +(784,6177),(750,6095) +(22111,44110),(22106,44013) +(1444,403),(1346,344) +(4010,46220),(3982,46212) +(17932,8150),(17861,8127) +(38685,31466),(38636,31416) +(14257,11549),(14242,11522) +(14990,15217),(14904,15211) +(21395,21533),(21307,21520) +(31948,33725),(31885,33694) +(433,49033),(390,48961) +(45205,609),(45173,523) +(25065,35494),(25003,35455) +(33265,6677),(33224,6611) +(18179,22345),(18133,22256) +(3916,13759),(3820,13732) +(1696,13478),(1604,13436) +(47203,25980),(47130,25907) +(24913,13361),(24868,13268) +(13824,40177),(13792,40130) +(25671,13555),(25585,13494) +(20133,37769),(20105,37679) +(26368,16734),(26288,16726) +(30545,35438),(30458,35376) +(48816,22926),(48812,22831) +(48807,31389),(48739,31330) +(11003,10859),(10950,10765) +(17288,8570),(17247,8485) +(38377,31415),(38331,31379) +(19085,23425),(19059,23326) +(40059,17068),(40052,17006) +(18811,13493),(18734,13394) +(36319,17197),(36225,17181) +(14939,38780),(14863,38714) +(49539,17656),(49479,17629) +(42530,45951),(42466,45854) +(27318,26654),(27233,26610) +(49980,35004),(49937,34963) +(18326,32558),(18322,32502) +(45951,28555),(45896,28481) +(12104,33531),(12014,33501) +(22311,41113),(22215,41066) +(25073,18721),(25047,18656) +(14524,13486),(14510,13390) +(40040,36688),(40000,36599) +(21594,11473),(21563,11436) +(44031,22274),(43938,22187) +(729,30683),(668,30601) +(14114,20873),(14102,20803) +(28239,41377),(28222,41308) +(26404,11922),(26317,11843) +(41660,34586),(41585,34501) +(21128,2384),(21101,2368) +(30209,16952),(30156,16858) +(39078,24963),(39045,24898) +(5598,1348),(5499,1294) +(38474,7436),(38450,7364) +(15117,45734),(15024,45693) +(23909,39853),(23888,39780) +(24292,30183),(24282,30148) +(48871,17661),(48868,17637) +(918,18752),(847,18708) +(43615,16162),(43606,16104) +(33763,47410),(33751,47409) +(4798,6485),(4773,6388) +(18524,41539),(18433,41518) +(47745,42449),(47651,42364) +(38936,21237),(38864,21204) +(5251,3516),(5194,3475) +(22269,36269),(22183,36228) +(18736,40983),(18685,40947) +(38393,15444),(38356,15363) +(38134,29898),(38103,29862) +(37789,39557),(37732,39474) +(31906,23005),(31838,23003) +(10647,40094),(10560,40040) +(9914,41547),(9867,41545) +(44221,443),(44125,433) +(41479,10936),(41381,10847) +(42586,6301),(42563,6235) +(2504,17588),(2449,17554) +(7045,18782),(7028,18764) +(41840,32018),(41768,31938) +(38416,17158),(38330,17060) +(8605,39015),(8605,38933) +(5764,43548),(5719,43496) +(20789,29902),(20696,29843) +(36104,47896),(36079,47816) +(31736,13834),(31722,13832) +(32617,19701),(32597,19684) +(1671,18997),(1622,18945) +(36007,26545),(36005,26535) +(31864,17494),(31820,17455) +(27346,28388),(27303,28289) +(8191,9653),(8133,9589) +(7501,21616),(7405,21536) +(35450,9580),(35368,9563) +(29281,37276),(29247,37255) +(6225,17192),(6200,17135) +(43689,8119),(43670,8028) +(41917,49601),(41835,49563) +(44295,13116),(44205,13078) +(22721,44772),(22667,44748) +(32640,11107),(32636,11050) +(20639,28851),(20613,28839) +(32479,10159),(32446,10061) +(27251,16978),(27196,16959) +(41401,33148),(41339,33074) +(49001,8538),(48989,8444) +(37958,35843),(37874,35802) +(46969,41229),(46903,41138) +(18541,8876),(18541,8870) +(4080,31634),(4061,31627) +(8097,35240),(8040,35152) +(18470,21414),(18463,21412) +(20914,17897),(20838,17869) +(42688,11681),(42666,11641) +(47525,25005),(47443,24907) +(32439,14438),(32397,14400) +(39667,19626),(39622,19542) +(1212,44525),(1169,44516) +(29766,4433),(29668,4401) +(25847,49657),(25813,49605) +(33859,17356),(33827,17263) +(28989,45953),(28904,45854) +(37211,30830),(37113,30819) +(45220,26382),(45219,26340) +(12312,43250),(12234,43246) +(37775,41504),(37762,41421) +(45889,33499),(45822,33411) +(49461,22601),(49369,22553) +(39857,33844),(39816,33824) +(46102,15822),(46030,15778) +(46605,31239),(46598,31170) +(23925,5856),(23862,5808) +(15459,4262),(15407,4241) +(12019,4907),(12015,4818) +(38258,17973),(38229,17923) +(40575,29566),(40477,29521) +(29715,45919),(29697,45891) +(11694,9510),(11670,9490) +(7053,44257),(7012,44231) +(16465,8603),(16391,8505) +(29170,15592),(29098,15527) +(20400,37354),(20345,37328) +(5281,10265),(5252,10184) +(6084,48782),(6058,48727) +(11006,6889),(10971,6796) +(16299,19461),(16286,19411) +(13718,29192),(13642,29106) +(3999,2965),(3963,2903) +(18509,12235),(18430,12208) +(49542,38575),(49537,38534) +(15093,41715),(15071,41634) +(6802,8385),(6714,8300) +(15127,17507),(15097,17424) +(36921,3025),(36835,2995) +(32117,24327),(32101,24262) +(27244,24151),(27165,24104) +(36339,42360),(36313,42358) +(47288,46252),(47245,46184) +(37867,6649),(37818,6565) +(14886,22103),(14865,22089) +(39611,17952),(39513,17951) +(37329,31436),(37298,31436) +(5715,39115),(5698,39099) +(13266,7364),(13203,7296) +(16076,10945),(16006,10942) +(7197,41509),(7126,41413) +(14411,40868),(14330,40772) +(12872,33481),(12862,33454) +(17786,19616),(17758,19560) +(1052,37358),(996,37311) +(42825,12643),(42762,12625) +(20007,49858),(19921,49778) +(27155,6355),(27072,6257) +(14117,40208),(14022,40155) +(47280,34069),(47279,34028) +(17551,15803),(17482,15763) +(1725,6673),(1676,6649) +(43984,31128),(43961,31105) +(43772,47042),(43731,47038) +(46901,47317),(46817,47228) +(19877,14179),(19837,14168) +(20691,19989),(20675,19935) +(4011,18914),(3963,18817) +(1023,23378),(933,23317) +(30051,46118),(29966,46039) +(43499,46488),(43496,46409) +(43531,2412),(43447,2396) +(16034,32285),(15976,32220) +(12817,21365),(12740,21298) +(7607,47293),(7585,47293) +(32512,12218),(32463,12170) +(1848,21496),(1839,21439) +(17567,23073),(17478,23046) +(35813,31847),(35807,31792) +(563,30859),(540,30842) +(13145,15488),(13063,15433) +(36754,37479),(36731,37411) +(1125,26069),(1057,25997) +(4539,20676),(4519,20618) +(8476,34721),(8409,34681) +(7794,25691),(7727,25656) +(23842,514),(23800,473) +(47678,41396),(47668,41365) +(6837,25974),(6799,25892) +(13355,11174),(13304,11161) +(37243,25548),(37158,25471) +(12528,30208),(12441,30205) +(14929,1672),(14886,1607) +(27263,49026),(27263,49010) +(15892,21645),(15835,21642) +(29446,48978),(29360,48967) +(41304,9892),(41211,9825) +(37418,49393),(37338,49296) +(41146,32178),(41120,32165) +(28738,13326),(28722,13266) +(14899,36595),(14873,36559) +(1973,31435),(1921,31426) +(19485,17742),(19421,17661) +(33072,20995),(32980,20903) +(47091,30055),(47080,30037) +(45753,12998),(45686,12992) +(11528,7826),(11509,7794) +(21104,13921),(21060,13836) +(16768,15491),(16747,15470) +(13279,20396),(13249,20326) +(4342,49518),(4339,49446) +(20413,15476),(20349,15447) +(45532,5649),(45484,5627) +(18647,27196),(18619,27115) +(1326,17473),(1261,17400) +(47646,19644),(47588,19609) +(35088,1813),(35080,1732) +(38461,34839),(38410,34838) +(34358,11540),(34285,11506) +(26969,7078),(26953,6989) +(12629,40352),(12617,40264) +(33800,7037),(33731,6992) +(24462,13518),(24392,13486) +(33164,47357),(33096,47329) +(15422,18451),(15413,18376) +(19643,12916),(19567,12912) +(40860,42125),(40770,42050) +(49103,29614),(49039,29606) +(36319,35582),(36222,35528) +(8924,36083),(8873,36018) +(49603,44022),(49505,44021) +(7783,40633),(7702,40618) +(25388,49107),(25346,49042) +(28375,38947),(28306,38919) +(47324,22672),(47321,22660) +(2287,8808),(2266,8719) +(44343,16339),(44248,16318) +(2374,28839),(2336,28798) +(22913,40710),(22819,40688) +(47747,684),(47658,627) +(16043,46011),(16021,45984) +(34958,32168),(34903,32092) +(4840,49328),(4752,49258) +(24341,2087),(24330,2009) +(18378,19374),(18327,19358) +(48165,7217),(48156,7141) +(14232,6044),(14182,6004) +(23080,4196),(22983,4191) +(259,1850),(175,1820) +(270,29508),(264,29440) +(45088,11375),(45050,11295) +(29666,39386),(29656,39302) +(8712,8782),(8660,8713) +(15900,6650),(15855,6561) +(28946,28348),(28917,28347) +(32544,25845),(32538,25779) +(44047,6957),(43951,6942) +(36465,588),(36382,503) +(28167,26679),(28150,26673) +(16065,4268),(15975,4180) +(12950,23494),(12893,23494) +(30145,24679),(30056,24654) +(3027,16162),(3001,16071) +(8259,34537),(8202,34484) +(41447,1515),(41427,1454) +(18407,28362),(18309,28303) +(21393,41872),(21328,41816) +(46040,26497),(45996,26408) +(49944,25163),(49902,25153) +(16195,11843),(16159,11831) +(44257,15270),(44254,15214) +(49760,4791),(49699,4713) +(22558,33709),(22519,33681) +(28375,10003),(28336,9938) +(18179,24310),(18106,24256) +(707,30688),(664,30669) +(5851,26118),(5822,26037) +(4266,1292),(4221,1217) +(16516,11331),(16432,11248) +(32374,38277),(32313,38245) +(21939,8015),(21927,7952) +(34322,32051),(34242,32003) +(6262,35977),(6260,35953) +(16717,38594),(16622,38498) +(14564,3433),(14535,3425) +(21078,1000),(20994,974) +(28584,956),(28575,868) +(5538,9962),(5465,9870) +(34183,44102),(34175,44085) +(42507,10289),(42441,10288) +(12671,19936),(12594,19920) +(24835,12179),(24770,12173) +(15664,11538),(15598,11494) +(28892,24446),(28821,24350) +(41654,26720),(41570,26632) +(36583,387),(36503,357) +(10842,34824),(10795,34788) +(11518,42588),(11429,42565) +(12577,40322),(12486,40266) +(2453,4045),(2439,3956) +(31837,33705),(31803,33681) +(24403,27711),(24383,27705) +(4431,2748),(4337,2656) +(3036,2887),(3014,2826) +(37664,16118),(37615,16022) +(8606,18063),(8587,18038) +(24738,25458),(24656,25362) +(45756,34022),(45671,33948) +(34079,15236),(33981,15171) +(9251,22488),(9228,22470) +(25136,2809),(25126,2717) +(5548,47695),(5543,47685) +(13765,40800),(13707,40754) +(25216,30678),(25144,30677) +(22441,17169),(22392,17106) +(1091,4770),(1054,4734) +(36311,50073),(36258,49987) +(22461,33163),(22457,33128) +(35873,28907),(35845,28867) +(42907,15848),(42904,15785) +(6549,24897),(6540,24861) +(21928,37764),(21891,37681) +(21237,41132),(21139,41086) +(12207,24266),(12173,24235) +(40643,49770),(40574,49687) +(32833,35686),(32815,35674) +(14545,18143),(14541,18098) +(33892,42783),(33884,42707) +(33933,8381),(33921,8369) +(12450,19044),(12403,19002) +(10176,45158),(10088,45145) +(35828,12080),(35732,12022) +(28102,13694),(28061,13666) +(49432,31744),(49340,31711) +(16192,37743),(16162,37697) +(46830,867),(46756,790) +(9200,28048),(9159,27986) +(13397,19369),(13340,19288) +(30879,43562),(30785,43545) +(21995,48224),(21920,48143) +(11871,47569),(11809,47568) +(29366,22196),(29280,22154) +(26243,28176),(26203,28116) +(28995,35031),(28906,35014) +(29384,39276),(29352,39183) +(8497,13798),(8471,13789) +(7412,27226),(7334,27220) +(25403,47678),(25363,47654) +(11599,5556),(11574,5502) +(44056,5123),(44008,5111) +(49603,30877),(49579,30840) +(32261,45876),(32206,45865) +(35104,41659),(35048,41587) +(5457,35844),(5376,35782) +(29423,3977),(29354,3959) +(18059,3001),(17965,2961) +(8509,5691),(8463,5620) +(27118,5762),(27083,5747) +(2991,48605),(2939,48559) +(44482,3484),(44425,3459) +(45143,16439),(45046,16365) +(2236,37531),(2147,37530) +(41561,3217),(41490,3210) +(6270,27200),(6171,27166) +(49195,24871),(49138,24798) +(46985,38881),(46897,38845) +(37486,23522),(37404,23441) +(26907,14490),(26900,14391) +(30829,16111),(30756,16056) +(3644,17291),(3587,17262) +(20508,49775),(20472,49680) +(43279,8972),(43198,8936) +(33744,7470),(33734,7439) +(46303,20538),(46284,20498) +(10365,48246),(10291,48154) +(12636,24987),(12545,24933) +(40998,46992),(40989,46916) +(30536,6073),(30531,6018) +(22102,9643),(22051,9594) +(18616,34348),(18530,34332) +(8222,8907),(8123,8848) +(45698,28860),(45698,28770) +(26958,1748),(26924,1726) +(26735,35073),(26659,35025) +(48370,40813),(48293,40737) +(13140,993),(13108,934) +(10588,22893),(10528,22883) +(23645,40789),(23567,40698) +(49548,12374),(49546,12329) +(41135,39626),(41100,39602) +(41374,10856),(41328,10769) +(12234,5765),(12146,5674) +(12832,46941),(12764,46917) +(47886,34532),(47851,34500) +(23777,10549),(23735,10495) +(1291,16913),(1194,16873) +(29239,30554),(29202,30500) +(36485,30007),(36454,29924) +(7067,11320),(7045,11229) +(16939,30482),(16904,30462) +(27423,34386),(27379,34303) +(35170,32021),(35155,31979) +(42570,36477),(42474,36457) +(19695,679),(19682,594) +(47537,39450),(47446,39450) +(19410,22942),(19375,22922) +(34216,40166),(34152,40158) +(37000,24351),(36972,24299) +(24989,1681),(24954,1672) +(54,38679),(3,38602) +(41461,40693),(41411,40599) +(7576,46054),(7545,45963) +(35505,28262),(35413,28222) +(1158,16976),(1145,16927) +(23494,42291),(23437,42229) +(32894,32519),(32880,32485) +(604,13413),(509,13401) +(18396,19712),(18355,19646) +(26657,28234),(26597,28191) +(24240,47211),(24154,47191) +(41778,10741),(41766,10730) +(44022,43776),(44010,43677) +(35967,30055),(35906,29969) +(28878,18042),(28806,18027) +(31507,27302),(31428,27267) +(13267,21935),(13265,21872) +(122,46832),(64,46762) +(10348,45916),(10306,45844) +(22962,12644),(22927,12607) +(6320,22290),(6284,22247) +(2297,11372),(2216,11298) +(29366,36660),(29325,36654) +(13962,39307),(13921,39220) +(11094,19151),(11092,19143) +(32289,23776),(32258,23760) +(36044,17356),(35956,17273) +(46304,38692),(46232,38675) +(10934,42999),(10922,42909) +(4271,21177),(4207,21093) +(7837,19926),(7747,19905) +(25537,36605),(25477,36584) +(22161,14999),(22079,14962) +(5127,31243),(5074,31213) +(14904,40664),(14838,40593) +(29308,8480),(29268,8438) +(17731,7410),(17699,7352) +(44840,29293),(44797,29248) +(15523,31519),(15505,31485) +(34429,38479),(34421,38478) +(3530,23456),(3440,23390) +(4699,6889),(4603,6796) +(47405,48524),(47389,48514) +(23357,43160),(23305,43156) +(16923,1995),(16860,1937) +(47592,33853),(47537,33758) +(31624,37490),(31595,37473) +(42321,13380),(42303,13337) +(3088,16094),(3079,16060) +(22884,2955),(22856,2857) +(17784,23073),(17724,23044) +(32638,45577),(32553,45512) +(13876,44091),(13801,44000) +(27844,24384),(27758,24330) +(28178,10225),(28155,10167) +(39910,14277),(39857,14241) +(30372,19524),(30301,19514) +(38732,43151),(38724,43151) +(32628,2068),(32547,2068) +(13950,28652),(13932,28566) +(38996,41070),(38919,40993) +(31759,45246),(31676,45215) +(5424,34145),(5382,34106) +(14727,45600),(14699,45547) +(31429,21537),(31414,21499) +(14740,3420),(14650,3323) +(21793,39498),(21743,39471) +(18102,25924),(18037,25868) +(33299,683),(33213,594) +(45882,48765),(45809,48721) +(49215,4098),(49180,4067) +(49698,33743),(49614,33663) +(21532,5215),(21514,5151) +(24840,26877),(24826,26808) +(32680,28433),(32631,28364) +(20661,27511),(20584,27414) +(28048,30385),(28009,30315) +(45403,42533),(45389,42464) +(46531,36947),(46531,36850) +(36943,32817),(36865,32737) +(37984,43763),(37888,43748) +(20593,10650),(20557,10610) +(5387,40595),(5326,40585) +(34412,10600),(34352,10539) +(7237,47546),(7206,47451) +(39931,26644),(39915,26598) +(29843,4734),(29800,4669) +(37503,8867),(37406,8821) +(2583,2373),(2570,2294) +(29275,46433),(29256,46350) +(3332,45620),(3287,45581) +(22472,39287),(22472,39257) +(36786,18907),(36708,18884) +(45503,28576),(45482,28494) +(33262,28386),(33163,28365) +(3606,49757),(3538,49697) +(2082,49380),(1991,49281) +(12065,3734),(11983,3663) +(15606,9048),(15596,9028) +(14687,19309),(14637,19263) +(4568,15461),(4499,15428) +(43938,7429),(43923,7391) +(2168,50012),(2108,49914) +(16022,8934),(15963,8928) +(24567,39147),(24561,39102) +(42781,14149),(42765,14088) +(39501,21084),(39468,21078) +(6697,29628),(6693,29584) +(11441,16164),(11364,16125) +(39946,1920),(39868,1844) +(18138,45512),(18111,45438) +(20799,41217),(20718,41138) +(30264,16697),(30240,16639) +(30746,50040),(30727,49992) +(37429,43273),(37423,43205) +(22854,28863),(22789,28810) +(11380,48298),(11287,48242) +(16471,37273),(16439,37223) +(32737,39842),(32661,39811) +(30959,3447),(30949,3357) +(36396,13263),(36348,13187) +(29607,14625),(29531,14619) +(7851,43399),(7824,43334) +(38515,14575),(38496,14492) +(29125,3289),(29086,3264) +(6866,10476),(6839,10424) +(318,31489),(235,31404) +(1140,7007),(1113,6945) +(36574,9291),(36484,9275) +(40320,40937),(40246,40866) +(588,25849),(552,25801) +(6728,42539),(6645,42507) +(12180,6185),(12123,6123) +(32913,44123),(32899,44037) +(25464,16803),(25441,16749) +(23711,5829),(23695,5750) +(31424,34930),(31377,34906) +(42171,8298),(42124,8222) +(451,31104),(375,31083) +(39996,3278),(39943,3260) +(25816,40396),(25735,40362) +(34471,28587),(34399,28547) +(45344,21540),(45297,21496) +(27269,16787),(27246,16763) +(18070,4469),(18022,4423) +(12668,16367),(12645,16295) +(13823,17276),(13730,17251) +(20555,45544),(20511,45498) +(35893,42189),(35861,42177) +(37081,45730),(37076,45705) +(17270,15651),(17201,15552) +(48690,46034),(48667,45945) +(456,16088),(368,16023) +(48707,12416),(48670,12363) +(29692,11509),(29614,11483) +(7005,3668),(6981,3574) +(12162,389),(12103,309) +(12371,24983),(12366,24964) +(6886,48414),(6868,48327) +(10653,26234),(10624,26142) +(8526,48205),(8517,48117) +(10521,31892),(10480,31798) +(43353,1086),(43281,1071) +(21007,35650),(20998,35649) +(2343,4396),(2310,4320) +(29379,12895),(29284,12891) +(27662,17407),(27570,17313) +(9845,29346),(9807,29321) +(43855,38669),(43790,38599) +(20461,44189),(20397,44158) +(11627,17368),(11581,17289) +(2971,38855),(2938,38807) +(43204,47082),(43128,47018) +(9930,46902),(9909,46871) +(30561,48461),(30536,48365) +(44059,7591),(44038,7563) +(46260,16898),(46162,16886) +(27491,2891),(27396,2814) +(36512,26034),(36455,25941) +(31193,20022),(31100,19942) +(17057,13643),(16960,13621) +(26897,3399),(26844,3318) +(1760,5504),(1683,5431) +(29347,5511),(29346,5450) +(38761,42083),(38688,41999) +(11226,4089),(11165,4068) +(46427,42983),(46361,42970) +(12958,30737),(12912,30712) +(44432,46521),(44333,46443) +(16124,2948),(16113,2852) +(24704,25422),(24635,25340) +(30833,46152),(30790,46122) +(4487,37006),(4473,36968) +(41047,23376),(41036,23327) +(16312,49392),(16298,49330) +(30081,14687),(30042,14660) +(11160,13954),(11103,13938) +(33207,23246),(33143,23168) +(14872,7635),(14860,7585) +(20139,23987),(20059,23955) +(10946,49757),(10923,49746) +(39438,36158),(39426,36134) +(35502,2385),(35464,2327) +(17073,42173),(16987,42130) +(6079,17258),(6068,17195) +(40458,15752),(40364,15728) +(23340,7879),(23313,7806) +(31819,15096),(31762,15059) +(31159,40864),(31158,40780) +(26975,32144),(26915,32113) +(34530,10378),(34440,10298) +(18855,49577),(18780,49528) +(16787,16625),(16723,16586) +(32330,26538),(32314,26458) +(34270,28674),(34265,28595) +(10022,16026),(10006,15962) +(23143,1479),(23095,1469) +(33676,4483),(33583,4408) +(31066,22074),(31059,22035) +(21603,47121),(21563,47082) +(30051,4244),(30021,4157) +(30634,39478),(30615,39446) +(34404,48724),(34393,48724) +(31103,21414),(31039,21380) +(22945,47397),(22849,47313) +(18133,32025),(18073,31941) +(4053,25759),(3977,25667) +(39185,39091),(39102,39068) +(43287,7407),(43225,7314) +(13137,31188),(13112,31182) +(46264,1438),(46258,1389) +(22804,43892),(22769,43822) +(7542,1044),(7487,983) +(33022,8321),(32925,8267) +(384,39161),(286,39073) +(28205,24401),(28142,24382) +(31708,39086),(31696,39026) +(36626,15708),(36560,15690) +(17099,16924),(17079,16924) +(10817,6989),(10747,6955) +(24338,19293),(24291,19277) +(27566,17576),(27544,17545) +(23041,38384),(22970,38320) +(12786,8485),(12702,8435) +(13876,49473),(13813,49448) +(31585,46998),(31490,46929) +(30227,8768),(30206,8715) +(32062,39306),(32023,39292) +(25003,35753),(24921,35687) +(3281,6758),(3232,6704) +(11395,30299),(11376,30220) +(5088,15275),(5007,15203) +(31100,39538),(31003,39444) +(2741,17877),(2726,17793) +(42897,48620),(42860,48537) +(4230,15778),(4181,15776) +(17835,27530),(17815,27431) +(34189,10933),(34135,10921) +(7537,39974),(7494,39973) +(21554,3507),(21528,3476) +(9350,32326),(9273,32275) +(16455,8874),(16420,8793) +(7346,34235),(7330,34224) +(16417,48134),(16352,48066) +(41916,4971),(41849,4886) +(15856,1522),(15807,1521) +(41549,40218),(41494,40144) +(9978,16226),(9972,16181) +(14856,13312),(14808,13283) +(38490,41641),(38428,41583) +(25828,7438),(25807,7378) +(21876,30633),(21796,30587) +(1908,14279),(1825,14247) +(32207,10251),(32121,10184) +(370,9493),(328,9441) +(42072,17634),(41974,17600) +(47298,9910),(47235,9846) +(17856,11266),(17782,11225) +(35009,21400),(34956,21396) +(18337,11145),(18335,11133) +(25425,9139),(25381,9085) +(35642,27783),(35621,27782) +(3629,33164),(3575,33163) +(17151,41255),(17115,41204) +(17417,5835),(17402,5751) +(33407,14226),(33329,14141) +(1930,29955),(1889,29931) +(41101,10942),(41065,10844) +(36333,27288),(36281,27233) +(21423,36868),(21367,36825) +(36385,19566),(36341,19510) +(27073,38301),(27066,38232) +(43989,34187),(43984,34174) +(48366,7488),(48316,7483) +(37497,36075),(37415,36043) +(46917,9891),(46887,9870) +(37179,657),(37103,634) +(3877,44736),(3811,44684) +(30556,2975),(30547,2962) +(7629,11447),(7547,11416) +(45687,48147),(45591,48088) +(5635,7184),(5571,7146) +(9611,47327),(9541,47246) +(7119,48224),(7117,48152) +(15233,26480),(15138,26430) +(37468,1526),(37466,1513) +(20855,2786),(20828,2711) +(30538,44084),(30480,44061) +(42231,41527),(42149,41454) +(14963,13239),(14952,13146) +(26819,43996),(26745,43934) +(42172,35953),(42086,35928) +(28785,12611),(28710,12534) +(14089,1704),(14047,1629) +(4343,26242),(4341,26169) +(20327,42244),(20231,42212) +(33671,12700),(33666,12630) +(42144,32642),(42128,32569) +(26590,19483),(26503,19442) +(21741,46259),(21723,46226) +(8822,34700),(8760,34693) +(2710,33521),(2675,33505) +(26067,19998),(26026,19989) +(12244,34509),(12202,34489) +(47162,598),(47119,499) +(33093,49382),(33068,49359) +(35170,26340),(35153,26264) +(22552,35785),(22490,35735) +(36791,23032),(36781,22976) +(22857,10857),(22833,10797) +(47207,37405),(47138,37365) +(21867,2836),(21854,2811) +(3387,31487),(3311,31456) +(47174,48121),(47167,48101) +(24415,22232),(24366,22224) +(7970,29251),(7959,29211) +(18635,31294),(18539,31221) +(8403,13380),(8370,13372) +(738,18097),(737,18054) +(37238,19195),(37218,19114) +(582,47934),(570,47897) +(12359,4635),(12350,4619) +(43272,2013),(43195,1958) +(47568,27149),(47521,27088) +(24695,12827),(24661,12796) +(26259,14077),(26168,14019) +(48478,36135),(48425,36092) +(5230,39250),(5206,39174) +(3488,18562),(3423,18489) +(39502,16331),(39460,16275) +(18296,1478),(18233,1471) +(28627,12430),(28559,12410) +(25257,21981),(25206,21954) +(2410,41192),(2325,41142) +(43681,9631),(43587,9538) +(15086,45309),(15064,45270) +(13824,40807),(13759,40787) +(7090,2207),(7062,2159) +(3685,2480),(3630,2391) +(14810,38335),(14801,38275) +(26668,38018),(26581,38012) +(45562,1517),(45506,1424) +(11001,32481),(10962,32402) +(27743,25245),(27673,25161) +(15952,10598),(15948,10535) +(12705,13308),(12694,13232) +(31992,21195),(31975,21118) +(25834,16652),(25745,16626) +(21022,43625),(20990,43576) +(45094,27254),(45000,27240) +(9688,42601),(9643,42533) +(17746,24659),(17694,24616) +(1509,38859),(1503,38809) +(2067,20438),(2041,20369) +(7885,44528),(7839,44444) +(27432,33052),(27422,32987) +(26577,17157),(26563,17142) +(10815,35985),(10734,35908) +(44891,24067),(44794,23979) +(48626,1900),(48595,1850) +(40659,35541),(40659,35489) +(22231,26628),(22210,26579) +(37408,23016),(37375,22919) +(5920,15916),(5906,15895) +(33125,9952),(33037,9880) +(12142,29705),(12141,29670) +(3672,20995),(3649,20899) +(39147,31967),(39101,31907) +(33812,48458),(33748,48399) +(25038,14639),(24978,14586) +(3859,16010),(3857,15994) +(31926,39496),(31889,39417) +(49300,28064),(49297,28026) +(24121,38305),(24048,38256) +(9252,4205),(9155,4149) +(36124,30451),(36056,30395) +(28809,49557),(28794,49533) +(30500,44504),(30471,44476) +(26866,42395),(26822,42332) +(48195,1784),(48101,1734) +(46201,14109),(46112,14097) +(2415,9975),(2354,9914) +(30485,9581),(30415,9558) +(6385,36838),(6305,36838) +(2799,11189),(2723,11095) +(21998,20503),(21923,20406) +(29151,10714),(29090,10671) +(28850,29276),(28757,29207) +(43386,48845),(43305,48834) +(25173,8310),(25101,8294) +(34244,32352),(34204,32342) +(35595,23728),(35533,23672) +(1122,13581),(1119,13538) +(388,21716),(296,21678) +(48782,11064),(48701,11005) +(40293,12997),(40213,12927) +(28194,46428),(28113,46414) +(4791,18118),(4708,18105) +(471,29808),(448,29775) +(3536,37803),(3447,37737) +(1336,28416),(1275,28392) +(16484,48478),(16422,48454) +(25846,19320),(25811,19296) +(48669,27703),(48575,27615) +(24032,44217),(24029,44127) +(12236,5019),(12233,4986) +(1179,29838),(1113,29778) +(33893,22049),(33867,21955) +(16718,19462),(16700,19440) +(17992,49438),(17894,49433) +(35163,39941),(35081,39885) +(33897,8362),(33853,8328) +(2480,6640),(2456,6599) +(28011,19729),(27937,19679) +(15819,41516),(15809,41440) +(29818,9136),(29747,9089) +(28551,37016),(28529,36941) +(36406,26879),(36374,26872) +(16821,48925),(16758,48914) +(23692,48163),(23595,48160) +(4803,10619),(4759,10522) +(46600,33581),(46553,33518) +(41349,11767),(41310,11710) +(20856,29642),(20799,29562) +(16559,46161),(16504,46131) +(23041,1300),(23003,1287) +(16630,44902),(16554,44853) +(43065,14299),(43013,14274) +(24818,22397),(24796,22348) +(22282,24949),(22218,24921) +(36668,28538),(36631,28456) +(8080,1220),(8018,1146) +(47282,34302),(47277,34269) +(35603,33558),(35557,33495) +(44764,32189),(44700,32175) +(46488,23965),(46449,23868) +(46314,15047),(46216,15013) +(6348,25381),(6286,25363) +(3871,49288),(3819,49251) +(462,38894),(398,38867) +(23196,29214),(23136,29169) +(29024,9775),(29016,9759) +(42016,18555),(41934,18472) +(8772,45981),(8692,45973) +(11028,1351),(10986,1278) +(26684,21668),(26641,21656) +(37262,26005),(37260,25947) +(14899,44069),(14814,44066) +(39635,18701),(39587,18698) +(28528,22948),(28457,22857) +(7755,36528),(7681,36454) +(32461,1172),(32427,1106) +(18775,27359),(18736,27329) +(15379,20031),(15337,19934) +(45888,33592),(45881,33544) +(44013,24694),(43962,24645) +(43347,10699),(43343,10699) +(49999,27218),(49908,27176) +(13698,17326),(13630,17317) +(34850,44313),(34775,44302) +(38076,49235),(37983,49214) +(35570,40218),(35500,40136) +(40062,28973),(40032,28878) +(3567,39847),(3523,39781) +(498,2442),(480,2401) +(29660,43620),(29577,43561) +(10946,47356),(10878,47351) +(8073,44233),(8005,44144) +(9720,13473),(9710,13462) +(3643,38014),(3598,37932) +(16887,1408),(16810,1375) +(7559,27914),(7508,27874) +(30356,18573),(30275,18569) +(12193,48176),(12130,48116) +(11884,7756),(11819,7731) +(18293,33272),(18227,33234) +(46697,47874),(46696,47828) +(35788,32517),(35760,32446) +(33877,36987),(33821,36958) +(31253,22819),(31184,22808) +(7744,23115),(7729,23103) +(21291,39817),(21219,39778) +(13877,43379),(13861,43290) +(42955,1406),(42876,1382) +(49232,15950),(49210,15880) +(48419,32001),(48326,31902) +(18940,43246),(18860,43150) +(32317,38240),(32310,38201) +(11307,48298),(11304,48222) +(38015,18190),(38000,18176) +(27821,1177),(27818,1131) +(18935,26757),(18865,26682) +(42659,48284),(42562,48244) +(30185,23350),(30146,23291) +(16496,11970),(16441,11919) +(162,26040),(120,25963) +(24238,47784),(24185,47746) +(32326,8612),(32274,8568) +(26141,13423),(26051,13407) +(40132,22815),(40089,22812) +(21151,48794),(21056,48740) +(22044,28358),(22031,28334) +(6680,14746),(6605,14669) +(40686,25139),(40632,25070) +(22823,27549),(22816,27507) +(2513,22841),(2427,22811) +(36316,27787),(36218,27728) +(554,35489),(540,35441) +(536,30674),(534,30609) +(25385,38468),(25295,38416) +(19467,47386),(19437,47317) +(22425,38591),(22387,38536) +(32493,17321),(32396,17298) +(40115,47315),(40109,47235) +(25002,2107),(24963,2104) +(3901,9790),(3898,9706) +(40316,1721),(40315,1658) +(40089,3454),(40074,3443) +(793,17897),(761,17897) +(6490,43552),(6434,43522) +(10825,487),(10820,405) +(47703,36067),(47641,36011) +(4480,11671),(4468,11653) +(37713,10642),(37711,10615) +(12315,5302),(12273,5203) +(8709,6617),(8647,6557) +(24467,30535),(24455,30494) +(40440,32757),(40369,32668) +(49449,42447),(49426,42428) +(44867,11197),(44792,11137) +(39173,33241),(39143,33187) +(43836,2212),(43803,2184) +(23819,47613),(23739,47575) +(20583,2134),(20485,2042) +(48922,6169),(48889,6111) +(5230,44613),(5131,44604) +(37060,8051),(37032,7975) +(19148,36711),(19112,36704) +(36305,4216),(36243,4118) +(6329,39089),(6302,39047) +(36703,26367),(36623,26307) +(44753,19721),(44701,19631) +(42094,43310),(42094,43285) +(4276,22377),(4241,22352) +(30329,18906),(30327,18815) +(21970,19605),(21871,19590) +(23722,41924),(23709,41861) +(30965,39775),(30908,39692) +(32394,37895),(32351,37890) +(23968,42162),(23873,42095) +(1776,2621),(1732,2548) +(24951,47758),(24900,47679) +(32917,35771),(32847,35753) +(5428,27773),(5343,27769) +(19650,142),(19630,51) +(39769,17276),(39743,17229) +(5171,24562),(5119,24470) +(32976,35249),(32917,35199) +(4174,24603),(4099,24504) +(38565,36960),(38535,36926) +(39084,4328),(39031,4301) +(32153,38043),(32070,37990) +(38085,30640),(38041,30603) +(14269,18426),(14185,18422) +(42941,30850),(42892,30788) +(32403,25999),(32339,25960) +(16906,191),(16816,139) +(3456,48722),(3418,48721) +(3050,18287),(3022,18243) +(6331,8439),(6234,8364) +(5331,20797),(5319,20793) +(39225,37408),(39216,37348) +(34510,19838),(34488,19810) +(45789,33873),(45770,33786) +(369,1457),(278,1409) +(16531,43785),(16482,43729) +(11974,14789),(11973,14730) +(23128,6811),(23094,6798) +(43962,33659),(43944,33599) +(20967,3115),(20947,3079) +(39257,38606),(39241,38595) +(22431,8246),(22381,8235) +(26007,14672),(25996,14593) +(24762,4261),(24675,4261) +(35402,32077),(35343,31988) +(5141,16476),(5139,16393) +(16439,17564),(16344,17472) +(36983,46663),(36903,46567) +(35170,14144),(35162,14048) +(22290,7841),(22283,7810) +(22414,38398),(22404,38319) +(9011,18177),(8932,18150) +(154,4019),(138,3990) +(20447,4998),(20383,4970) +(38867,35757),(38795,35659) +(32322,15845),(32227,15804) +(29889,12142),(29852,12055) +(36235,36918),(36217,36897) +(41620,6581),(41568,6581) +(24758,38504),(24731,38483) +(42524,12904),(42473,12895) +(17954,49975),(17865,49915) +(1938,39019),(1927,39013) +(4864,33279),(4817,33258) +(45373,41967),(45313,41885) +(28786,19028),(28782,18978) +(41913,44950),(41911,44908) +(33408,14698),(33392,14681) +(27602,3460),(27576,3419) +(3336,3728),(3334,3715) +(9099,910),(9080,813) +(34141,6403),(34071,6367) +(48270,17216),(48252,17130) +(2549,16546),(2461,16474) +(27802,33669),(27735,33642) +(48419,1682),(48323,1583) +(5094,41211),(5002,41123) +(11192,6217),(11190,6146) +(6979,18503),(6959,18421) +(41210,48187),(41140,48143) +(15303,29527),(15273,29441) +(12326,45572),(12267,45570) +(29293,5861),(29212,5826) +(23847,37241),(23761,37178) +(44656,23926),(44653,23831) +(30043,16194),(29977,16105) +(902,9358),(879,9339) +(23850,46501),(23834,46494) +(42333,13300),(42287,13246) +(25226,18086),(25169,18005) +(40252,12082),(40183,12038) +(49275,18076),(49216,18055) +(8255,28878),(8238,28862) +(11325,41286),(11320,41235) +(16948,18588),(16926,18528) +(31394,1099),(31374,1038) +(30705,35772),(30637,35766) +(3858,39131),(3771,39125) +(17565,24892),(17515,24808) +(9221,49715),(9216,49661) +(44945,25769),(44875,25722) +(33408,13563),(33310,13527) +(48505,4407),(48408,4373) +(21859,37217),(21763,37217) +(39393,14422),(39335,14364) +(19905,1154),(19841,1098) +(25946,10388),(25906,10366) +(10104,13748),(10027,13746) +(5822,24629),(5820,24599) +(38194,11287),(38127,11252) +(15694,46757),(15625,46716) +(326,18837),(285,18817) +(49611,47078),(49533,47052) +(48233,18850),(48150,18842) +(29239,9962),(29208,9875) +(40062,44554),(39973,44460) +(19135,20729),(19059,20643) +(31969,40664),(31896,40643) +(3725,9191),(3711,9095) +(44280,40158),(44264,40108) +(37236,42756),(37160,42694) +(27958,19055),(27888,18959) +(45270,17661),(45187,17601) +(12115,39546),(12061,39525) +(10227,32295),(10168,32231) +(39264,31123),(39226,31085) +(6566,40000),(6532,39904) +(30058,6975),(30012,6903) +(49631,6909),(49597,6823) +(42168,10926),(42134,10905) +(44892,30042),(44858,29970) +(19540,19803),(19495,19788) +(18403,25454),(18371,25404) +(22929,26795),(22841,26722) +(16648,30213),(16626,30174) +(3440,7495),(3429,7468) +(30708,49028),(30643,48998) +(26258,14164),(26255,14151) +(44206,31653),(44121,31637) +(1510,15179),(1426,15130) +(6986,30496),(6887,30416) +(7192,43403),(7138,43339) +(39921,22071),(39866,21976) +(45870,17011),(45796,16919) +(15939,9563),(15917,9539) +(23728,24737),(23691,24725) +(6444,40416),(6363,40375) +(21899,23861),(21857,23765) +(20610,36765),(20533,36742) +(46520,33082),(46433,32983) +(21406,20902),(21311,20895) +(37913,42300),(37814,42269) +(18216,8177),(18161,8173) +(32967,8258),(32899,8244) +(14978,40230),(14971,40149) +(30343,39152),(30266,39101) +(25917,5835),(25843,5806) +(5169,45366),(5141,45314) +(16221,20898),(16209,20875) +(13151,19869),(13145,19811) +(44399,2801),(44337,2713) +(10959,48311),(10957,48230) +(4794,11711),(4732,11661) +(764,10149),(762,10091) +(15985,46067),(15898,46028) +(41434,22870),(41342,22867) +(43769,23796),(43743,23756) +(10017,18440),(9919,18384) +(21141,43119),(21097,43112) +(7782,13424),(7694,13398) +(25088,36224),(25059,36150) +(46325,48722),(46241,48631) +(11042,33125),(11011,33071) +(22347,13460),(22290,13375) +(3508,20538),(3483,20536) +(5331,42945),(5272,42875) +(2368,15537),(2339,15503) +(45314,31830),(45254,31817) +(34358,2649),(34319,2589) +(17576,30407),(17572,30323) +(29836,41324),(29746,41287) +(21036,39996),(21014,39899) +(26886,6460),(26787,6400) +(15709,5625),(15627,5558) +(37415,15979),(37414,15911) +(47761,16860),(47728,16813) +(35814,48252),(35755,48173) +(28559,20810),(28496,20715) +(12034,11921),(12002,11905) +(1818,27450),(1805,27406) +(33810,45499),(33806,45413) +(17376,18175),(17323,18138) +(34106,28135),(34049,28106) +(44947,23165),(44919,23091) +(37670,41904),(37616,41840) +(12614,15027),(12555,14969) +(43301,75),(43227,43) +(27526,15096),(27450,15088) +(26947,33409),(26853,33333) +(1537,43572),(1471,43499) +(21607,35452),(21605,35375) +(24869,46565),(24818,46531) +(4774,30335),(4723,30257) +(11615,18316),(11579,18310) +(18444,15819),(18354,15763) +(47267,22574),(47203,22518) +(22287,49538),(22203,49511) +(43010,16270),(43010,16202) +(1623,8350),(1578,8254) +(21220,43808),(21137,43748) +(40397,16471),(40358,16434) +(34839,1377),(34744,1327) +(17096,5730),(17090,5637) +(28156,37782),(28155,37723) +(3672,5686),(3586,5638) +(21856,48656),(21840,48638) +(6907,7791),(6892,7761) +(17952,21370),(17862,21350) +(37793,13461),(37784,13381) +(14740,49655),(14709,49604) +(21690,6337),(21593,6289) +(10423,33548),(10364,33498) +(39187,23274),(39136,23197) +(21882,37247),(21835,37167) +(11343,16957),(11281,16914) +(38279,43400),(38264,43352) +(23167,30271),(23086,30224) +(46278,6037),(46180,5964) +(28626,31165),(28605,31095) +(31018,367),(30946,333) +(23541,12541),(23530,12523) +(49741,14535),(49691,14511) +(31444,12702),(31425,12612) +(22406,26536),(22316,26534) +(6807,9761),(6758,9723) +(15698,1941),(15687,1848) +(49310,4625),(49295,4584) +(21345,18939),(21269,18887) +(31433,30493),(31411,30439) +(44980,12400),(44950,12372) +(25054,13949),(24984,13949) +(40538,7253),(40483,7212) +(16967,8627),(16936,8604) +(26872,3646),(26804,3594) +(24575,42883),(24530,42883) +(11823,5755),(11771,5721) +(2553,46189),(2513,46174) +(24993,14552),(24898,14470) +(28453,1719),(28419,1665) +(8925,22603),(8878,22589) +(47635,15380),(47546,15378) +(35378,18112),(35324,18058) +(27347,22264),(27293,22200) +(44323,29044),(44273,28958) +(41538,38324),(41484,38290) +(19128,49932),(19112,49849) +(17904,12548),(17867,12503) +(35103,14426),(35092,14336) +(29807,10142),(29714,10052) +(44507,22903),(44462,22847) +(11419,13324),(11399,13251) +(8573,42221),(8562,42123) +(46798,45843),(46765,45765) +(12028,31783),(11967,31749) +(10635,45300),(10604,45251) +(9626,8248),(9587,8194) +(18290,741),(18246,732) +(39949,44672),(39932,44641) +(7897,11692),(7893,11637) +(20165,42246),(20112,42168) +(4341,48390),(4285,48338) +(30126,28913),(30088,28869) +(40565,1733),(40472,1721) +(9981,30147),(9915,30133) +(47292,25511),(47217,25462) +(20137,24489),(20104,24392) +(2385,28283),(2381,28189) +(20429,10052),(20357,10009) +(8395,38568),(8348,38480) +(17381,36112),(17349,36038) +(37845,30953),(37759,30926) +(27452,12732),(27411,12652) +(38196,32186),(38114,32116) +(6527,49356),(6508,49315) +(43891,29789),(43856,29723) +(6146,37192),(6085,37107) +(42012,28897),(41939,28808) +(14909,13815),(14846,13757) +(11120,24095),(11035,24049) +(3132,41545),(3053,41526) +(40084,40315),(39994,40261) +(39671,17445),(39576,17361) +(47135,35853),(47085,35831) +(39297,1941),(39290,1911) +(47143,35898),(47072,35880) +(16017,6711),(15989,6686) +(47110,30305),(47087,30213) +(38102,27639),(38091,27602) +(17954,22544),(17863,22453) +(39891,11791),(39815,11739) +(13996,20290),(13922,20278) +(22284,23143),(22190,23081) +(25345,24019),(25313,24017) +(47134,44803),(47055,44761) +(41360,16573),(41326,16503) +(10464,1071),(10457,998) +(23515,47517),(23451,47499) +(9308,8452),(9238,8392) +(28695,5657),(28671,5644) +(45104,9913),(45077,9871) +(337,455),(240,359) +(11562,45479),(11472,45428) +(11952,18466),(11931,18425) +(35789,5154),(35775,5128) +(19024,18299),(18979,18230) +(43056,38113),(42975,38067) +(10075,26847),(10064,26806) +(3065,8107),(3029,8038) +(24766,19059),(24749,18985) +(14438,24805),(14413,24708) +(9523,3058),(9485,2998) +(24516,31262),(24478,31204) +(49513,26044),(49434,26035) +(14110,38528),(14103,38461) +(31679,35618),(31619,35618) +(10029,20258),(10008,20248) +(39269,37586),(39233,37539) +(12343,8197),(12247,8113) +(11155,44223),(11111,44134) +(25437,20606),(25338,20534) +(46604,16156),(46570,16131) +(4636,14004),(4592,13941) +(15975,29628),(15912,29556) +(49887,24274),(49805,24184) +(11812,13440),(11723,13418) +(21589,38179),(21531,38085) +(32255,44463),(32219,44454) +(15023,12698),(14989,12687) +(28906,48630),(28818,48568) +(28886,38905),(28861,38832) +(34786,22285),(34740,22240) +(46513,46780),(46425,46780) +(26626,31759),(26551,31677) +(19792,25967),(19763,25933) +(20432,14394),(20388,14365) +(27092,7301),(27052,7278) +(22283,987),(22198,928) +(6197,24363),(6112,24311) +(46601,49259),(46551,49231) +(12392,48052),(12363,48038) +(46116,31386),(46067,31356) +(7354,16855),(7289,16778) +(47501,42808),(47495,42761) +(16461,25487),(16391,25398) +(42678,18798),(42678,18756) +(9466,18207),(9419,18185) +(17467,14177),(17416,14097) +(28533,31886),(28487,31832) +(13225,38472),(13188,38395) +(5180,40970),(5173,40902) +(83,10271),(15,10265) +(2111,6784),(2016,6690) +(41835,11064),(41798,10995) +(29273,48585),(29181,48536) +(29066,21615),(28985,21543) +(19805,44143),(19727,44128) +(48919,21468),(48875,21467) +(28790,34287),(28721,34251) +(10911,33074),(10869,32989) +(6111,16519),(6032,16489) +(43889,33838),(43837,33768) +(32323,21685),(32304,21644) +(9552,27819),(9539,27753) +(38266,49852),(38233,49844) +(37672,48362),(37663,48277) +(32550,47029),(32529,46931) +(46307,6620),(46272,6616) +(23192,46608),(23105,46566) +(30399,48330),(30335,48239) +(36268,25058),(36235,24984) +(19181,8120),(19089,8098) +(24376,19983),(24294,19925) +(18297,18375),(18202,18292) +(31608,6215),(31575,6168) +(12788,49510),(12784,49468) +(46071,13013),(46035,12991) +(27647,8218),(27582,8201) +(49580,11076),(49537,11050) +(35501,33782),(35501,33687) +(19969,3148),(19964,3082) +(37728,49153),(37726,49152) +(5322,48440),(5321,48435) +(48003,10096),(47904,10005) +(39361,22318),(39348,22236) +(30488,7456),(30437,7430) +(18533,39476),(18481,39394) +(39462,23701),(39433,23604) +(26701,18300),(26686,18235) +(17405,35577),(17387,35517) +(33971,29928),(33953,29919) +(6328,10241),(6276,10217) +(32459,44259),(32453,44217) +(1715,42385),(1647,42357) +(48113,6960),(48103,6872) +(30561,4255),(30476,4240) +(38907,43619),(38827,43553) +(29149,20773),(29070,20698) +(17006,1543),(16970,1497) +(11737,18808),(11714,18788) +(13019,30534),(13005,30481) +(39224,31729),(39191,31683) +(4942,41680),(4907,41596) +(12287,37187),(12188,37172) +(30758,29579),(30725,29531) +(16604,17963),(16581,17912) +(19459,15888),(19409,15812) +(34696,24783),(34600,24725) +(21621,14159),(21558,14110) +(12193,46149),(12145,46096) +(37781,4715),(37692,4635) +(41854,44125),(41807,44040) +(23604,23585),(23571,23533) +(7853,36967),(7797,36908) +(2755,13279),(2720,13206) +(4314,15424),(4283,15383) +(29584,12685),(29493,12594) +(25138,33726),(25042,33691) +(38393,10270),(38326,10185) +(4247,12615),(4225,12567) +(36100,33156),(36100,33107) +(20024,40796),(20016,40708) +(3927,44892),(3914,44843) +(10317,43168),(10226,43096) +(22057,3419),(22042,3334) +(37097,21814),(37025,21811) +(32084,21564),(31996,21491) +(34079,39921),(34058,39911) +(23078,47459),(23018,47373) +(38109,616),(38082,568) +(11862,40382),(11764,40292) +(33403,33320),(33389,33289) +(36639,24829),(36623,24829) +(12995,45080),(12992,45040) +(16545,19981),(16532,19891) +(26155,10659),(26154,10634) +(24423,255),(24360,213) +(823,22487),(781,22442) +(12823,20064),(12735,20040) +(19688,11710),(19681,11654) +(2892,20452),(2836,20424) +(15533,10807),(15464,10711) +(46994,41143),(46955,41082) +(18155,2421),(18069,2392) +(2628,12688),(2605,12602) +(35128,8396),(35044,8365) +(44765,49615),(44758,49524) +(11226,44529),(11178,44515) +(31334,32463),(31291,32456) +(43224,23387),(43168,23364) +(30882,10414),(30798,10395) +(29139,967),(29139,923) +(29959,45244),(29877,45223) +(19946,217),(19941,118) +(49732,22033),(49642,22012) +(32914,15360),(32879,15290) +(47825,21097),(47747,21030) +(10788,5131),(10746,5086) +(15497,9698),(15481,9678) +(10617,47195),(10601,47117) +(42392,10583),(42340,10550) +(10753,33520),(10669,33509) +(5553,21580),(5521,21527) +(36840,12336),(36817,12320) +(49785,12554),(49702,12553) +(17737,38349),(17639,38277) +(48000,7823),(47956,7814) +(5019,3184),(4931,3160) +(30120,3524),(30063,3492) +(37044,2016),(37001,1942) +(23496,38566),(23469,38528) +(17255,48957),(17200,48903) +(27815,2138),(27808,2090) +(40440,11129),(40368,11105) +(35305,21772),(35272,21717) +(41308,45065),(41229,44973) +(14893,28807),(14817,28789) +(30776,45824),(30731,45772) +(742,40724),(652,40672) +(5985,41133),(5927,41097) +(9576,10226),(9540,10218) +(21407,23207),(21323,23160) +(44880,34228),(44877,34169) +(29146,49694),(29143,49682) +(28502,34886),(28471,34832) +(30662,5584),(30604,5528) +(12612,26081),(12552,26001) +(17166,49308),(17098,49270) +(9586,14116),(9488,14104) +(37323,47576),(37264,47482) +(48009,49713),(48004,49614) +(49308,23780),(49297,23760) +(8667,32342),(8592,32294) +(37826,48560),(37822,48485) +(24493,18653),(24486,18616) +(17914,3850),(17887,3775) +(34270,43873),(34231,43826) +(7753,44715),(7660,44651) +(44328,36364),(44265,36350) +(10146,3030),(10111,2975) +(35273,40106),(35269,40062) +(38566,43846),(38547,43760) +(12400,41394),(12377,41378) +(45196,38286),(45153,38250) +(48511,14972),(48428,14883) +(25939,36328),(25886,36277) +(38997,11007),(38979,10917) +(30342,518),(30244,453) +(6876,7468),(6867,7454) +(17566,27575),(17566,27480) +(18869,28538),(18858,28475) +(16825,33309),(16726,33255) +(14585,26111),(14490,26035) +(28743,49392),(28664,49349) +(26652,23359),(26618,23297) +(40129,33653),(40102,33584) +(41074,26393),(41038,26389) +(3869,33564),(3869,33536) +(28455,14205),(28364,14163) +(13866,45603),(13770,45543) +(21666,30586),(21578,30544) +(29978,11931),(29893,11868) +(1594,1043),(1517,971) +(948,1201),(907,1156) +(27547,13692),(27545,13677) +(13661,38184),(13566,38154) +(2389,40026),(2317,39938) +(35481,46379),(35481,46320) +(26917,45698),(26864,45689) +(23933,41617),(23909,41539) +(8912,8471),(8862,8401) +(9625,4747),(9558,4692) +(34743,35056),(34721,34969) +(39544,21762),(39475,21717) +(11741,26330),(11656,26293) +(39015,1315),(38966,1285) +(13418,44237),(13326,44202) +(2107,17672),(2093,17616) +(42448,28844),(42370,28764) +(49843,5175),(49808,5145) +(6536,23000),(6467,22958) +(11114,5822),(11027,5739) +(48457,11074),(48384,11024) +(12343,23110),(12310,23074) +(17300,24847),(17276,24825) +(8823,8253),(8793,8238) +(3449,171),(3354,108) +(21650,23955),(21605,23883) +(13260,3234),(13193,3214) +(25361,10896),(25305,10806) +(25051,25042),(25011,25001) +(25044,25088),(25015,25005) +(25007,25061),(25002,25013) +(25066,25105),(25003,25007) +(25028,25012),(25015,25011) +(25031,25057),(25006,25018) +(25015,25042),(25004,25012) +(25091,25049),(25019,25019) +(25023,25011),(25000,25004) +(25053,25104),(25010,25012) +(25058,25001),(25018,25000) +(25059,25051),(25008,25016) +(25043,25069),(25007,25004) +(25006,25101),(25002,25002) +(25095,25012),(25014,25007) +(25054,25052),(25019,25013) +(25108,25077),(25009,25018) +(25007,25023),(25003,25002) +(25076,25098),(25002,25016) +(25030,25077),(25012,25006) diff --git a/contrib/cube/expected/cube.out b/contrib/cube/expected/cube.out new file mode 100644 index 0000000..5b89cb1 --- /dev/null +++ b/contrib/cube/expected/cube.out @@ -0,0 +1,1950 @@ +-- +-- Test cube datatype +-- +CREATE EXTENSION cube; +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + amname | opcname +--------+--------- +(0 rows) + +-- +-- testing the input and output functions +-- +-- Any number (a one-dimensional point) +SELECT '1'::cube AS cube; + cube +------ + (1) +(1 row) + +SELECT '-1'::cube AS cube; + cube +------ + (-1) +(1 row) + +SELECT '1.'::cube AS cube; + cube +------ + (1) +(1 row) + +SELECT '-1.'::cube AS cube; + cube +------ + (-1) +(1 row) + +SELECT '.1'::cube AS cube; + cube +------- + (0.1) +(1 row) + +SELECT '-.1'::cube AS cube; + cube +-------- + (-0.1) +(1 row) + +SELECT '1.0'::cube AS cube; + cube +------ + (1) +(1 row) + +SELECT '-1.0'::cube AS cube; + cube +------ + (-1) +(1 row) + +SELECT 'infinity'::cube AS cube; + cube +------------ + (Infinity) +(1 row) + +SELECT '-infinity'::cube AS cube; + cube +------------- + (-Infinity) +(1 row) + +SELECT 'NaN'::cube AS cube; + cube +------- + (NaN) +(1 row) + +SELECT '.1234567890123456'::cube AS cube; + cube +---------------------- + (0.1234567890123456) +(1 row) + +SELECT '+.1234567890123456'::cube AS cube; + cube +---------------------- + (0.1234567890123456) +(1 row) + +SELECT '-.1234567890123456'::cube AS cube; + cube +----------------------- + (-0.1234567890123456) +(1 row) + +-- simple lists (points) +SELECT '()'::cube AS cube; + cube +------ + () +(1 row) + +SELECT '1,2'::cube AS cube; + cube +-------- + (1, 2) +(1 row) + +SELECT '(1,2)'::cube AS cube; + cube +-------- + (1, 2) +(1 row) + +SELECT '1,2,3,4,5'::cube AS cube; + cube +----------------- + (1, 2, 3, 4, 5) +(1 row) + +SELECT '(1,2,3,4,5)'::cube AS cube; + cube +----------------- + (1, 2, 3, 4, 5) +(1 row) + +-- double lists (cubes) +SELECT '(),()'::cube AS cube; + cube +------ + () +(1 row) + +SELECT '(0),(0)'::cube AS cube; + cube +------ + (0) +(1 row) + +SELECT '(0),(1)'::cube AS cube; + cube +--------- + (0),(1) +(1 row) + +SELECT '[(0),(0)]'::cube AS cube; + cube +------ + (0) +(1 row) + +SELECT '[(0),(1)]'::cube AS cube; + cube +--------- + (0),(1) +(1 row) + +SELECT '(0,0,0,0),(0,0,0,0)'::cube AS cube; + cube +-------------- + (0, 0, 0, 0) +(1 row) + +SELECT '(0,0,0,0),(1,0,0,0)'::cube AS cube; + cube +--------------------------- + (0, 0, 0, 0),(1, 0, 0, 0) +(1 row) + +SELECT '[(0,0,0,0),(0,0,0,0)]'::cube AS cube; + cube +-------------- + (0, 0, 0, 0) +(1 row) + +SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube; + cube +--------------------------- + (0, 0, 0, 0),(1, 0, 0, 0) +(1 row) + +-- invalid input: parse errors +SELECT ''::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT ''::cube AS cube; + ^ +DETAIL: syntax error at end of input +SELECT 'ABC'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT 'ABC'::cube AS cube; + ^ +DETAIL: syntax error at or near "A" +SELECT '[]'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '[]'::cube AS cube; + ^ +DETAIL: syntax error at or near "]" +SELECT '[()]'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '[()]'::cube AS cube; + ^ +DETAIL: syntax error at or near "]" +SELECT '[(1)]'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '[(1)]'::cube AS cube; + ^ +DETAIL: syntax error at or near "]" +SELECT '[(1),]'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '[(1),]'::cube AS cube; + ^ +DETAIL: syntax error at or near "]" +SELECT '[(1),2]'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '[(1),2]'::cube AS cube; + ^ +DETAIL: syntax error at or near "2" +SELECT '[(1),(2),(3)]'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '[(1),(2),(3)]'::cube AS cube; + ^ +DETAIL: syntax error at or near "," +SELECT '1,'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '1,'::cube AS cube; + ^ +DETAIL: syntax error at end of input +SELECT '1,2,'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '1,2,'::cube AS cube; + ^ +DETAIL: syntax error at end of input +SELECT '1,,2'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '1,,2'::cube AS cube; + ^ +DETAIL: syntax error at or near "," +SELECT '(1,)'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '(1,)'::cube AS cube; + ^ +DETAIL: syntax error at or near ")" +SELECT '(1,2,)'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '(1,2,)'::cube AS cube; + ^ +DETAIL: syntax error at or near ")" +SELECT '(1,,2)'::cube AS cube; +ERROR: invalid input syntax for cube +LINE 1: SELECT '(1,,2)'::cube AS cube; + ^ +DETAIL: syntax error at or near "," +-- invalid input: semantic errors and trailing garbage +SELECT '[(1),(2)],'::cube AS cube; -- 0 +ERROR: invalid input syntax for cube +LINE 1: SELECT '[(1),(2)],'::cube AS cube; + ^ +DETAIL: syntax error at or near "," +SELECT '[(1,2,3),(2,3)]'::cube AS cube; -- 1 +ERROR: invalid input syntax for cube +LINE 1: SELECT '[(1,2,3),(2,3)]'::cube AS cube; + ^ +DETAIL: Different point dimensions in (1,2,3) and (2,3). +SELECT '[(1,2),(1,2,3)]'::cube AS cube; -- 1 +ERROR: invalid input syntax for cube +LINE 1: SELECT '[(1,2),(1,2,3)]'::cube AS cube; + ^ +DETAIL: Different point dimensions in (1,2) and (1,2,3). +SELECT '(1),(2),'::cube AS cube; -- 2 +ERROR: invalid input syntax for cube +LINE 1: SELECT '(1),(2),'::cube AS cube; + ^ +DETAIL: syntax error at or near "," +SELECT '(1,2,3),(2,3)'::cube AS cube; -- 3 +ERROR: invalid input syntax for cube +LINE 1: SELECT '(1,2,3),(2,3)'::cube AS cube; + ^ +DETAIL: Different point dimensions in (1,2,3) and (2,3). +SELECT '(1,2),(1,2,3)'::cube AS cube; -- 3 +ERROR: invalid input syntax for cube +LINE 1: SELECT '(1,2),(1,2,3)'::cube AS cube; + ^ +DETAIL: Different point dimensions in (1,2) and (1,2,3). +SELECT '(1,2,3)ab'::cube AS cube; -- 4 +ERROR: invalid input syntax for cube +LINE 1: SELECT '(1,2,3)ab'::cube AS cube; + ^ +DETAIL: syntax error at or near "a" +SELECT '(1,2,3)a'::cube AS cube; -- 5 +ERROR: invalid input syntax for cube +LINE 1: SELECT '(1,2,3)a'::cube AS cube; + ^ +DETAIL: syntax error at or near "a" +SELECT '(1,2)('::cube AS cube; -- 5 +ERROR: invalid input syntax for cube +LINE 1: SELECT '(1,2)('::cube AS cube; + ^ +DETAIL: syntax error at or near "(" +SELECT '1,2ab'::cube AS cube; -- 6 +ERROR: invalid input syntax for cube +LINE 1: SELECT '1,2ab'::cube AS cube; + ^ +DETAIL: syntax error at or near "a" +SELECT '1 e7'::cube AS cube; -- 6 +ERROR: invalid input syntax for cube +LINE 1: SELECT '1 e7'::cube AS cube; + ^ +DETAIL: syntax error at or near "e" +SELECT '1,2a'::cube AS cube; -- 7 +ERROR: invalid input syntax for cube +LINE 1: SELECT '1,2a'::cube AS cube; + ^ +DETAIL: syntax error at or near "a" +SELECT '1..2'::cube AS cube; -- 7 +ERROR: invalid input syntax for cube +LINE 1: SELECT '1..2'::cube AS cube; + ^ +DETAIL: syntax error at or near ".2" +SELECT '-1e-700'::cube AS cube; -- out of range +ERROR: "-1e-700" is out of range for type double precision +LINE 1: SELECT '-1e-700'::cube AS cube; + ^ +-- +-- Testing building cubes from float8 values +-- +SELECT cube(0::float8); + cube +------ + (0) +(1 row) + +SELECT cube(1::float8); + cube +------ + (1) +(1 row) + +SELECT cube(1,2); + cube +--------- + (1),(2) +(1 row) + +SELECT cube(cube(1,2),3); + cube +--------------- + (1, 3),(2, 3) +(1 row) + +SELECT cube(cube(1,2),3,4); + cube +--------------- + (1, 3),(2, 4) +(1 row) + +SELECT cube(cube(cube(1,2),3,4),5); + cube +--------------------- + (1, 3, 5),(2, 4, 5) +(1 row) + +SELECT cube(cube(cube(1,2),3,4),5,6); + cube +--------------------- + (1, 3, 5),(2, 4, 6) +(1 row) + +-- +-- Test that the text -> cube cast was installed. +-- +SELECT '(0)'::text::cube; + cube +------ + (0) +(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),(1,3,5)'), ARRAY[3,2,1,1]); + cube_subset +-------------- + (5, 3, 1, 1) +(1 row) + +SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]); +ERROR: Index out of bounds +SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]); +ERROR: Index out of bounds +-- test for limits: this should pass +SELECT cube_subset(cube('(6,7,8),(6,7,8)'), array(SELECT 1 as a FROM generate_series(1,100))); + cube_subset +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + (6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6) +(1 row) + +-- and this should fail +SELECT cube_subset(cube('(6,7,8),(6,7,8)'), array(SELECT 1 as a FROM generate_series(1,101))); +ERROR: array is too long +DETAIL: A cube cannot have more than 100 dimensions. +-- +-- Test point processing +-- +SELECT cube('(1,2),(1,2)'); -- cube_in + cube +-------- + (1, 2) +(1 row) + +SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8 + cube +----------- + (0, 1, 2) +(1 row) + +SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8 + cube +-------------- + (5, 6, 7, 8) +(1 row) + +SELECT cube(1.37); -- cube_f8 + cube +-------- + (1.37) +(1 row) + +SELECT cube(1.37, 1.37); -- cube_f8_f8 + cube +-------- + (1.37) +(1 row) + +SELECT cube(cube(1,1), 42); -- cube_c_f8 + cube +--------- + (1, 42) +(1 row) + +SELECT cube(cube(1,2), 42); -- cube_c_f8 + cube +----------------- + (1, 42),(2, 42) +(1 row) + +SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8 + cube +--------- + (1, 42) +(1 row) + +SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8 + cube +----------------- + (1, 42),(1, 24) +(1 row) + +SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8 + cube +----------------- + (1, 42),(2, 42) +(1 row) + +SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8 + cube +----------------- + (1, 42),(2, 24) +(1 row) + +-- +-- Testing limit of CUBE_MAX_DIM dimensions check in cube_in. +-- +-- create too big cube from literal +select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; +ERROR: invalid input syntax for cube +LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... + ^ +DETAIL: A cube cannot have more than 100 dimensions. +select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; +ERROR: invalid input syntax for cube +LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... + ^ +DETAIL: A cube cannot have more than 100 dimensions. +-- from an array +select cube(array(SELECT 0 as a FROM generate_series(1,101))); +ERROR: array is too long +DETAIL: A cube cannot have more than 100 dimensions. +select cube(array(SELECT 0 as a FROM generate_series(1,101)),array(SELECT 0 as a FROM generate_series(1,101))); +ERROR: can't extend cube +DETAIL: A cube cannot have more than 100 dimensions. +-- extend cube beyond limit +-- this should work +select cube(array(SELECT 0 as a FROM generate_series(1,100))); + cube +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +(1 row) + +select cube(array(SELECT 0 as a FROM generate_series(1,100)),array(SELECT 0 as a FROM generate_series(1,100))); + cube +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) +(1 row) + +-- this should fail +select cube(cube(array(SELECT 0 as a FROM generate_series(1,100))), 0); +ERROR: can't extend cube +DETAIL: A cube cannot have more than 100 dimensions. +select cube(cube(array(SELECT 0 as a FROM generate_series(1,100)),array(SELECT 0 as a FROM generate_series(1,100))), 0, 0); +ERROR: can't extend cube +DETAIL: A cube cannot have more than 100 dimensions. +-- +-- testing the operators +-- +-- equality/inequality: +-- +SELECT '24, 33.20'::cube = '24, 33.20'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '24, 33.20'::cube != '24, 33.20'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '24, 33.20'::cube = '24, 33.21'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '24, 33.20'::cube != '24, 33.21'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; + bool +------ + f +(1 row) + +-- "lower than" / "greater than" +-- (these operators are not useful for anything but ordering) +-- +SELECT '1'::cube > '2'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '1'::cube < '2'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '1,1'::cube > '1,2'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '1,1'::cube < '1,2'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube > '(2,0),(3,1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube < '(2,0),(3,1)'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; + bool +------ + f +(1 row) + +-- "overlap" +-- +SELECT '1'::cube && '1'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '1'::cube && '2'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '0'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1,1,1'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1,1),(2,2,2)]'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1),(2,2)]'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(2,1,1),(2,2,2)]'::cube AS bool; + bool +------ + f +(1 row) + +-- "contained in" (the left operand is the cube entirely enclosed by +-- the right operand): +-- +SELECT '0'::cube <@ '0'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '0,0,0'::cube <@ '0,0,0'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '0,0'::cube <@ '0,0,1'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '0,0,0'::cube <@ '0,0,1'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '1,0,0'::cube <@ '0,0,1'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '(1,0,0),(0,0,1)'::cube <@ '(1,0,0),(0,0,1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(1,0,0),(0,0,1)'::cube <@ '(-1,-1,-1),(1,1,1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(1,0,0),(0,0,1)'::cube <@ '(-1,-1,-1,-1),(1,1,1,1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '0'::cube <@ '(-1),(1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '1'::cube <@ '(-1),(1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '-1'::cube <@ '(-1),(1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(-1),(1)'::cube <@ '(-1),(1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(-1),(1)'::cube <@ '(-1,-1),(1,1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(-2),(1)'::cube <@ '(-1),(1)'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '(-2),(1)'::cube <@ '(-1,-1),(1,1)'::cube AS bool; + bool +------ + f +(1 row) + +-- "contains" (the left operand is the cube that entirely encloses the +-- right operand) +-- +SELECT '0'::cube @> '0'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '0,0,0'::cube @> '0,0,0'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '0,0,1'::cube @> '0,0'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '0,0,1'::cube @> '0,0,0'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '0,0,1'::cube @> '1,0,0'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '(1,0,0),(0,0,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(-1,-1,-1),(1,1,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(-1,-1,-1,-1),(1,1,1,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(-1),(1)'::cube @> '0'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(-1),(1)'::cube @> '1'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(-1),(1)'::cube @> '-1'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(-1),(1)'::cube @> '(-1),(1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(-1,-1),(1,1)'::cube @> '(-1),(1)'::cube AS bool; + bool +------ + t +(1 row) + +SELECT '(-1),(1)'::cube @> '(-2),(1)'::cube AS bool; + bool +------ + f +(1 row) + +SELECT '(-1,-1),(1,1)'::cube @> '(-2),(1)'::cube AS bool; + bool +------ + f +(1 row) + +-- Test of distance function +-- +SELECT cube_distance('(0)'::cube,'(2,2,2,2)'::cube); + cube_distance +--------------- + 4 +(1 row) + +SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); + cube_distance +--------------- + 0.5 +(1 row) + +SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube); + cube_distance +--------------- + 0 +(1 row) + +SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube); + cube_distance +--------------- + 190 +(1 row) + +SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube); + cube_distance +-------------------- + 140.76221083799445 +(1 row) + +-- Test of cube function (text to cube) +-- +SELECT cube('(1,1.2)'::text); + cube +---------- + (1, 1.2) +(1 row) + +SELECT cube(NULL); + cube +------ + +(1 row) + +-- Test of cube_dim function (dimensions stored in cube) +-- +SELECT cube_dim('(0)'::cube); + cube_dim +---------- + 1 +(1 row) + +SELECT cube_dim('(0,0)'::cube); + cube_dim +---------- + 2 +(1 row) + +SELECT cube_dim('(0,0,0)'::cube); + cube_dim +---------- + 3 +(1 row) + +SELECT cube_dim('(42,42,42),(42,42,42)'::cube); + cube_dim +---------- + 3 +(1 row) + +SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube); + cube_dim +---------- + 5 +(1 row) + +-- Test of cube_ll_coord function (retrieves LL coordinate values) +-- +SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1); + cube_ll_coord +--------------- + -1 +(1 row) + +SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 2); + cube_ll_coord +--------------- + -2 +(1 row) + +SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3); + cube_ll_coord +--------------- + 0 +(1 row) + +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1); + cube_ll_coord +--------------- + 1 +(1 row) + +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2); + cube_ll_coord +--------------- + 2 +(1 row) + +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3); + cube_ll_coord +--------------- + 0 +(1 row) + +SELECT cube_ll_coord('(42,137)'::cube, 1); + cube_ll_coord +--------------- + 42 +(1 row) + +SELECT cube_ll_coord('(42,137)'::cube, 2); + cube_ll_coord +--------------- + 137 +(1 row) + +SELECT cube_ll_coord('(42,137)'::cube, 3); + cube_ll_coord +--------------- + 0 +(1 row) + +-- Test of cube_ur_coord function (retrieves UR coordinate values) +-- +SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1); + cube_ur_coord +--------------- + 2 +(1 row) + +SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 2); + cube_ur_coord +--------------- + 1 +(1 row) + +SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3); + cube_ur_coord +--------------- + 0 +(1 row) + +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1); + cube_ur_coord +--------------- + 1 +(1 row) + +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2); + cube_ur_coord +--------------- + 2 +(1 row) + +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3); + cube_ur_coord +--------------- + 0 +(1 row) + +SELECT cube_ur_coord('(42,137)'::cube, 1); + cube_ur_coord +--------------- + 42 +(1 row) + +SELECT cube_ur_coord('(42,137)'::cube, 2); + cube_ur_coord +--------------- + 137 +(1 row) + +SELECT cube_ur_coord('(42,137)'::cube, 3); + cube_ur_coord +--------------- + 0 +(1 row) + +-- Test of cube_is_point +-- +SELECT cube_is_point('(0)'::cube); + cube_is_point +--------------- + t +(1 row) + +SELECT cube_is_point('(0,1,2)'::cube); + cube_is_point +--------------- + t +(1 row) + +SELECT cube_is_point('(0,1,2),(0,1,2)'::cube); + cube_is_point +--------------- + t +(1 row) + +SELECT cube_is_point('(0,1,2),(-1,1,2)'::cube); + cube_is_point +--------------- + f +(1 row) + +SELECT cube_is_point('(0,1,2),(0,-1,2)'::cube); + cube_is_point +--------------- + f +(1 row) + +SELECT cube_is_point('(0,1,2),(0,1,-2)'::cube); + cube_is_point +--------------- + f +(1 row) + +-- Test of cube_enlarge (enlarging and shrinking cubes) +-- +SELECT cube_enlarge('(0)'::cube, 0, 0); + cube_enlarge +-------------- + (0) +(1 row) + +SELECT cube_enlarge('(0)'::cube, 0, 1); + cube_enlarge +-------------- + (0) +(1 row) + +SELECT cube_enlarge('(0)'::cube, 0, 2); + cube_enlarge +-------------- + (0) +(1 row) + +SELECT cube_enlarge('(2),(-2)'::cube, 0, 4); + cube_enlarge +-------------- + (-2),(2) +(1 row) + +SELECT cube_enlarge('(0)'::cube, 1, 0); + cube_enlarge +-------------- + (-1),(1) +(1 row) + +SELECT cube_enlarge('(0)'::cube, 1, 1); + cube_enlarge +-------------- + (-1),(1) +(1 row) + +SELECT cube_enlarge('(0)'::cube, 1, 2); + cube_enlarge +----------------- + (-1, -1),(1, 1) +(1 row) + +SELECT cube_enlarge('(2),(-2)'::cube, 1, 4); + cube_enlarge +------------------------------- + (-3, -1, -1, -1),(3, 1, 1, 1) +(1 row) + +SELECT cube_enlarge('(0)'::cube, -1, 0); + cube_enlarge +-------------- + (0) +(1 row) + +SELECT cube_enlarge('(0)'::cube, -1, 1); + cube_enlarge +-------------- + (0) +(1 row) + +SELECT cube_enlarge('(0)'::cube, -1, 2); + cube_enlarge +-------------- + (0) +(1 row) + +SELECT cube_enlarge('(2),(-2)'::cube, -1, 4); + cube_enlarge +-------------- + (-1),(1) +(1 row) + +SELECT cube_enlarge('(0,0,0)'::cube, 1, 0); + cube_enlarge +------------------------ + (-1, -1, -1),(1, 1, 1) +(1 row) + +SELECT cube_enlarge('(0,0,0)'::cube, 1, 2); + cube_enlarge +------------------------ + (-1, -1, -1),(1, 1, 1) +(1 row) + +SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 1, 2); + cube_enlarge +----------------- + (-4, -3),(3, 8) +(1 row) + +SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 3, 2); + cube_enlarge +------------------ + (-6, -5),(5, 10) +(1 row) + +SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -1, 2); + cube_enlarge +----------------- + (-2, -1),(1, 6) +(1 row) + +SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2); + cube_enlarge +--------------------- + (-0.5, 1),(-0.5, 4) +(1 row) + +SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5); + cube_enlarge +-------------- + (42, 0, 0) +(1 row) + +SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5); + cube_enlarge +-------------- + (42, 0, 0) +(1 row) + +-- Test of cube_union (MBR for two cubes) +-- +SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube); + cube_union +---------------------- + (1, 2, 0),(8, 9, 10) +(1 row) + +SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube); + cube_union +--------------------------- + (1, 2, 0, 0),(4, 2, 0, 0) +(1 row) + +SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube); + cube_union +--------------- + (1, 2),(4, 2) +(1 row) + +SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube); + cube_union +------------ + (1, 2) +(1 row) + +SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube); + cube_union +------------ + (1, 2, 0) +(1 row) + +-- Test of cube_inter +-- +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects + cube_inter +----------------- + (3, 4),(10, 11) +(1 row) + +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes + cube_inter +--------------- + (3, 4),(6, 5) +(1 row) + +SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection + cube_inter +------------------- + (13, 14),(10, 11) +(1 row) + +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects + cube_inter +------------------ + (3, 14),(10, 11) +(1 row) + +SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection + cube_inter +------------ + (10, 11) +(1 row) + +SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args + cube_inter +------------ + (1, 2, 3) +(1 row) + +SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args + cube_inter +--------------------- + (5, 6, 3),(1, 2, 3) +(1 row) + +-- Test of cube_size +-- +SELECT cube_size('(4,8),(15,16)'::cube); + cube_size +----------- + 88 +(1 row) + +SELECT cube_size('(42,137)'::cube); + cube_size +----------- + 0 +(1 row) + +-- Test of distances (euclidean distance may not be bit-exact) +-- +SET extra_float_digits = 0; +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) + +RESET extra_float_digits; +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 0 is out of bounds +SELECT cube(array[10,20,30], array[40,50,60])->7; +ERROR: cube index 7 is out of bounds +SELECT cube(array[10,20,30], array[40,50,60])->-1; +ERROR: cube index -1 is out of bounds +SELECT cube(array[10,20,30], array[40,50,60])->-6; +ERROR: cube index -6 is 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 -6 is 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? +---------- + 40 +(1 row) + +SELECT cube(array[40,50,60], array[10,20,30])~>2; + ?column? +---------- + 40 +(1 row) + +SELECT cube(array[10,20,30], array[40,50,60])~>3; + ?column? +---------- + 20 +(1 row) + +SELECT cube(array[40,50,60], array[10,20,30])~>3; + ?column? +---------- + 20 +(1 row) + +SELECT cube(array[40,50,60], array[10,20,30])~>0; +ERROR: zero cube index is not defined +SELECT cube(array[40,50,60], array[10,20,30])~>4; + ?column? +---------- + 50 +(1 row) + +SELECT cube(array[40,50,60], array[10,20,30])~>(-1); + ?column? +---------- + -10 +(1 row) + +-- Load some example data and build the index +-- +CREATE TABLE test_cube (c cube); +\copy test_cube from 'data/test_cube.data' +CREATE INDEX test_cube_ix ON test_cube USING gist (c); +SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' ORDER BY c; + c +-------------------------- + (337, 455),(240, 359) + (759, 187),(662, 163) + (1444, 403),(1346, 344) + (1594, 1043),(1517, 971) + (2424, 160),(2424, 81) +(5 rows) + +-- Test sorting +SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c; + c +-------------------------- + (337, 455),(240, 359) + (759, 187),(662, 163) + (1444, 403),(1346, 344) + (1594, 1043),(1517, 971) + (2424, 160),(2424, 81) +(5 rows) + +-- Test index-only scans +SET enable_bitmapscan = false; +EXPLAIN (COSTS OFF) +SELECT c FROM test_cube WHERE c <@ '(3000,1000),(0,0)' ORDER BY c; + QUERY PLAN +-------------------------------------------------------- + Sort + Sort Key: c + -> Index Only Scan using test_cube_ix on test_cube + Index Cond: (c <@ '(3000, 1000),(0, 0)'::cube) +(4 rows) + +SELECT c FROM test_cube WHERE c <@ '(3000,1000),(0,0)' ORDER BY c; + c +------------------------- + (337, 455),(240, 359) + (759, 187),(662, 163) + (1444, 403),(1346, 344) + (2424, 160),(2424, 81) +(4 rows) + +RESET enable_bitmapscan; +-- Test kNN +INSERT INTO test_cube VALUES ('(1,1)'), ('(100000)'), ('(0, 100000)'); -- Some corner cases +SET enable_seqscan = false; +-- Test different metrics +SET extra_float_digits = 0; +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 + (1, 1) | 140.007142674936 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 772.000647668122 + (1444, 403),(1346, 344) | 846 +(5 rows) + +RESET extra_float_digits; +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 + (1, 1) | 99 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 656 + (1444, 403),(1346, 344) | 846 +(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 + (1, 1) | 198 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 +(5 rows) + +-- Test sorting by coordinates +SELECT c~>1, c FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by left bound + ?column? | c +----------+--------------------------- + 0 | (0, 100000) + 1 | (1, 1) + 3 | (54, 38679),(3, 38602) + 15 | (83, 10271),(15, 10265) + 64 | (122, 46832),(64, 46762) + 92 | (167, 17214),(92, 17184) + 107 | (161, 24465),(107, 24374) + 120 | (162, 26040),(120, 25963) + 138 | (154, 4019),(138, 3990) + 175 | (259, 1850),(175, 1820) + 179 | (207, 40886),(179, 40879) + 204 | (288, 49588),(204, 49571) + 226 | (270, 32616),(226, 32607) + 235 | (318, 31489),(235, 31404) + 240 | (337, 455),(240, 359) +(15 rows) + +SELECT c~>2, c FROM test_cube ORDER BY c~>2 LIMIT 15; -- ascending by right bound + ?column? | c +----------+--------------------------- + 0 | (0, 100000) + 1 | (1, 1) + 54 | (54, 38679),(3, 38602) + 83 | (83, 10271),(15, 10265) + 122 | (122, 46832),(64, 46762) + 154 | (154, 4019),(138, 3990) + 161 | (161, 24465),(107, 24374) + 162 | (162, 26040),(120, 25963) + 167 | (167, 17214),(92, 17184) + 207 | (207, 40886),(179, 40879) + 259 | (259, 1850),(175, 1820) + 270 | (270, 29508),(264, 29440) + 270 | (270, 32616),(226, 32607) + 288 | (288, 49588),(204, 49571) + 318 | (318, 31489),(235, 31404) +(15 rows) + +SELECT c~>3, c FROM test_cube ORDER BY c~>3 LIMIT 15; -- ascending by lower bound + ?column? | c +----------+--------------------------- + 0 | (100000) + 1 | (1, 1) + 6 | (30333, 50),(30273, 6) + 43 | (43301, 75),(43227, 43) + 51 | (19650, 142),(19630, 51) + 81 | (2424, 160),(2424, 81) + 108 | (3449, 171),(3354, 108) + 109 | (18037, 155),(17941, 109) + 114 | (28511, 208),(28479, 114) + 118 | (19946, 217),(19941, 118) + 139 | (16906, 191),(16816, 139) + 163 | (759, 187),(662, 163) + 181 | (22684, 266),(22656, 181) + 213 | (24423, 255),(24360, 213) + 222 | (45989, 249),(45910, 222) +(15 rows) + +SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper bound + ?column? | c +----------+--------------------------- + 0 | (100000) + 1 | (1, 1) + 50 | (30333, 50),(30273, 6) + 75 | (43301, 75),(43227, 43) + 142 | (19650, 142),(19630, 51) + 155 | (18037, 155),(17941, 109) + 160 | (2424, 160),(2424, 81) + 171 | (3449, 171),(3354, 108) + 187 | (759, 187),(662, 163) + 191 | (16906, 191),(16816, 139) + 208 | (28511, 208),(28479, 114) + 217 | (19946, 217),(19941, 118) + 249 | (45989, 249),(45910, 222) + 255 | (24423, 255),(24360, 213) + 266 | (22684, 266),(22656, 181) +(15 rows) + +SELECT c~>(-1), c FROM test_cube ORDER BY c~>(-1) LIMIT 15; -- descending by left bound + ?column? | c +----------+------------------------------- + -100000 | (100000) + -49951 | (50027, 49230),(49951, 49214) + -49937 | (49980, 35004),(49937, 34963) + -49927 | (49985, 6436),(49927, 6338) + -49908 | (49999, 27218),(49908, 27176) + -49905 | (49954, 1340),(49905, 1294) + -49902 | (49944, 25163),(49902, 25153) + -49898 | (49981, 34876),(49898, 34786) + -49897 | (49957, 43390),(49897, 43384) + -49848 | (49853, 18504),(49848, 18503) + -49818 | (49902, 41752),(49818, 41746) + -49810 | (49907, 30225),(49810, 30158) + -49808 | (49843, 5175),(49808, 5145) + -49805 | (49887, 24274),(49805, 24184) + -49798 | (49847, 7128),(49798, 7067) +(15 rows) + +SELECT c~>(-2), c FROM test_cube ORDER BY c~>(-2) LIMIT 15; -- descending by right bound + ?column? | c +----------+------------------------------- + -100000 | (100000) + -50027 | (50027, 49230),(49951, 49214) + -49999 | (49999, 27218),(49908, 27176) + -49985 | (49985, 6436),(49927, 6338) + -49981 | (49981, 34876),(49898, 34786) + -49980 | (49980, 35004),(49937, 34963) + -49957 | (49957, 43390),(49897, 43384) + -49954 | (49954, 1340),(49905, 1294) + -49944 | (49944, 25163),(49902, 25153) + -49907 | (49907, 30225),(49810, 30158) + -49902 | (49902, 41752),(49818, 41746) + -49887 | (49887, 24274),(49805, 24184) + -49853 | (49853, 18504),(49848, 18503) + -49847 | (49847, 7128),(49798, 7067) + -49843 | (49843, 5175),(49808, 5145) +(15 rows) + +SELECT c~>(-3), c FROM test_cube ORDER BY c~>(-3) LIMIT 15; -- descending by lower bound + ?column? | c +----------+------------------------------- + -100000 | (0, 100000) + -49992 | (30746, 50040),(30727, 49992) + -49987 | (36311, 50073),(36258, 49987) + -49934 | (3531, 49962),(3463, 49934) + -49915 | (17954, 49975),(17865, 49915) + -49914 | (2168, 50012),(2108, 49914) + -49913 | (31287, 49923),(31236, 49913) + -49885 | (21551, 49983),(21492, 49885) + -49878 | (43925, 49912),(43888, 49878) + -49849 | (19128, 49932),(19112, 49849) + -49844 | (38266, 49852),(38233, 49844) + -49836 | (14913, 49873),(14849, 49836) + -49834 | (37595, 49849),(37581, 49834) + -49830 | (46151, 49848),(46058, 49830) + -49818 | (29261, 49910),(29247, 49818) +(15 rows) + +SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upper bound + ?column? | c +----------+------------------------------- + -100000 | (0, 100000) + -50073 | (36311, 50073),(36258, 49987) + -50040 | (30746, 50040),(30727, 49992) + -50012 | (2168, 50012),(2108, 49914) + -49983 | (21551, 49983),(21492, 49885) + -49975 | (17954, 49975),(17865, 49915) + -49962 | (3531, 49962),(3463, 49934) + -49932 | (19128, 49932),(19112, 49849) + -49923 | (31287, 49923),(31236, 49913) + -49912 | (43925, 49912),(43888, 49878) + -49910 | (29261, 49910),(29247, 49818) + -49873 | (14913, 49873),(14849, 49836) + -49858 | (20007, 49858),(19921, 49778) + -49852 | (38266, 49852),(38233, 49844) + -49849 | (37595, 49849),(37581, 49834) +(15 rows) + +-- Same queries with sequential scan (should give the same results as above) +RESET enable_seqscan; +SET enable_indexscan = OFF; +SET extra_float_digits = 0; +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 + (1, 1) | 140.007142674936 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 772.000647668122 + (1444, 403),(1346, 344) | 846 +(5 rows) + +RESET extra_float_digits; +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 + (1, 1) | 99 + (759, 187),(662, 163) | 162 + (948, 1201),(907, 1156) | 656 + (1444, 403),(1346, 344) | 846 +(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 + (1, 1) | 198 + (1444, 403),(1346, 344) | 846 + (369, 1457),(278, 1409) | 909 +(5 rows) + +SELECT c~>1, c FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by left bound + ?column? | c +----------+--------------------------- + 0 | (0, 100000) + 1 | (1, 1) + 3 | (54, 38679),(3, 38602) + 15 | (83, 10271),(15, 10265) + 64 | (122, 46832),(64, 46762) + 92 | (167, 17214),(92, 17184) + 107 | (161, 24465),(107, 24374) + 120 | (162, 26040),(120, 25963) + 138 | (154, 4019),(138, 3990) + 175 | (259, 1850),(175, 1820) + 179 | (207, 40886),(179, 40879) + 204 | (288, 49588),(204, 49571) + 226 | (270, 32616),(226, 32607) + 235 | (318, 31489),(235, 31404) + 240 | (337, 455),(240, 359) +(15 rows) + +SELECT c~>2, c FROM test_cube ORDER BY c~>2 LIMIT 15; -- ascending by right bound + ?column? | c +----------+--------------------------- + 0 | (0, 100000) + 1 | (1, 1) + 54 | (54, 38679),(3, 38602) + 83 | (83, 10271),(15, 10265) + 122 | (122, 46832),(64, 46762) + 154 | (154, 4019),(138, 3990) + 161 | (161, 24465),(107, 24374) + 162 | (162, 26040),(120, 25963) + 167 | (167, 17214),(92, 17184) + 207 | (207, 40886),(179, 40879) + 259 | (259, 1850),(175, 1820) + 270 | (270, 29508),(264, 29440) + 270 | (270, 32616),(226, 32607) + 288 | (288, 49588),(204, 49571) + 318 | (318, 31489),(235, 31404) +(15 rows) + +SELECT c~>3, c FROM test_cube ORDER BY c~>3 LIMIT 15; -- ascending by lower bound + ?column? | c +----------+--------------------------- + 0 | (100000) + 1 | (1, 1) + 6 | (30333, 50),(30273, 6) + 43 | (43301, 75),(43227, 43) + 51 | (19650, 142),(19630, 51) + 81 | (2424, 160),(2424, 81) + 108 | (3449, 171),(3354, 108) + 109 | (18037, 155),(17941, 109) + 114 | (28511, 208),(28479, 114) + 118 | (19946, 217),(19941, 118) + 139 | (16906, 191),(16816, 139) + 163 | (759, 187),(662, 163) + 181 | (22684, 266),(22656, 181) + 213 | (24423, 255),(24360, 213) + 222 | (45989, 249),(45910, 222) +(15 rows) + +SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper bound + ?column? | c +----------+--------------------------- + 0 | (100000) + 1 | (1, 1) + 50 | (30333, 50),(30273, 6) + 75 | (43301, 75),(43227, 43) + 142 | (19650, 142),(19630, 51) + 155 | (18037, 155),(17941, 109) + 160 | (2424, 160),(2424, 81) + 171 | (3449, 171),(3354, 108) + 187 | (759, 187),(662, 163) + 191 | (16906, 191),(16816, 139) + 208 | (28511, 208),(28479, 114) + 217 | (19946, 217),(19941, 118) + 249 | (45989, 249),(45910, 222) + 255 | (24423, 255),(24360, 213) + 266 | (22684, 266),(22656, 181) +(15 rows) + +SELECT c~>(-1), c FROM test_cube ORDER BY c~>(-1) LIMIT 15; -- descending by left bound + ?column? | c +----------+------------------------------- + -100000 | (100000) + -49951 | (50027, 49230),(49951, 49214) + -49937 | (49980, 35004),(49937, 34963) + -49927 | (49985, 6436),(49927, 6338) + -49908 | (49999, 27218),(49908, 27176) + -49905 | (49954, 1340),(49905, 1294) + -49902 | (49944, 25163),(49902, 25153) + -49898 | (49981, 34876),(49898, 34786) + -49897 | (49957, 43390),(49897, 43384) + -49848 | (49853, 18504),(49848, 18503) + -49818 | (49902, 41752),(49818, 41746) + -49810 | (49907, 30225),(49810, 30158) + -49808 | (49843, 5175),(49808, 5145) + -49805 | (49887, 24274),(49805, 24184) + -49798 | (49847, 7128),(49798, 7067) +(15 rows) + +SELECT c~>(-2), c FROM test_cube ORDER BY c~>(-2) LIMIT 15; -- descending by right bound + ?column? | c +----------+------------------------------- + -100000 | (100000) + -50027 | (50027, 49230),(49951, 49214) + -49999 | (49999, 27218),(49908, 27176) + -49985 | (49985, 6436),(49927, 6338) + -49981 | (49981, 34876),(49898, 34786) + -49980 | (49980, 35004),(49937, 34963) + -49957 | (49957, 43390),(49897, 43384) + -49954 | (49954, 1340),(49905, 1294) + -49944 | (49944, 25163),(49902, 25153) + -49907 | (49907, 30225),(49810, 30158) + -49902 | (49902, 41752),(49818, 41746) + -49887 | (49887, 24274),(49805, 24184) + -49853 | (49853, 18504),(49848, 18503) + -49847 | (49847, 7128),(49798, 7067) + -49843 | (49843, 5175),(49808, 5145) +(15 rows) + +SELECT c~>(-3), c FROM test_cube ORDER BY c~>(-3) LIMIT 15; -- descending by lower bound + ?column? | c +----------+------------------------------- + -100000 | (0, 100000) + -49992 | (30746, 50040),(30727, 49992) + -49987 | (36311, 50073),(36258, 49987) + -49934 | (3531, 49962),(3463, 49934) + -49915 | (17954, 49975),(17865, 49915) + -49914 | (2168, 50012),(2108, 49914) + -49913 | (31287, 49923),(31236, 49913) + -49885 | (21551, 49983),(21492, 49885) + -49878 | (43925, 49912),(43888, 49878) + -49849 | (19128, 49932),(19112, 49849) + -49844 | (38266, 49852),(38233, 49844) + -49836 | (14913, 49873),(14849, 49836) + -49834 | (37595, 49849),(37581, 49834) + -49830 | (46151, 49848),(46058, 49830) + -49818 | (29261, 49910),(29247, 49818) +(15 rows) + +SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upper bound + ?column? | c +----------+------------------------------- + -100000 | (0, 100000) + -50073 | (36311, 50073),(36258, 49987) + -50040 | (30746, 50040),(30727, 49992) + -50012 | (2168, 50012),(2108, 49914) + -49983 | (21551, 49983),(21492, 49885) + -49975 | (17954, 49975),(17865, 49915) + -49962 | (3531, 49962),(3463, 49934) + -49932 | (19128, 49932),(19112, 49849) + -49923 | (31287, 49923),(31236, 49913) + -49912 | (43925, 49912),(43888, 49878) + -49910 | (29261, 49910),(29247, 49818) + -49873 | (14913, 49873),(14849, 49836) + -49858 | (20007, 49858),(19921, 49778) + -49852 | (38266, 49852),(38233, 49844) + -49849 | (37595, 49849),(37581, 49834) +(15 rows) + +RESET enable_indexscan; diff --git a/contrib/cube/expected/cube_sci.out b/contrib/cube/expected/cube_sci.out new file mode 100644 index 0000000..488499a --- /dev/null +++ b/contrib/cube/expected/cube_sci.out @@ -0,0 +1,106 @@ +--- +--- Testing cube output in scientific notation. This was put into separate +--- test, because has platform-depending output. +--- +SELECT '1e27'::cube AS cube; + cube +--------- + (1e+27) +(1 row) + +SELECT '-1e27'::cube AS cube; + cube +---------- + (-1e+27) +(1 row) + +SELECT '1.0e27'::cube AS cube; + cube +--------- + (1e+27) +(1 row) + +SELECT '-1.0e27'::cube AS cube; + cube +---------- + (-1e+27) +(1 row) + +SELECT '1e+27'::cube AS cube; + cube +--------- + (1e+27) +(1 row) + +SELECT '-1e+27'::cube AS cube; + cube +---------- + (-1e+27) +(1 row) + +SELECT '1.0e+27'::cube AS cube; + cube +--------- + (1e+27) +(1 row) + +SELECT '-1.0e+27'::cube AS cube; + cube +---------- + (-1e+27) +(1 row) + +SELECT '1e-7'::cube AS cube; + cube +--------- + (1e-07) +(1 row) + +SELECT '-1e-7'::cube AS cube; + cube +---------- + (-1e-07) +(1 row) + +SELECT '1.0e-7'::cube AS cube; + cube +--------- + (1e-07) +(1 row) + +SELECT '-1.0e-7'::cube AS cube; + cube +---------- + (-1e-07) +(1 row) + +SELECT '1e-300'::cube AS cube; + cube +---------- + (1e-300) +(1 row) + +SELECT '-1e-300'::cube AS cube; + cube +----------- + (-1e-300) +(1 row) + +SELECT '1234567890123456'::cube AS cube; + cube +------------------------- + (1.234567890123456e+15) +(1 row) + +SELECT '+1234567890123456'::cube AS cube; + cube +------------------------- + (1.234567890123456e+15) +(1 row) + +SELECT '-1234567890123456'::cube AS cube; + cube +-------------------------- + (-1.234567890123456e+15) +(1 row) + diff --git a/contrib/cube/sql/cube.sql b/contrib/cube/sql/cube.sql new file mode 100644 index 0000000..7f8b2e3 --- /dev/null +++ b/contrib/cube/sql/cube.sql @@ -0,0 +1,432 @@ +-- +-- Test cube datatype +-- + +CREATE EXTENSION cube; + +-- Check whether any of our opclasses fail amvalidate +SELECT amname, opcname +FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod +WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid); + +-- +-- testing the input and output functions +-- + +-- Any number (a one-dimensional point) +SELECT '1'::cube AS cube; +SELECT '-1'::cube AS cube; +SELECT '1.'::cube AS cube; +SELECT '-1.'::cube AS cube; +SELECT '.1'::cube AS cube; +SELECT '-.1'::cube AS cube; +SELECT '1.0'::cube AS cube; +SELECT '-1.0'::cube AS cube; +SELECT 'infinity'::cube AS cube; +SELECT '-infinity'::cube AS cube; +SELECT 'NaN'::cube AS cube; +SELECT '.1234567890123456'::cube AS cube; +SELECT '+.1234567890123456'::cube AS cube; +SELECT '-.1234567890123456'::cube AS cube; + +-- simple lists (points) +SELECT '()'::cube AS cube; +SELECT '1,2'::cube AS cube; +SELECT '(1,2)'::cube AS cube; +SELECT '1,2,3,4,5'::cube AS cube; +SELECT '(1,2,3,4,5)'::cube AS cube; + +-- double lists (cubes) +SELECT '(),()'::cube AS cube; +SELECT '(0),(0)'::cube AS cube; +SELECT '(0),(1)'::cube AS cube; +SELECT '[(0),(0)]'::cube AS cube; +SELECT '[(0),(1)]'::cube AS cube; +SELECT '(0,0,0,0),(0,0,0,0)'::cube AS cube; +SELECT '(0,0,0,0),(1,0,0,0)'::cube AS cube; +SELECT '[(0,0,0,0),(0,0,0,0)]'::cube AS cube; +SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube; + +-- invalid input: parse errors +SELECT ''::cube AS cube; +SELECT 'ABC'::cube AS cube; +SELECT '[]'::cube AS cube; +SELECT '[()]'::cube AS cube; +SELECT '[(1)]'::cube AS cube; +SELECT '[(1),]'::cube AS cube; +SELECT '[(1),2]'::cube AS cube; +SELECT '[(1),(2),(3)]'::cube AS cube; +SELECT '1,'::cube AS cube; +SELECT '1,2,'::cube AS cube; +SELECT '1,,2'::cube AS cube; +SELECT '(1,)'::cube AS cube; +SELECT '(1,2,)'::cube AS cube; +SELECT '(1,,2)'::cube AS cube; + +-- invalid input: semantic errors and trailing garbage +SELECT '[(1),(2)],'::cube AS cube; -- 0 +SELECT '[(1,2,3),(2,3)]'::cube AS cube; -- 1 +SELECT '[(1,2),(1,2,3)]'::cube AS cube; -- 1 +SELECT '(1),(2),'::cube AS cube; -- 2 +SELECT '(1,2,3),(2,3)'::cube AS cube; -- 3 +SELECT '(1,2),(1,2,3)'::cube AS cube; -- 3 +SELECT '(1,2,3)ab'::cube AS cube; -- 4 +SELECT '(1,2,3)a'::cube AS cube; -- 5 +SELECT '(1,2)('::cube AS cube; -- 5 +SELECT '1,2ab'::cube AS cube; -- 6 +SELECT '1 e7'::cube AS cube; -- 6 +SELECT '1,2a'::cube AS cube; -- 7 +SELECT '1..2'::cube AS cube; -- 7 +SELECT '-1e-700'::cube AS cube; -- out of range + +-- +-- Testing building cubes from float8 values +-- + +SELECT cube(0::float8); +SELECT cube(1::float8); +SELECT cube(1,2); +SELECT cube(cube(1,2),3); +SELECT cube(cube(1,2),3,4); +SELECT cube(cube(cube(1,2),3,4),5); +SELECT cube(cube(cube(1,2),3,4),5,6); + +-- +-- Test that the text -> cube cast was installed. +-- + +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),(1,3,5)'), ARRAY[3,2,1,1]); +SELECT cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[4,0]); +SELECT cube_subset(cube('(6,7,8),(6,7,8)'), ARRAY[4,0]); +-- test for limits: this should pass +SELECT cube_subset(cube('(6,7,8),(6,7,8)'), array(SELECT 1 as a FROM generate_series(1,100))); +-- and this should fail +SELECT cube_subset(cube('(6,7,8),(6,7,8)'), array(SELECT 1 as a FROM generate_series(1,101))); + + + +-- +-- Test point processing +-- +SELECT cube('(1,2),(1,2)'); -- cube_in +SELECT cube('{0,1,2}'::float[], '{0,1,2}'::float[]); -- cube_a_f8_f8 +SELECT cube('{5,6,7,8}'::float[]); -- cube_a_f8 +SELECT cube(1.37); -- cube_f8 +SELECT cube(1.37, 1.37); -- cube_f8_f8 +SELECT cube(cube(1,1), 42); -- cube_c_f8 +SELECT cube(cube(1,2), 42); -- cube_c_f8 +SELECT cube(cube(1,1), 42, 42); -- cube_c_f8_f8 +SELECT cube(cube(1,1), 42, 24); -- cube_c_f8_f8 +SELECT cube(cube(1,2), 42, 42); -- cube_c_f8_f8 +SELECT cube(cube(1,2), 42, 24); -- cube_c_f8_f8 + +-- +-- Testing limit of CUBE_MAX_DIM dimensions check in cube_in. +-- +-- create too big cube from literal +select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; +select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube; +-- from an array +select cube(array(SELECT 0 as a FROM generate_series(1,101))); +select cube(array(SELECT 0 as a FROM generate_series(1,101)),array(SELECT 0 as a FROM generate_series(1,101))); + +-- extend cube beyond limit +-- this should work +select cube(array(SELECT 0 as a FROM generate_series(1,100))); +select cube(array(SELECT 0 as a FROM generate_series(1,100)),array(SELECT 0 as a FROM generate_series(1,100))); +-- this should fail +select cube(cube(array(SELECT 0 as a FROM generate_series(1,100))), 0); +select cube(cube(array(SELECT 0 as a FROM generate_series(1,100)),array(SELECT 0 as a FROM generate_series(1,100))), 0, 0); + + +-- +-- testing the operators +-- + +-- equality/inequality: +-- +SELECT '24, 33.20'::cube = '24, 33.20'::cube AS bool; +SELECT '24, 33.20'::cube != '24, 33.20'::cube AS bool; +SELECT '24, 33.20'::cube = '24, 33.21'::cube AS bool; +SELECT '24, 33.20'::cube != '24, 33.21'::cube AS bool; +SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; +SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; + +-- "lower than" / "greater than" +-- (these operators are not useful for anything but ordering) +-- +SELECT '1'::cube > '2'::cube AS bool; +SELECT '1'::cube < '2'::cube AS bool; +SELECT '1,1'::cube > '1,2'::cube AS bool; +SELECT '1,1'::cube < '1,2'::cube AS bool; + +SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; +SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; +SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; +SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; +SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; +SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; +SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube > '(2,0),(3,1)'::cube AS bool; +SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube < '(2,0),(3,1)'::cube AS bool; +SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; +SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; +SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; +SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; + + +-- "overlap" +-- +SELECT '1'::cube && '1'::cube AS bool; +SELECT '1'::cube && '2'::cube AS bool; + +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '0'::cube AS bool; +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1'::cube AS bool; +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1,1,1'::cube AS bool; +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1,1),(2,2,2)]'::cube AS bool; +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1),(2,2)]'::cube AS bool; +SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(2,1,1),(2,2,2)]'::cube AS bool; + + +-- "contained in" (the left operand is the cube entirely enclosed by +-- the right operand): +-- +SELECT '0'::cube <@ '0'::cube AS bool; +SELECT '0,0,0'::cube <@ '0,0,0'::cube AS bool; +SELECT '0,0'::cube <@ '0,0,1'::cube AS bool; +SELECT '0,0,0'::cube <@ '0,0,1'::cube AS bool; +SELECT '1,0,0'::cube <@ '0,0,1'::cube AS bool; +SELECT '(1,0,0),(0,0,1)'::cube <@ '(1,0,0),(0,0,1)'::cube AS bool; +SELECT '(1,0,0),(0,0,1)'::cube <@ '(-1,-1,-1),(1,1,1)'::cube AS bool; +SELECT '(1,0,0),(0,0,1)'::cube <@ '(-1,-1,-1,-1),(1,1,1,1)'::cube AS bool; +SELECT '0'::cube <@ '(-1),(1)'::cube AS bool; +SELECT '1'::cube <@ '(-1),(1)'::cube AS bool; +SELECT '-1'::cube <@ '(-1),(1)'::cube AS bool; +SELECT '(-1),(1)'::cube <@ '(-1),(1)'::cube AS bool; +SELECT '(-1),(1)'::cube <@ '(-1,-1),(1,1)'::cube AS bool; +SELECT '(-2),(1)'::cube <@ '(-1),(1)'::cube AS bool; +SELECT '(-2),(1)'::cube <@ '(-1,-1),(1,1)'::cube AS bool; + + +-- "contains" (the left operand is the cube that entirely encloses the +-- right operand) +-- +SELECT '0'::cube @> '0'::cube AS bool; +SELECT '0,0,0'::cube @> '0,0,0'::cube AS bool; +SELECT '0,0,1'::cube @> '0,0'::cube AS bool; +SELECT '0,0,1'::cube @> '0,0,0'::cube AS bool; +SELECT '0,0,1'::cube @> '1,0,0'::cube AS bool; +SELECT '(1,0,0),(0,0,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; +SELECT '(-1,-1,-1),(1,1,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; +SELECT '(-1,-1,-1,-1),(1,1,1,1)'::cube @> '(1,0,0),(0,0,1)'::cube AS bool; +SELECT '(-1),(1)'::cube @> '0'::cube AS bool; +SELECT '(-1),(1)'::cube @> '1'::cube AS bool; +SELECT '(-1),(1)'::cube @> '-1'::cube AS bool; +SELECT '(-1),(1)'::cube @> '(-1),(1)'::cube AS bool; +SELECT '(-1,-1),(1,1)'::cube @> '(-1),(1)'::cube AS bool; +SELECT '(-1),(1)'::cube @> '(-2),(1)'::cube AS bool; +SELECT '(-1,-1),(1,1)'::cube @> '(-2),(1)'::cube AS bool; + +-- Test of distance function +-- +SELECT cube_distance('(0)'::cube,'(2,2,2,2)'::cube); +SELECT cube_distance('(0)'::cube,'(.3,.4)'::cube); +SELECT cube_distance('(2,3,4)'::cube,'(2,3,4)'::cube); +SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube); +SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube); + +-- Test of cube function (text to cube) +-- +SELECT cube('(1,1.2)'::text); +SELECT cube(NULL); + +-- Test of cube_dim function (dimensions stored in cube) +-- +SELECT cube_dim('(0)'::cube); +SELECT cube_dim('(0,0)'::cube); +SELECT cube_dim('(0,0,0)'::cube); +SELECT cube_dim('(42,42,42),(42,42,42)'::cube); +SELECT cube_dim('(4,8,15,16,23),(4,8,15,16,23)'::cube); + +-- Test of cube_ll_coord function (retrieves LL coordinate values) +-- +SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 1); +SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 2); +SELECT cube_ll_coord('(-1,1),(2,-2)'::cube, 3); +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 1); +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 2); +SELECT cube_ll_coord('(1,2),(1,2)'::cube, 3); +SELECT cube_ll_coord('(42,137)'::cube, 1); +SELECT cube_ll_coord('(42,137)'::cube, 2); +SELECT cube_ll_coord('(42,137)'::cube, 3); + +-- Test of cube_ur_coord function (retrieves UR coordinate values) +-- +SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 1); +SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 2); +SELECT cube_ur_coord('(-1,1),(2,-2)'::cube, 3); +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 1); +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 2); +SELECT cube_ur_coord('(1,2),(1,2)'::cube, 3); +SELECT cube_ur_coord('(42,137)'::cube, 1); +SELECT cube_ur_coord('(42,137)'::cube, 2); +SELECT cube_ur_coord('(42,137)'::cube, 3); + +-- Test of cube_is_point +-- +SELECT cube_is_point('(0)'::cube); +SELECT cube_is_point('(0,1,2)'::cube); +SELECT cube_is_point('(0,1,2),(0,1,2)'::cube); +SELECT cube_is_point('(0,1,2),(-1,1,2)'::cube); +SELECT cube_is_point('(0,1,2),(0,-1,2)'::cube); +SELECT cube_is_point('(0,1,2),(0,1,-2)'::cube); + +-- Test of cube_enlarge (enlarging and shrinking cubes) +-- +SELECT cube_enlarge('(0)'::cube, 0, 0); +SELECT cube_enlarge('(0)'::cube, 0, 1); +SELECT cube_enlarge('(0)'::cube, 0, 2); +SELECT cube_enlarge('(2),(-2)'::cube, 0, 4); +SELECT cube_enlarge('(0)'::cube, 1, 0); +SELECT cube_enlarge('(0)'::cube, 1, 1); +SELECT cube_enlarge('(0)'::cube, 1, 2); +SELECT cube_enlarge('(2),(-2)'::cube, 1, 4); +SELECT cube_enlarge('(0)'::cube, -1, 0); +SELECT cube_enlarge('(0)'::cube, -1, 1); +SELECT cube_enlarge('(0)'::cube, -1, 2); +SELECT cube_enlarge('(2),(-2)'::cube, -1, 4); +SELECT cube_enlarge('(0,0,0)'::cube, 1, 0); +SELECT cube_enlarge('(0,0,0)'::cube, 1, 2); +SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 1, 2); +SELECT cube_enlarge('(2,-2),(-3,7)'::cube, 3, 2); +SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -1, 2); +SELECT cube_enlarge('(2,-2),(-3,7)'::cube, -3, 2); +SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -23, 5); +SELECT cube_enlarge('(42,-23,-23),(42,23,23)'::cube, -24, 5); + +-- Test of cube_union (MBR for two cubes) +-- +SELECT cube_union('(1,2),(3,4)'::cube, '(5,6,7),(8,9,10)'::cube); +SELECT cube_union('(1,2)'::cube, '(4,2,0,0)'::cube); +SELECT cube_union('(1,2),(1,2)'::cube, '(4,2),(4,2)'::cube); +SELECT cube_union('(1,2),(1,2)'::cube, '(1,2),(1,2)'::cube); +SELECT cube_union('(1,2),(1,2)'::cube, '(1,2,0),(1,2,0)'::cube); + +-- Test of cube_inter +-- +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (16,15)'::cube); -- intersects +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,4), (6,5)'::cube); -- includes +SELECT cube_inter('(1,2),(10,11)'::cube, '(13,14), (16,15)'::cube); -- no intersection +SELECT cube_inter('(1,2),(10,11)'::cube, '(3,14), (16,15)'::cube); -- no intersection, but one dimension intersects +SELECT cube_inter('(1,2),(10,11)'::cube, '(10,11), (16,15)'::cube); -- point intersection +SELECT cube_inter('(1,2,3)'::cube, '(1,2,3)'::cube); -- point args +SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args + +-- Test of cube_size +-- +SELECT cube_size('(4,8),(15,16)'::cube); +SELECT cube_size('(42,137)'::cube); + +-- Test of distances (euclidean distance may not be bit-exact) +-- +SET extra_float_digits = 0; +SELECT cube_distance('(1,1)'::cube, '(4,5)'::cube); +SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e; +RESET extra_float_digits; +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); + +\copy test_cube from 'data/test_cube.data' + +CREATE INDEX test_cube_ix ON test_cube USING gist (c); +SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' ORDER BY c; + +-- Test sorting +SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c; + +-- Test index-only scans +SET enable_bitmapscan = false; +EXPLAIN (COSTS OFF) +SELECT c FROM test_cube WHERE c <@ '(3000,1000),(0,0)' ORDER BY c; +SELECT c FROM test_cube WHERE c <@ '(3000,1000),(0,0)' ORDER BY c; +RESET enable_bitmapscan; + +-- Test kNN +INSERT INTO test_cube VALUES ('(1,1)'), ('(100000)'), ('(0, 100000)'); -- Some corner cases +SET enable_seqscan = false; + +-- Test different metrics +SET extra_float_digits = 0; +SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; +RESET extra_float_digits; +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; + +-- Test sorting by coordinates +SELECT c~>1, c FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by left bound +SELECT c~>2, c FROM test_cube ORDER BY c~>2 LIMIT 15; -- ascending by right bound +SELECT c~>3, c FROM test_cube ORDER BY c~>3 LIMIT 15; -- ascending by lower bound +SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper bound +SELECT c~>(-1), c FROM test_cube ORDER BY c~>(-1) LIMIT 15; -- descending by left bound +SELECT c~>(-2), c FROM test_cube ORDER BY c~>(-2) LIMIT 15; -- descending by right bound +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 + +-- Same queries with sequential scan (should give the same results as above) +RESET enable_seqscan; +SET enable_indexscan = OFF; +SET extra_float_digits = 0; +SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5; +RESET extra_float_digits; +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~>1, c FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by left bound +SELECT c~>2, c FROM test_cube ORDER BY c~>2 LIMIT 15; -- ascending by right bound +SELECT c~>3, c FROM test_cube ORDER BY c~>3 LIMIT 15; -- ascending by lower bound +SELECT c~>4, c FROM test_cube ORDER BY c~>4 LIMIT 15; -- ascending by upper bound +SELECT c~>(-1), c FROM test_cube ORDER BY c~>(-1) LIMIT 15; -- descending by left bound +SELECT c~>(-2), c FROM test_cube ORDER BY c~>(-2) LIMIT 15; -- descending by right bound +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; diff --git a/contrib/cube/sql/cube_sci.sql b/contrib/cube/sql/cube_sci.sql new file mode 100644 index 0000000..35a5407 --- /dev/null +++ b/contrib/cube/sql/cube_sci.sql @@ -0,0 +1,22 @@ +--- +--- Testing cube output in scientific notation. This was put into separate +--- test, because has platform-depending output. +--- + +SELECT '1e27'::cube AS cube; +SELECT '-1e27'::cube AS cube; +SELECT '1.0e27'::cube AS cube; +SELECT '-1.0e27'::cube AS cube; +SELECT '1e+27'::cube AS cube; +SELECT '-1e+27'::cube AS cube; +SELECT '1.0e+27'::cube AS cube; +SELECT '-1.0e+27'::cube AS cube; +SELECT '1e-7'::cube AS cube; +SELECT '-1e-7'::cube AS cube; +SELECT '1.0e-7'::cube AS cube; +SELECT '-1.0e-7'::cube AS cube; +SELECT '1e-300'::cube AS cube; +SELECT '-1e-300'::cube AS cube; +SELECT '1234567890123456'::cube AS cube; +SELECT '+1234567890123456'::cube AS cube; +SELECT '-1234567890123456'::cube AS cube; |