summaryrefslogtreecommitdiffstats
path: root/contrib/cube
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/cube')
-rw-r--r--contrib/cube/.gitignore6
-rw-r--r--contrib/cube/CHANGES130
-rw-r--r--contrib/cube/Makefile40
-rw-r--r--contrib/cube/cube--1.0--1.1.sql59
-rw-r--r--contrib/cube/cube--1.1--1.2.sql75
-rw-r--r--contrib/cube/cube--1.2--1.3.sql12
-rw-r--r--contrib/cube/cube--1.2.sql378
-rw-r--r--contrib/cube/cube--1.3--1.4.sql58
-rw-r--r--contrib/cube/cube.c1852
-rw-r--r--contrib/cube/cube.control6
-rw-r--r--contrib/cube/cubedata.h69
-rw-r--r--contrib/cube/cubeparse.c1719
-rw-r--r--contrib/cube/cubeparse.y269
-rw-r--r--contrib/cube/cubescan.c2115
-rw-r--r--contrib/cube/cubescan.l121
-rw-r--r--contrib/cube/data/test_cube.data3100
-rw-r--r--contrib/cube/expected/cube.out1950
-rw-r--r--contrib/cube/expected/cube_sci.out106
-rw-r--r--contrib/cube/sql/cube.sql432
-rw-r--r--contrib/cube/sql/cube_sci.sql22
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;