From a3694b420f194ba26f3bf721f4a53fc0a43c2581 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 11 Dec 2000 20:40:33 +0000 Subject: [PATCH] Gene Selkov's SEG datatype (GiST example code) --- contrib/seg/Makefile | 83 + contrib/seg/README.seg | 326 ++++ contrib/seg/buffer.c | 79 + contrib/seg/buffer.h | 8 + contrib/seg/data/test_seg.data | 2577 ++++++++++++++++++++++++++++++++ contrib/seg/expected/seg.out | 1064 +++++++++++++ contrib/seg/seg-validate.pl | 42 + contrib/seg/seg.c | 1049 +++++++++++++ contrib/seg/seg.sql.in | 361 +++++ contrib/seg/segdata.h | 8 + contrib/seg/segparse.y | 183 +++ contrib/seg/segscan.l | 53 + contrib/seg/sort-segments.pl | 20 + contrib/seg/sql/seg.sql | 223 +++ 14 files changed, 6076 insertions(+) create mode 100644 contrib/seg/Makefile create mode 100644 contrib/seg/README.seg create mode 100644 contrib/seg/buffer.c create mode 100644 contrib/seg/buffer.h create mode 100644 contrib/seg/data/test_seg.data create mode 100644 contrib/seg/expected/seg.out create mode 100755 contrib/seg/seg-validate.pl create mode 100644 contrib/seg/seg.c create mode 100644 contrib/seg/seg.sql.in create mode 100644 contrib/seg/segdata.h create mode 100644 contrib/seg/segparse.y create mode 100644 contrib/seg/segscan.l create mode 100755 contrib/seg/sort-segments.pl create mode 100644 contrib/seg/sql/seg.sql diff --git a/contrib/seg/Makefile b/contrib/seg/Makefile new file mode 100644 index 0000000000..65b8eca4d1 --- /dev/null +++ b/contrib/seg/Makefile @@ -0,0 +1,83 @@ +# +# $Header: /cvsroot/pgsql/contrib/seg/Makefile,v 1.1 2000/12/11 20:40:33 tgl Exp $ +# + +subdir = contrib/seg +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global + +# override libdir to install shlib in contrib not main directory +libdir := $(libdir)/contrib + +# shared library parameters +NAME= seg +SO_MAJOR_VERSION= 1 +SO_MINOR_VERSION= 0 + +override CPPFLAGS += -I$(srcdir) + +OBJS= seg.o segparse.o segscan.o buffer.o + +all: all-lib $(NAME).sql + +# Shared library stuff +include $(top_srcdir)/src/Makefile.shlib + + +segparse.c segparse.h: segparse.y + $(YACC) -d $(YFLAGS) -p seg_yy $< + mv -f y.tab.c segparse.c + mv -f y.tab.h segparse.h + +segscan.c: segscan.l +ifdef FLEX + $(FLEX) $(FLEXFLAGS) -Pseg_yy -o'$@' $< +else + @$(missing) flex $< $@ +endif + +$(NAME).sql: $(NAME).sql.in + sed -e 's:MODULE_PATHNAME:$(libdir)/$(shlib):g' < $< > $@ + +.PHONY: submake +submake: + $(MAKE) -C $(top_builddir)/src/test/regress pg_regress + +# against installed postmaster +installcheck: submake + $(top_builddir)/src/test/regress/pg_regress seg + +# in-tree test doesn't work yet (no way to install my shared library) +#check: all submake +# $(top_builddir)/src/test/regress/pg_regress --temp-install \ +# --top-builddir=$(top_builddir) seg +check: + @echo "'make check' is not supported." + @echo "Do 'make install', then 'make installcheck' instead." + +install: all installdirs install-lib + $(INSTALL_DATA) $(srcdir)/README.$(NAME) $(docdir)/contrib + $(INSTALL_DATA) $(NAME).sql $(datadir)/contrib + +installdirs: + $(mkinstalldirs) $(docdir)/contrib $(datadir)/contrib $(libdir) + +uninstall: uninstall-lib + rm -f $(docdir)/contrib/README.$(NAME) $(datadir)/contrib/$(NAME).sql + +clean distclean maintainer-clean: clean-lib + rm -f segparse.c segparse.h segscan.c + rm -f y.tab.c y.tab.h $(OBJS) $(NAME).sql +# things created by various check targets + rm -rf results tmp_check log + rm -f regression.diffs regression.out regress.out run_check.out +ifeq ($(PORTNAME), win) + rm -f regress.def +endif + +depend dep: + $(CC) -MM $(CFLAGS) *.c >depend + +ifeq (depend,$(wildcard depend)) +include depend +endif diff --git a/contrib/seg/README.seg b/contrib/seg/README.seg new file mode 100644 index 0000000000..5c80ebcd5c --- /dev/null +++ b/contrib/seg/README.seg @@ -0,0 +1,326 @@ +This directory contains the code for the user-defined type, +SEG, representing laboratory measurements as floating point +intervals. + +RATIONALE +========= + +The geometry of measurements is usually more complex than that of a +point in a numeric continuum. A measurement is usually a segment of +that continuum with somewhat fuzzy limits. The measurements come out +as intervals because of uncertainty and randomness, as well as because +the value being measured may naturally be an interval indicating some +condition, such as the temperature range of stability of a protein. + +Using just common sense, it appears more convenient to store such data +as intervals, rather than pairs of numbers. In practice, it even turns +out more efficient in most applications. + +Further along the line of common sense, the fuzziness of the limits +suggests that the use of traditional numeric data types leads to a +certain loss of information. Consider this: your instrument reads +6.50, and you input this reading into the database. What do you get +when you fetch it? Watch: + +test=> select 6.50 as "pH"; + pH +--- +6.5 +(1 row) + +In the world of measurements, 6.50 is not the same as 6.5. It may +sometimes be critically different. The experimenters usually write +down (and publish) the digits they trust. 6.50 is actually a fuzzy +interval contained within a bigger and even fuzzier interval, 6.5, +with their center points being (probably) the only common feature they +share. We definitely do not want such different data items to appear the +same. + +Conclusion? It is nice to have a special data type that can record the +limits of an interval with arbitrarily variable precision. Variable in +a sense that each data element records its own precision. + +Check this out: + +test=> select '6.25 .. 6.50'::seg as "pH"; + pH +------------ +6.25 .. 6.50 +(1 row) + + +FILES +===== + +Makefile building instructions for the shared library + +README.seg the file you are now reading + +buffer.c global variables and buffer access utilities + shared between the parser (segparse.y) and the + scanner (segscan.l) + +buffer.h function prototypes for buffer.c + +seg.c the implementation of this data type in c + +seg.sql.in SQL code needed to register this type with postgres + (transformed to seg.sql by make) + +segdata.h the data structure used to store the segments + +segparse.y the grammar file for the parser (used by seg_in() in seg.c) + +segscan.l scanner rules (used by seg_yyparse() in segparse.y) + +seg-validate.pl a simple input validation script. It is probably a + little stricter than the type itself: for example, + it rejects '22 ' because of the trailing space. Use + as a filter to discard bad values from a single column; + redirect to /dev/null to see the offending input + +sort-segments.pl a script to sort the tables having a SEG type column + + +INSTALLATION +============ + +To install the type, run + + make + make install + +For this to work, make sure that: + +. the seg source directory is in the postgres contrib directory +. the user running "make install" has postgres administrative authority +. this user's environment defines the PGLIB and PGDATA variables and has + postgres binaries in the PATH. + +This only installs the type implementation and documentation. To make the +type available in any particular database, do + + psql -d databasename < seg.sql + +If you install the type in the template1 database, all subsequently created +databases will inherit it. + +To test the new type, after "make install" do + + make installcheck + +If it fails, examine the file regression.diffs to find out the reason (the +test code is a direct adaptation of the regression tests from the main +source tree). + + +SYNTAX +====== + +The external representation of an interval is formed using one or two +floating point numbers joined by the range operator ('..' or '...'). +Optional certainty indicators (<, > and ~) are ignored by the internal +logics, but are retained in the data. + +Grammar +------- + +rule 1 seg -> boundary PLUMIN deviation +rule 2 seg -> boundary RANGE boundary +rule 3 seg -> boundary RANGE +rule 4 seg -> RANGE boundary +rule 5 seg -> boundary +rule 6 boundary -> FLOAT +rule 7 boundary -> EXTENSION FLOAT +rule 8 deviation -> FLOAT + +Tokens +------ + +RANGE (\.\.)(\.)? +PLUMIN \'\+\-\' +integer [+-]?[0-9]+ +real [+-]?[0-9]+\.[0-9]+ +FLOAT ({integer}|{real})([eE]{integer})? +EXTENSION [<>~] + + +Examples of valid SEG representations: +-------------------------------------- + +Any number (rules 5,6) -- creates a zero-length segment (a point, + if you will) + +~5.0 (rules 5,7) -- creates a zero-length segment AND records + '~' in the data. This notation reads 'approximately 5.0', + but its meaning is not recognized by the code. It is ignored + until you get the value back. View it is a short-hand comment. + +<5.0 (rules 5,7) -- creates a point at 5.0; '<' is ignored but + is preserved as a comment + +>5.0 (rules 5,7) -- creates a point at 5.0; '>' is ignored but + is preserved as a comment + +5(+-)0.3 +5'+-'0.3 (rules 1,8) -- creates an interval '4.7..5.3'. As of this + writing (02/09/2000), this mechanism isn't completely accurate + in determining the number of significant digits for the + boundaries. For example, it adds an extra digit to the lower + boundary if the resulting interval includes a power of ten: + + template1=> select '10(+-)1'::seg as seg; + seg + --------- + 9.0 .. 11 -- should be: 9 .. 11 + + Also, the (+-) notation is not preserved: 'a(+-)b' will + always be returned as '(a-b) .. (a+b)'. The purpose of this + notation is to allow input from certain data sources without + conversion. + +50 .. (rule 3) -- everything that is greater than or equal to 50 + +.. 0 (rule 4) -- everything that is less than or equal to 0 + +1.5e-2 .. 2E-2 (rule 2) -- creates an interval (0.015 .. 0.02) + +1 ... 2 The same as 1...2, or 1 .. 2, or 1..2 (space is ignored). + Because of the widespread use of '...' in the data sources, + I decided to stick to is as a range operator. This, and + also the fact that the white space around the range operator + is ignored, creates a parsing conflict with numeric constants + starting with a decimal point. + + +Examples of invalid SEG input: +------------------------------ + +.1e7 should be: 0.1e7 +.1 .. .2 should be: 0.1 .. 0.2 +2.4 E4 should be: 2.4E4 + +The following, although it is not a syntax error, is disallowed to improve +the sanity of the data: + +5 .. 2 should be: 2 .. 5 + + +PRECISION +========= + +The segments are stored internally as pairs of 32-bit floating point +numbers. It means that the numbers with more than 7 significant digits +will be truncated. + +The numbers with less than or exactly 7 significant digits retain their +original precision. That is, if your query returns 0.00, you will be +sure that the trailing zeroes are not the artifacts of formatting: they +reflect the precision of the original data. The number of leading +zeroes does not affect precision: the value 0.0067 is considered to +have just 2 significant digits. + + +USAGE +===== + +The access method for SEG is a GiST (gist_seg_ops), which is a +generalization of R-tree. GiSTs allow the postgres implementation of +R-tree, originally encoded to support 2-D geometric types such as +boxes and polygons, to be used with any data type whose data domain +can be partitioned using the concepts of containment, intersection and +equality. In other words, everything that can intersect or contain +its own kind can be indexed with a GiST. That includes, among other +things, all geometric data types, regardless of their dimensionality +(see also contrib/cube). + +The operators supported by the GiST access method include: + + +[a, b] << [c, d] Is left of + + The left operand, [a, b], occurs entirely to the left of the + right operand, [c, d], on the axis (-inf, inf). It means, + [a, b] << [c, d] is true if b < c and false otherwise + +[a, b] >> [c, d] Is right of + + [a, b] is occurs entirely to the right of [c, d]. + [a, b] >> [c, d] is true if b > c and false otherwise + +[a, b] &< [c, d] Over left + + The segment [a, b] overlaps the segment [c, d] in such a way + that a <= c <= b and b <= d + +[a, b] &> [c, d] Over right + + The segment [a, b] overlaps the segment [c, d] in such a way + that a > c and b <= c <= d + +[a, b] = [c, d] Same as + + The segments [a, b] and [c, d] are identical, that is, a == b + and c == d + +[a, b] @ [c, d] Contains + + The segment [a, b] contains the segment [c, d], that is, + a <= c and b >= d + +[a, b] @ [c, d] Contained in + + The segment [a, b] is contained in [c, d], that is, + a >= c and b <= d + +Although the mnemonics of the following operators is questionable, I +preserved them to maintain visual consistency with other geometric +data types defined in Postgres. + +Other operators: + +[a, b] < [c, d] Less than +[a, b] > [c, d] Greater than + + These operators do not make a lot of sense for any practical + purpose but sorting. These operators first compare (a) to (c), + and if these are equal, compare (b) to (d). That accounts for + reasonably good sorting in most cases, which is useful if + you want to use ORDER BY with this type + +There are a few other potentially useful functions defined in seg.c +that vanished from the schema because I stopped using them. Some of +these were meant to support type casting. Let me know if I was wrong: +I will then add them back to the schema. I would also appreciate +other ideas that would enhance the type and make it more useful. + +For examples of usage, see sql/seg.sql + +NOTE: The performance of an R-tree index can largely depend on the +order of input values. It may be very helpful to sort the input table +on the SEG column (see the script sort-segments.pl for an example) + + +CREDITS +======= + +My thanks are primarily to Prof. Joe Hellerstein +(http://db.cs.berkeley.edu/~jmh/) for elucidating the gist of the GiST +(http://gist.cs.berkeley.edu/). I am also grateful to all postgres +developers, present and past, for enabling myself to create my own +world and live undisturbed in it. And I would like to acknowledge my +gratitude to Argonne Lab and to the U.S. Department of Energy for the +years of faithful support of my database research. + + +------------------------------------------------------------------------ +Gene Selkov, Jr. +Computational Scientist +Mathematics and Computer Science Division +Argonne National Laboratory +9700 S Cass Ave. +Building 221 +Argonne, IL 60439-4844 + +selkovjr@mcs.anl.gov + diff --git a/contrib/seg/buffer.c b/contrib/seg/buffer.c new file mode 100644 index 0000000000..f4dfc1edcd --- /dev/null +++ b/contrib/seg/buffer.c @@ -0,0 +1,79 @@ +/* This module defines the parse buffer and routines for setting/reading it */ + +#include "postgres.h" + +#include "utils/elog.h" + +static char * PARSE_BUFFER; +static char * PARSE_BUFFER_PTR; +static unsigned int PARSE_BUFFER_SIZE; +static unsigned int SCANNER_POS; + +void set_parse_buffer( char* s ); +void reset_parse_buffer( void ); +int read_parse_buffer( void ); +char * parse_buffer( void ); +char * parse_buffer_ptr( void ); +unsigned int parse_buffer_curr_char( void ); +unsigned int parse_buffer_size( void ); +unsigned int parse_buffer_pos( void ); + +extern void seg_flush_scanner_buffer(void); /* defined in segscan.l */ + +void set_parse_buffer( char* s ) +{ + PARSE_BUFFER = s; + PARSE_BUFFER_SIZE = strlen(s); + if ( PARSE_BUFFER_SIZE == 0 ) { + elog(ERROR, "seg_in: can't parse an empty string"); + } + PARSE_BUFFER_PTR = PARSE_BUFFER; + SCANNER_POS = 0; +} + +void reset_parse_buffer( void ) +{ + PARSE_BUFFER_PTR = PARSE_BUFFER; + SCANNER_POS = 0; + seg_flush_scanner_buffer(); +} + +int read_parse_buffer( void ) +{ + int c; + /* + c = *PARSE_BUFFER_PTR++; + SCANNER_POS++; + */ + c = PARSE_BUFFER[SCANNER_POS]; + if(SCANNER_POS < PARSE_BUFFER_SIZE) + SCANNER_POS++; + return c; +} + +char * parse_buffer( void ) +{ + return PARSE_BUFFER; +} + +unsigned int parse_buffer_curr_char( void ) +{ + return PARSE_BUFFER[SCANNER_POS]; +} + +char * parse_buffer_ptr( void ) +{ + return PARSE_BUFFER_PTR; +} + +unsigned int parse_buffer_pos( void ) +{ + return SCANNER_POS; +} + +unsigned int parse_buffer_size( void ) +{ + return PARSE_BUFFER_SIZE; +} + + diff --git a/contrib/seg/buffer.h b/contrib/seg/buffer.h new file mode 100644 index 0000000000..fd41a7b69b --- /dev/null +++ b/contrib/seg/buffer.h @@ -0,0 +1,8 @@ +extern void set_parse_buffer( char* s ); +extern void reset_parse_buffer( void ); +extern int read_parse_buffer( void ); +extern char * parse_buffer( void ); +extern char * parse_buffer_ptr( void ); +extern unsigned int parse_buffer_curr_char( void ); +extern unsigned int parse_buffer_pos( void ); +extern unsigned int parse_buffer_size( void ); diff --git a/contrib/seg/data/test_seg.data b/contrib/seg/data/test_seg.data new file mode 100644 index 0000000000..dba9ac9045 --- /dev/null +++ b/contrib/seg/data/test_seg.data @@ -0,0 +1,2577 @@ +...10.3 +...10.5 +...3.5 +...3.9 +...4.9 +...40 +...5.6 +...5.8 +...6.0 +...6.6 +...6.7 +...6.75 +...7.0 +...7.2 +...7.3 +...7.5 +...7.6 +...7.8 +...8.0 +...8.5 +...8.6 +...8.8 +...8.9 +...9.0 +...9.2 +...9.3 +...9.5 +...9.6 +...90 +...<3.0 +...<5.8 +...<7 +...<7.0 +...<8.0 +...<8.2 +...<8.9 +...>10 +...>7.2 +...>7.7 +...>8.0 +...>82 +...>9.0 +< 1.0...3.8 +< 1.5...4.1 +< 1.5...4.15 +< 10...>11.6 +< 2...>4 +< 2.0...3.4 +< 2.0...4.2 +< 2.0...>8.0 +< 2.5...4.7 +< 2.5...5.5 +< 2.5...>8.5 +< 3...>5 +< 3.0... +< 3.0...4.5 +< 3.0...6.0 +< 3.0...6.5 +< 3.0...9.0 +< 3.0...>10 +< 3.0...>11.0 +< 3.0...>8.0 +< 3.0...>9.0 +< 3.0...>9.5 +< 3.5 +< 3.5...4.3 +< 3.5...5.3 +< 3.5...5.6 +< 3.5...6.0 +< 3.5...8.4 +< 3.6...>6.5 +< 3.7...5.4 +< 4...9.5 +< 4...>5 +< 4...>6.0 +< 4.0... +< 4.0...10.5 +< 4.0...5.3 +< 4.0...5.75 +< 4.0...6.0 +< 4.0...7.3 +< 4.0...7.5 +< 4.0...7.7 +< 4.0...8.5 +< 4.0...>12 +< 4.0...>5.0 +< 4.0...>6.0 +< 4.0...>7.5 +< 4.0...>8.0 +< 4.0...>8.1 +< 4.0...>9.0 +< 4.2...5.2 +< 4.2...5.3 +< 4.2...5.4 +< 4.2...6.2 +< 4.3...>9.0 +< 4.4 +< 4.4...6.0 +< 4.4...<6.0 +< 4.5...6.3 +< 4.5...7.2 +< 4.5...>12 +< 4.5...>5.0 +< 4.5...>5.5 +< 4.5...>6 +< 4.5...>7.5 +< 4.5...>8 +< 4.5...>9.5 +< 4.7...>9.3 +< 4.8...>6.4 +< 5...7.5 +< 5...7.7 +< 5...>7 +< 5...>8 +< 5...>8.0 +< 5.0 +< 5.0...10 +< 5.0...6.3 +< 5.0...7.4 +< 5.0...7.7 +< 5.0...8.1 +< 5.0...8.3 +< 5.0...8.5 +< 5.0...8.8 +< 5.0...9.5 +< 5.0...<9.0 +< 5.0...>10 +< 5.0...>10.0 +< 5.0...>10.5 +< 5.0...>11 +< 5.0...>6.0 +< 5.0...>6.6 +< 5.0...>7.5 +< 5.0...>8.0 +< 5.0...>8.5 +< 5.0...>8.6 +< 5.0...>9.0 +< 5.2...7.3 +< 5.2...8.2 +< 5.2...8.5 +< 5.2...>5.8 +< 5.2...>7.6 +< 5.3 +< 5.3...6.5 +< 5.3...7.5 +< 5.3...7.8 +< 5.4...6.35 +< 5.5...10 +< 5.5...6.3 +< 5.5...7.0 +< 5.5...7.5 +< 5.5...8.4 +< 5.5...8.5 +< 5.5...>10 +< 5.5...>10.0 +< 5.5...>10.5 +< 5.5...>6.5 +< 5.5...>7 +< 5.5...>7.5 +< 5.5...>8 +< 5.5...>8.0 +< 5.5...>8.5 +< 5.5...>8.7 +< 5.5...>8.9 +< 5.5...>9.0 +< 5.6...6.75 +< 5.75...>9.0 +< 5.8...7.8 +< 5.8...>11 +< 5.8...>8.2 +< 5.9...>8.0 +< 6...>10.5 +< 6...>8 +< 6...>9.5 +< 6.0 +< 6.0...6.8 +< 6.0...7.15 +< 6.0...7.6 +< 6.0...7.7 +< 6.0...8.0 +< 6.0...8.2 +< 6.0...8.5 +< 6.0...9.0 +< 6.0...9.5 +< 6.0...>10 +< 6.0...>10.0 +< 6.0...>11 +< 6.0...>7.0 +< 6.0...>8.0 +< 6.0...>8.2 +< 6.0...>8.5 +< 6.0...>8.6 +< 6.0...>9.0 +< 6.0...>9.6 +< 6.3...9.5 +< 6.3...>6.7 +< 6.3...>7.8 +< 6.35...>7.7 +< 6.4...>8.0 +< 6.4...>8.7 +< 6.5...11 +< 6.5...7.25 +< 6.5...8.0 +< 6.5...8.2 +< 6.5...8.4 +< 6.5...8.5 +< 6.5...9.7 +< 6.5...>10.0 +< 6.5...>10.5 +< 6.5...>7.5 +< 6.5...>8.0 +< 6.5...>8.5 +< 6.5...>8.6 +< 6.5...>8.7 +< 6.5...>9.0 +< 6.5...>9.5 +< 6.6...>7.5 +< 6.6...>8.5 +< 6.8...7.8 +< 6.8...9.5 +< 6.8...>7.5 +< 6.8...>8.6 +< 6.8...>9.0 +< 6.9...9.0 +< 7...9.2 +< 7...>11 +< 7...>7.5 +< 7...>9.5 +< 7.0 +< 7.0...10 +< 7.0...10.5 +< 7.0...11.0 +< 7.0...8.2 +< 7.0...8.3 +< 7.0...8.4 +< 7.0...8.55 +< 7.0...8.7 +< 7.0...8.8 +< 7.0...9.0 +< 7.0...<8.0 +< 7.0...>10.5 +< 7.0...>11 +< 7.0...>11.0 +< 7.0...>7.0 +< 7.0...>7.3 +< 7.0...>7.4 +< 7.0...>7.5 +< 7.0...>7.75 +< 7.0...>7.8 +< 7.0...>8.0 +< 7.0...>8.2 +< 7.0...>8.5 +< 7.0...>8.6 +< 7.0...>8.9 +< 7.0...>9.0 +< 7.0...>9.5 +< 7.2...8.3 +< 7.2...>7.5 +< 7.2...>7.8 +< 7.2...>8.0 +< 7.2...>8.2 +< 7.2...>8.6 +< 7.2...>8.8 +< 7.4...>7.8 +< 7.4...>8.0 +< 7.4...>8.1 +< 7.4...>8.6 +< 7.4...>8.8 +< 7.5...9.0 +< 7.5...>10 +< 7.5...>8.0 +< 7.5...>8.5 +< 7.5...>8.7 +< 7.5...>9 +< 7.5...>9.0 +< 7.5...>9.5 +< 7.6...>7.8 +< 7.6...>8.0 +< 7.6...>8.5 +< 7.6...>8.6 +< 7.6...>8.9 +< 7.8...>9.0 +< 7.9...>8.3 +< 8.0 +< 8.0...>10.0 +< 8.0...>8.5 +< 8.0...>9.0 +< 8.0...>9.4 +< 8.0...>9.5 +< 8.2...9.8 +< 8.2...>8.6 +< 8.5...>10.5 +< 8.5...>11 +< 8.5...>9.5 +< 9...10.5 +<1.0...3.5 +<1.0...3.7 +<1.0...4.0 +<1.0...>13.0 +<1.0...>5.5 +<10.5...11.5 +<12.0...12.5 +<2...10 +<2...>4 +<2.0 +<2.0...11 +<2.0...3.5 +<2.0...5.7 +<2.0...6.0 +<2.0...6.8 +<2.0...9.7 +<2.0...>6.5 +<2.0...>9.0 +<2.3... +<2.3...>11.0 +<2.4...6.8 +<2.5...7.7 +<2.5...>8.0 +<2.8...>8.0 +<3.0...4.6 +<3.0...5.5 +<3.0...6.0 +<3.0...6.3 +<3.0...6.4 +<3.0...6.8 +<3.0...7.0 +<3.0...7.5 +<3.0...8.3 +<3.0...>10.5 +<3.0...>5.0 +<3.0...>7.0 +<3.0...>7.2 +<3.0...>8.5 +<3.0...>8.7 +<3.0...>9.0 +<3.5...6.0 +<3.5...8.0 +<3.5...<7.0 +<3.5...>10.0 +<3.55...5.3 +<3.7...4.9 +<3.7...5.0 +<4...6.5 +<4.0...10.0 +<4.0...10.5 +<4.0...6.1 +<4.0...6.3 +<4.0...6.5 +<4.0...7.7 +<4.0...8.2 +<4.0...<9.0 +<4.0...>10 +<4.0...>10.0 +<4.0...>10.5 +<4.0...>6.0 +<4.0...>8.0 +<4.0...>9.0 +<4.1...>8.0 +<4.3...7.6 +<4.5...6.3 +<4.5...6.5 +<4.5...>6.5 +<4.5...>9.5 +<4.8...>7.4 +<4.9...>9.5 +<5...>6 +<5...>6.0 +<5...>8 +<5.0...10.0 +<5.0...6.0 +<5.0...6.6 +<5.0...6.8 +<5.0...7.0 +<5.0...7.5 +<5.0...8.2 +<5.0...9.5 +<5.0...>11.0 +<5.0...>5.5 +<5.0...>7.0 +<5.0...>8.0 +<5.0...>9.0 +<5.2...7.5 +<5.2...>6.8 +<5.2...>8.0 +<5.3...10.2 +<5.3...>10.5 +<5.4...8.0 +<5.4...8.5 +<5.4...>8.2 +<5.4...>9.1 +<5.5...6.5 +<5.5...7.0 +<5.5...7.5 +<5.5...8.2 +<5.5...8.3 +<5.5...8.5 +<5.5...8.6 +<5.5...>10.0 +<5.5...>7.0 +<5.5...>7.5 +<5.5...>8.0 +<5.5...>8.5 +<5.5...>9.0 +<5.6...7.5 +<5.6...>6.4 +<5.6...>7.4 +<5.6...>8.0 +<5.6...>8.5 +<5.7...>7.1 +<5.8...7.4 +<5.8...>6.7 +<5.8...>6.8 +<5.8...>7.0 +<5.8...>7.8 +<5.8...>8.8 +<5.85...>9.5 +<6...>9 +<6.0...10.0 +<6.0...6.8 +<6.0...7.1 +<6.0...7.2 +<6.0...7.7 +<6.0...8.0 +<6.0...8.2 +<6.0...8.4 +<6.0...8.5 +<6.0...8.6 +<6.0...9.1 +<6.0...9.2 +<6.0...9.3 +<6.0...9.5 +<6.0...>10 +<6.0...>11.0 +<6.0...>7.0 +<6.0...>7.5 +<6.0...>7.6 +<6.0...>7.9 +<6.0...>8.0 +<6.0...>8.3 +<6.0...>8.5 +<6.0...>8.6 +<6.0...>9.0 +<6.0...>9.2 +<6.0...>9.5 +<6.1...8.4 +<6.1...>6.6 +<6.1...>8.1 +<6.2 +<6.2...6.9 +<6.2...8.3 +<6.2...>7.5 +<6.2...>8.5 +<6.2...>8.7 +<6.3...10.0 +<6.3...7.4 +<6.3...9.6 +<6.3...>7.0 +<6.3...>8.0 +<6.4...7.6 +<6.4...8.5 +<6.4...>8.5 +<6.4...>9.0 +<6.5...7.8 +<6.5...8.2 +<6.5...9.2 +<6.5...>7.0 +<6.5...>7.5 +<6.5...>8.0 +<6.5...>8.5 +<6.5...>8.7 +<6.5...>9.0 +<6.5...>9.5 +<6.6 +<6.6...8.0 +<6.8...8.0 +<6.8...8.2 +<6.8...>7.5 +<6.8...>8.5 +<6.8...>9.5 +<7...9 +<7...>10 +<7.0...7.5 +<7.0...9.0 +<7.0...9.0 +<7.0...9.4 +<7.0...9.5 +<7.0...9.5 +<7.0...>10 +<7.0...>10.0 +<7.0...>11.5 +<7.0...>7.5 +<7.0...>8.0 +<7.0...>8.3 +<7.0...>8.4 +<7.0...>8.5 +<7.0...>9.0 +<7.2...8.8 +<7.2...9.0 +<7.2...>8.2 +<7.2...>8.8 +<7.2...>9.5 +<7.3...>8.0 +<7.4...8.8 +<7.4...9.6 +<7.4...>8.5 +<7.4...>8.7 +<7.5...8.5 +<7.5...<9.0 +<7.5...>8.0 +<7.5...>8.5 +<7.5...>9.5 +<7.6...>8.4 +<7.6...>9.4 +<7.8...>10.2 +<7.8...>8.2 +<8.0 +<8.0...10.0 +<8.0...>8.5 +<8.0...>8.8 +<8.0...>9.0 +<8.2...>10.2 +<8.5...9.6 +<8.5...>9.0 +<8.5...>9.5 +<8.6...>10.6 +<9.1...10.3 +<9.2...>11.0 +<9.5...12 +<9.5...>12.2 +> 11.0 +> 3.0...<7.0 +> 4.0...<10.0 +> 4.0...<9.0 +> 4.5...<9.0 +> 5.0 +> 5.0...<10.0 +> 5.0...<11 +> 5.5... +> 5.6 +> 5.9...<9.5 +> 6.0...8.0 +> 6.0...<11.5 +> 6.0...<8.0 +> 6.0...>10.0 +> 6.2...<7.4 +> 7.0...<10 +> 7.0...>8.5 +> 7.0...>8.6 +> 7.0...>8.7 +> 7.15... +> 8.0 +> 8.7 +> 9.3 +> 9.5 +>10.5 +>120 +>2.3... +>3.0...<7.0 +>3.8...<8.0 +>4.0...<10 +>5.0...<7.0 +>5.0...>8.0 +>5.0...>9.2 +>5.25...6.5 +>5.5...>9.3 +>5.6...<8.2 +>6.0...>11.0 +>6.5...>8.0 +>6.6...<7.3 +>6.8...>8.5 +>6.9...>8.0 +>7.0 +>7.0...<9.0 +>7.0...<9.5 +>7.3... +>7.5...<10.5 +>8.0 +>8.4 +>8.5 +>9.0 +>9.4 +>9.5 +>95 +~10 +~23 +~5.0...>9.0 +~6.0 +~6.4...~8.5 +~6.8 +~7.0 +~7.5 +~8.0 +~8.0...~10.0 +1.0 +1.0...4.0 +1.0...5.0 +1.1 +1.1...3.6 +1.2...3.2 +1.2...3.5 +1.3...12.0 +1.4...2.0 +1.4...8.2 +1.5 +1.5...10.5 +1.5...4.2 +1.5...4.5 +1.6...3.8 +1.6...7.2 +1.7 +1.7...2.4 +1.7...3.2 +1.7...5.0 +1.7...5.7 +1.8 +1.8...3.8 +1.8...>9.0 +1.9...3.6 +2 +2.0 +2.0...10.0 +2.0...11.0 +2.0...11.5 +2.0...2.5 +2.0...3.2 +2.0...3.5 +2.0...4.0 +2.0...4.3 +2.0...4.4 +2.0...4.6 +2.0...4.75 +2.0...4.8 +2.0...5.0 +2.0...5.5 +2.0...6.5 +2.0...7.0 +2.0...7.5 +2.0...8.0 +2.0...9.0 +2.0...>10 +2.0...>4.0 +2.0...>5.5 +2.1 +2.1...11.8 +2.1...4.2 +2.2 +2.2...11.2 +2.2...4.1 +2.2...4.2 +2.2...5.9 +2.2...6.4 +2.2...6.8 +2.3...10.6 +2.3...4.1 +2.3...4.3 +2.3...4.5 +2.3...4.7 +2.3...6.0 +2.4 +2.4...11.3 +2.4...4.5 +2.4...5.6 +2.4...5.7 +2.4...6.3 +2.5 +2.5...11 +2.5...11.2 +2.5...11.5 +2.5...11.8 +2.5...3.0 +2.5...3.7 +2.5...4.1 +2.5...4.5 +2.5...4.6 +2.5...5.0 +2.5...5.1 +2.5...5.5 +2.5...6.0 +2.5...6.3 +2.5...7.0 +2.5...9.0 +2.5...>3.5 +2.5...>4.0 +2.52 +2.56 +2.6... +2.6...10.0 +2.6...9.3 +2.6...>4.0 +2.6...>9.4 +2.62 +2.7 +2.7...12.0 +2.7...3.7 +2.7...3.8 +2.7...4.5 +2.7...4.7 +2.7...6.0 +2.7...6.4 +2.7...7.0 +2.7...8.0 +2.75...5.25 +2.79 +2.8 +2.8...11.0 +2.8...3.4 +2.8...4.0 +2.8...7.0 +2.8...8.0 +2.8...9.0 +2.8...9.7 +2.9...3.7 +2.9...4.5 +2.9...5.0 +2.9...5.6 +2.9...6.1 +2.9...7.6 +2.9...9.0 +2.97 +3 +3...10.0 +3...10.5 +3...5.5 +3...58 +3...6 +3...8 +3.0 +3.0...10 +3.0...10.0 +3.0...10.5 +3.0...11.0 +3.0...3.5 +3.0...4.0 +3.0...4.5 +3.0...4.9 +3.0...5.0 +3.0...5.4 +3.0...5.6 +3.0...5.65 +3.0...6.0 +3.0...6.3 +3.0...6.5 +3.0...6.7 +3.0...6.9 +3.0...7.0 +3.0...7.2 +3.0...7.5 +3.0...8.0 +3.0...8.5 +3.0...8.7 +3.0...9.0 +3.0...9.7 +3.0...>10 +3.0...>10.0 +3.0...>8.0 +3.00...5.0 +3.1 +3.1...11.5 +3.1...5.2 +3.1...5.8 +3.1...6.8 +3.1...7.8 +3.15...7.25 +3.2 +3.2...10.0 +3.2...4.2 +3.2...4.6 +3.2...5.4 +3.2...5.8 +3.2...6.25 +3.2...6.8 +3.2...8.1 +3.2...>8.0 +3.2...>9.9 +3.22 +3.3 +3.3...4.7 +3.3...5.3 +3.3...5.5 +3.3...5.6 +3.3...6.0 +3.3...6.5 +3.3...6.7 +3.3...7.2 +3.3...7.4 +3.3...7.5 +3.3...7.8 +3.3...9.0 +3.4 +3.4...4.1 +3.4...4.7 +3.4...5.5 +3.4...6.2 +3.4...6.4 +3.4...8.2 +3.4...>8.0 +3.5 +3.5...10 +3.5...10.0 +3.5...10.5 +3.5...10.8 +3.5...11.0 +3.5...11.5 +3.5...12.2 +3.5...4.0 +3.5...4.4 +3.5...4.5 +3.5...5.0 +3.5...5.3 +3.5...5.5 +3.5...5.6 +3.5...6 +3.5...6.0 +3.5...6.3 +3.5...6.4 +3.5...6.5 +3.5...6.6 +3.5...6.7 +3.5...7.0 +3.5...7.2 +3.5...7.3 +3.5...7.5 +3.5...8.5 +3.5...8.6 +3.5...8.7 +3.5...9.0 +3.5...9.5 +3.5...>11.0 +3.5...>5.0 +3.5...>8.5 +3.5...>9.0 +3.6 +3.6...3.8 +3.6...4.55 +3.6...4.6 +3.6...4.8 +3.6...5.4 +3.6...5.5 +3.6...6 +3.6...6.0 +3.6...6.6 +3.6...6.8 +3.6...7.0 +3.6...7.7 +3.6...8.6 +3.6...8.7 +3.6...8.8 +3.7 +3.7...10.0 +3.7...10.6 +3.7...4.6 +3.7...5.3 +3.7...6.2 +3.7...6.3 +3.7...6.5 +3.7...6.7 +3.7...8.2 +3.7...8.3 +3.7...9.1 +3.7...>10 +3.7...>11 +3.75...5.7 +3.8 +3.8...10 +3.8...4.0 +3.8...4.5 +3.8...4.8 +3.8...5.5 +3.8...5.8 +3.8...5.9 +3.8...6.2 +3.8...7.7 +3.8...8.3 +3.8...8.7 +3.9 +3.9...5.5 +3.9...6.8 +3.9...7.8 +3.9...>7.5 +3.9...>8.5 +3.9...>9.0 +3.95 +4 +4...10 +4...11.0 +4...12 +4...5 +4...6.9 +4...7 +4...7.5 +4...8 +4...9 +4...>11 +4...>8 +4.0 +4.0... +4.0...10 +4.0...10.0 +4.0...10.4 +4.0...10.5 +4.0...11.0 +4.0...11.7 +4.0...12.5 +4.0...13.0 +4.0...4.4 +4.0...4.5 +4.0...4.8 +4.0...5.0 +4.0...5.1 +4.0...5.2 +4.0...5.5 +4.0...5.7 +4.0...5.75 +4.0...5.8 +4.0...6.0 +4.0...6.1 +4.0...6.2 +4.0...6.3 +4.0...6.5 +4.0...60 +4.0...7.0 +4.0...7.2 +4.0...7.3 +4.0...7.5 +4.0...7.7 +4.0...7.9 +4.0...8.0 +4.0...8.1 +4.0...8.2 +4.0...8.3 +4.0...8.5 +4.0...8.8 +4.0...9.0 +4.0...9.4 +4.0...>10 +4.0...>11 +4.0...>9.0 +4.1 +4.1...10.5 +4.1...5.6 +4.1...5.8 +4.1...6.0 +4.1...7.2 +4.1...8.0 +4.1...9.1 +4.15...5.25 +4.15...6.25 +4.15...6.5 +4.2 +4.2...11.0 +4.2...11.5 +4.2...11.7 +4.2...5.0 +4.2...5.3 +4.2...5.35 +4.2...5.4 +4.2...5.6 +4.2...5.7 +4.2...6.0 +4.2...6.3 +4.2...6.4 +4.2...6.7 +4.2...7.1 +4.2...7.2 +4.2...7.3 +4.2...8.0 +4.2...8.4 +4.2...9.5 +4.2...>7.0 +4.2...>7.3 +4.2...>9.0 +4.2...>9.5 +4.25 +4.25...5.00 +4.25...9.75 +4.3 +4.3...10.3 +4.3...5.3 +4.3...5.7 +4.3...5.8 +4.3...6.0 +4.3...6.3 +4.3...6.5 +4.3...6.8 +4.3...7.0 +4.3...7.2 +4.3...7.3 +4.3...7.5 +4.3...7.6 +4.3...8 +4.3...8.2 +4.3...8.5 +4.3...8.6 +4.3...>5.0 +4.3...>6.0 +4.3...>7.0 +4.3...>8.0 +4.35 +4.4 +4.4...10.7 +4.4...4.6 +4.4...4.8 +4.4...6.0 +4.4...6.2 +4.4...6.4 +4.4...6.6 +4.4...6.7 +4.4...7.0 +4.4...7.2 +4.4...7.5 +4.4...7.6 +4.4...8.5 +4.4...9.3 +4.5 +4.5...10 +4.5...10.0 +4.5...10.5 +4.5...11.0 +4.5...11.5 +4.5...115 +4.5...12.5 +4.5...4.8 +4.5...5.0 +4.5...5.2 +4.5...5.5 +4.5...5.7 +4.5...5.8 +4.5...6.0 +4.5...6.2 +4.5...6.4 +4.5...6.5 +4.5...6.8 +4.5...7 +4.5...7.0 +4.5...7.1 +4.5...7.3 +4.5...7.5 +4.5...7.6 +4.5...7.7 +4.5...7.8 +4.5...7.9 +4.5...8.0 +4.5...8.3 +4.5...8.5 +4.5...8.6 +4.5...8.7 +4.5...8.8 +4.5...8.9 +4.5...9.0 +4.5...9.3 +4.5...9.4 +4.5...9.5 +4.5...<12 +4.5...>10 +4.5...>12 +4.5...>6.0 +4.5...>7.0 +4.5...>7.5 +4.5...>8.0 +4.5...>8.5 +4.5...>9.0 +4.6 +4.6 +4.6...4.8 +4.6...5.0 +4.6...5.2 +4.6...6.3 +4.6...6.4 +4.6...6.5 +4.6...6.6 +4.6...7.0 +4.6...7.2 +4.6...7.4 +4.6...7.5 +4.6...8.2 +4.6...8.5 +4.6...8.6 +4.6...8.7 +4.6...<6.5 +4.6...>10 +4.6...>11 +4.6...>7.4 +4.6...>8.0 +4.6...~7.0 +4.7 +4.7...10.8 +4.7...11 +4.7...11.8 +4.7...5.6 +4.7...6.0 +4.7...6.2 +4.7...6.3 +4.7...6.6 +4.7...6.7 +4.7...7.0 +4.7...7.4 +4.7...7.5 +4.7...7.7 +4.7...7.8 +4.7...8.0 +4.7...8.3 +4.7...8.4 +4.7...8.5 +4.7...9.3 +4.7...9.5 +4.7...9.6 +4.7...9.7 +4.7...>10 +4.7...>10.0 +4.7...>10.5 +4.7...>6.5 +4.7...>8.0 +4.75 +4.8 +4.8... +4.8...10.3 +4.8...11.5 +4.8...11.6 +4.8...12.5 +4.8...5.2 +4.8...5.9 +4.8...6.0 +4.8...6.2 +4.8...6.3 +4.8...7.0 +4.8...7.3 +4.8...7.4 +4.8...7.5 +4.8...7.6 +4.8...7.7 +4.8...7.75 +4.8...8.0 +4.8...8.2 +4.8...8.4 +4.8...8.6 +4.8...9.0 +4.8...9.3 +4.8...9.7 +4.8...>10.0 +4.8...>8.0 +4.8...>9.0 +4.85 +4.9 +4.9... +4.9...6.5 +4.9...7.2 +4.9...7.8 +4.9...8.2 +4.9...8.3 +4.9...9.0 +4.9...9.5 +4.9...<6.0 +4.9...>12 +4.9...>7.5 +4.9...>9.5 +5 +5...10.0 +5...10.5 +5...11 +5...11.5 +5...12 +5...30 +5...6 +5...6.6 +5...7 +5...8 +5...8.5 +5...9 +5...9.5 +5.0 +5.0...10 +5.0...10.0 +5.0...10.2 +5.0...10.3 +5.0...10.5 +5.0...11 +5.0...11.0 +5.0...11.2 +5.0...11.4 +5.0...11.5 +5.0...11.6 +5.0...11.7 +5.0...12.0 +5.0...5.5 +5.0...5.7 +5.0...6.0 +5.0...6.1 +5.0...6.2 +5.0...6.4 +5.0...6.5 +5.0...6.6 +5.0...6.8 +5.0...6.9 +5.0...7.0 +5.0...7.2 +5.0...7.3 +5.0...7.4 +5.0...7.5 +5.0...7.6 +5.0...7.7 +5.0...7.8 +5.0...8.0 +5.0...8.2 +5.0...8.3 +5.0...8.4 +5.0...8.5 +5.0...8.6 +5.0...8.7 +5.0...9.0 +5.0...9.0 +5.0...9.2 +5.0...9.5 +5.0...>10 +5.0...>10.0 +5.0...>11 +5.0...>12 +5.0...>12.0 +5.0...>7.0 +5.0...>8.0 +5.0...>8.4 +5.0...>8.5 +5.0...>9.0 +5.02...6.74 +5.1 +5.1...5.3 +5.1...5.4 +5.1...6.2 +5.1...6.3 +5.1...6.4 +5.1...6.6 +5.1...6.8 +5.1...7.0 +5.1...7.2 +5.1...7.3 +5.1...7.8 +5.1...8.0 +5.1...8.3 +5.1...8.7 +5.1...>7.0 +5.15 +5.2 +5.2...10.0 +5.2...10.8 +5.2...11.5 +5.2...5.3 +5.2...5.5 +5.2...5.7 +5.2...6.0 +5.2...6.2 +5.2...6.4 +5.2...6.7 +5.2...6.8 +5.2...6.9 +5.2...7.0 +5.2...7.3 +5.2...7.4 +5.2...7.5 +5.2...7.6 +5.2...7.7 +5.2...7.9 +5.2...8.0 +5.2...8.2 +5.2...8.4 +5.2...8.5 +5.2...8.7 +5.2...8.8 +5.2...9.0 +5.2...9.5 +5.2...9.6 +5.2...9.7 +5.2...9.9 +5.2...>10.0 +5.2...>11 +5.2...>12 +5.2...>6.5 +5.2...>7.0 +5.2...>7.5 +5.2...>8 +5.2...>8.0 +5.25...7.5 +5.25...8.5 +5.25...>12 +5.3 +5.3... +5.3...10.0 +5.3...10.1 +5.3...10.2 +5.3...10.5 +5.3...10.6 +5.3...11.5 +5.3...13 +5.3...5.5 +5.3...5.8 +5.3...7.0 +5.3...7.2 +5.3...7.4 +5.3...7.5 +5.3...7.6 +5.3...7.8 +5.3...8.0 +5.3...8.2 +5.3...8.3 +5.3...8.6 +5.3...8.7 +5.3...8.8 +5.3...8.9 +5.3...9.0 +5.3...9.3 +5.3...9.5 +5.3...9.7 +5.3...9.9 +5.3...>7.8 +5.3...>9.0 +5.3...>90 +5.35 +5.4 +5.4... +5.4...10 +5.4...10.5 +5.4...5.8 +5.4...6.8 +5.4...7.0 +5.4...7.1 +5.4...7.2 +5.4...7.3 +5.4...7.7 +5.4...7.8 +5.4...8.2 +5.4...8.5 +5.4...9.4 +5.4...>10.0 +5.4...>11.0 +5.4...>9.0 +5.45 +5.5 +5.5... +5.5...10.0 +5.5...10.2 +5.5...10.5 +5.5...11 +5.5...11.5 +5.5...11.7 +5.5...12 +5.5...12.5 +5.5...13.5 +5.5...5.6 +5.5...5.7 +5.5...5.8 +5.5...6 +5.5...6.0 +5.5...6.2 +5.5...6.3 +5.5...6.5 +5.5...6.7 +5.5...6.8 +5.5...7.0 +5.5...7.1 +5.5...7.2 +5.5...7.3 +5.5...7.4 +5.5...7.5 +5.5...7.6 +5.5...7.7 +5.5...7.9 +5.5...8.0 +5.5...8.1 +5.5...8.2 +5.5...8.5 +5.5...8.6 +5.5...8.7 +5.5...9.0 +5.5...9.1 +5.5...9.3 +5.5...9.5 +5.5...9.7 +5.5...<6.8 +5.5...>10 +5.5...>10.0 +5.5...>11 +5.5...>11.0 +5.5...>12 +5.5...>7.0 +5.5...>8.0 +5.5...>9.0 +5.5...>9.5 +5.55 +5.55...7.8 +5.56 +5.6 +5.6...10 +5.6...10.1 +5.6...6.0 +5.6...6.2 +5.6...6.4 +5.6...6.6 +5.6...7.0 +5.6...7.1 +5.6...7.2 +5.6...7.3 +5.6...7.4 +5.6...7.5 +5.6...7.6 +5.6...7.7 +5.6...8.0 +5.6...8.3 +5.6...8.4 +5.6...8.5 +5.6...8.75 +5.6...8.8 +5.6...9 +5.6...9.0 +5.6...9.4 +5.6...9.5 +5.6...9.6 +5.6...>11 +5.6...>7.0 +5.6...>7.5 +5.6...>8.0 +5.6...>9.0 +5.65 +5.7 +5.7... +5.7...10 +5.7...10.0 +5.7...11 +5.7...6.0 +5.7...6.2 +5.7...6.3 +5.7...6.5 +5.7...6.8 +5.7...7.0 +5.7...7.2 +5.7...7.3 +5.7...7.5 +5.7...7.6 +5.7...7.65 +5.7...7.7 +5.7...7.8 +5.7...7.9 +5.7...8.0 +5.7...8.4 +5.7...8.5 +5.7...8.7 +5.7...8.9 +5.7...9.0 +5.7...9.2 +5.7...9.4 +5.7...9.7 +5.7...>10.0 +5.7...>11 +5.7...>6.6 +5.7...>7.2 +5.7...>8.5 +5.7...>9.0 +5.73 +5.75 +5.75...7.3 +5.8 +5.8...10.0 +5.8...11 +5.8...6.0 +5.8...6.2 +5.8...6.5 +5.8...6.7 +5.8...6.8 +5.8...6.9 +5.8...7.0 +5.8...7.2 +5.8...7.3 +5.8...7.4 +5.8...7.5 +5.8...7.6 +5.8...7.7 +5.8...7.8 +5.8...8.0 +5.8...8.1 +5.8...8.2 +5.8...8.3 +5.8...8.4 +5.8...8.5 +5.8...8.6 +5.8...8.8 +5.8...9.0 +5.8...9.2 +5.8...9.3 +5.8...9.8 +5.8...>10.5 +5.8...>11 +5.8...>6.7 +5.8...>6.8 +5.8...>8.0 +5.8...>9.0 +5.85 +5.87 +5.9 +5.9... +5.9...10.2 +5.9...6.0 +5.9...6.5 +5.9...7.3 +5.9...7.5 +5.9...7.7 +5.9...8.0 +5.9...8.2 +5.9...8.3 +5.9...8.4 +5.9...8.5 +5.9...8.7 +5.9...9.0 +5.9...>7.0 +5.9...>8.5 +5.92 +5.95...8.0 +6 +6...10 +6...11 +6...11.5 +6...6.5 +6...8 +6...8.0 +6...8.5 +6...9 +6...9.2 +6...9.3 +6...>10 +6...>12 +6...>7.2 +6...>8 +6.0 +6.0 +6.0...10 +6.0...10.0 +6.0...10.2 +6.0...10.3 +6.0...10.4 +6.0...10.5 +6.0...11 +6.0...11.0 +6.0...11.5 +6.0...13 +6.0...6.2 +6.0...6.3 +6.0...6.4 +6.0...6.5 +6.0...6.6 +6.0...6.7 +6.0...6.8 +6.0...7.0 +6.0...7.2 +6.0...7.3 +6.0...7.4 +6.0...7.5 +6.0...7.6 +6.0...7.7 +6.0...7.8 +6.0...8.0 +6.0...8.1 +6.0...8.2 +6.0...8.3 +6.0...8.4 +6.0...8.5 +6.0...8.5 +6.0...8.6 +6.0...8.7 +6.0...8.9 +6.0...9.0 +6.0...9.1 +6.0...9.2 +6.0...9.3 +6.0...9.4 +6.0...9.5 +6.0...9.7 +6.0...9.8 +6.0...9.9 +6.0...>10.0 +6.0...>10.5 +6.0...>11 +6.0...>7.0 +6.0...>7.5 +6.0...>8.0 +6.0...>8.2 +6.0...>8.5 +6.0...>8.7 +6.0...>9.0 +6.0...>9.5 +6.01 +6.1 +6.1... +6.1...10 +6.1...10.8 +6.1...6.2 +6.1...6.6 +6.1...6.8 +6.1...6.9 +6.1...7.0 +6.1...7.2 +6.1...7.5 +6.1...7.6 +6.1...7.7 +6.1...7.8 +6.1...7.9 +6.1...8.0 +6.1...8.2 +6.1...8.5 +6.1...8.7 +6.1...8.9 +6.1...9.0 +6.1...9.3 +6.1...9.4 +6.1...>12 +6.1...>8.0 +6.1...>8.2 +6.1...>8.5 +6.1...>9.0 +6.1...>9.5 +6.15 +6.18 +6.2 +6.2...10 +6.2...10.0 +6.2...10.5 +6.2...11 +6.2...6.4 +6.2...6.5 +6.2...6.8 +6.2...6.9 +6.2...7.0 +6.2...7.2 +6.2...7.4 +6.2...7.5 +6.2...7.6 +6.2...7.7 +6.2...7.8 +6.2...8.0 +6.2...8.1 +6.2...8.2 +6.2...8.3 +6.2...8.4 +6.2...8.5 +6.2...8.6 +6.2...8.7 +6.2...8.8 +6.2...9.0 +6.2...9.1 +6.2...9.2 +6.2...9.5 +6.2...9.7 +6.2...9.8 +6.2...>10.5 +6.2...>11.5 +6.2...>7.1 +6.2...>7.8 +6.2...>8.0 +6.2...>9.0 +6.2...>9.5 +6.23...8.07 +6.24 +6.25 +6.25...7.5 +6.25...>9.0 +6.3 +6.3... +6.3...10.0 +6.3...10.2 +6.3...10.4 +6.3...10.5 +6.3...6.4 +6.3...6.5 +6.3...6.6 +6.3...6.7 +6.3...6.8 +6.3...7.3 +6.3...7.5 +6.3...7.7 +6.3...7.8 +6.3...7.9 +6.3...8.0 +6.3...8.2 +6.3...8.3 +6.3...8.5 +6.3...8.6 +6.3...8.7 +6.3...8.9 +6.3...9.0 +6.3...9.1 +6.3...9.2 +6.3...9.3 +6.3...9.4 +6.3...9.5 +6.3...9.7 +6.3...9.8 +6.3...>10.0 +6.3...>11 +6.3...>7.5 +6.3...>7.8 +6.3...>8.0 +6.3...>8.1 +6.3...>8.3 +6.3...>8.5 +6.3...>9.0 +6.3...>9.2 +6.35 +6.4 +6.4...7.7 +6.4...10 +6.4...10.8 +6.4...6.7 +6.4...6.8 +6.4...7.0 +6.4...7.2 +6.4...7.4 +6.4...7.5 +6.4...7.6 +6.4...7.7 +6.4...7.8 +6.4...8.0 +6.4...8.1 +6.4...8.2 +6.4...8.3 +6.4...8.4 +6.4...8.6 +6.4...8.7 +6.4...8.8 +6.4...9.0 +6.4...9.3 +6.4...>10 +6.4...>11.0 +6.4...>7.8 +6.4...>8.0 +6.4...>8.5 +6.4...>8.6 +6.4...>9.0 +6.4...>9.1 +6.4...>9.2 +6.4...>9.5 +6.42 +6.5 +6.5 +6.5... +6.5...10 +6.5...10.0 +6.5...10.2 +6.5...10.3 +6.5...10.5 +6.5...11 +6.5...11.0 +6.5...11.5 +6.5...12.0 +6.5...6.7 +6.5...6.75 +6.5...6.8 +6.5...6.9 +6.5...7.0 +6.5...7.1 +6.5...7.3 +6.5...7.4 +6.5...7.5 +6.5...7.6 +6.5...7.7 +6.5...7.8 +6.5...7.9 +6.5...8.0 +6.5...8.1 +6.5...8.2 +6.5...8.25 +6.5...8.3 +6.5...8.4 +6.5...8.5 +6.5...8.6 +6.5...8.7 +6.5...8.8 +6.5...8.9 +6.5...9 +6.5...9.0 +6.5...9.2 +6.5...9.3 +6.5...9.5 +6.5...9.7 +6.5...9.8 +6.5...>10 +6.5...>10.0 +6.5...>11 +6.5...>11.0 +6.5...>12.0 +6.5...>7.0 +6.5...>7.9 +6.5...>8.0 +6.5...>8.3 +6.5...>8.5 +6.5...>8.7 +6.5...>8.8 +6.5...>9.0 +6.5...>9.5 +6.51 +6.55 +6.6 +6.6... +6.6...7.0 +6.6...7.1 +6.6...7.3 +6.6...7.4 +6.6...7.5 +6.6...7.9 +6.6...8.3 +6.6...8.4 +6.6...8.5 +6.6...8.6 +6.6...8.7 +6.6...8.8 +6.6...8.9 +6.6...9.0 +6.6...9.4 +6.6...9.7 +6.6...9.8 +6.6...>10.0 +6.6...>10.3 +6.6...>11 +6.6...>9.0 +6.6...>9.5 +6.65...8.6 +6.67 +6.7 +6.7... +6.7...10.2 +6.7...11.5 +6.7...6.8 +6.7...6.9 +6.7...7.0 +6.7...7.3 +6.7...7.4 +6.7...7.5 +6.7...7.6 +6.7...7.8 +6.7...8.0 +6.7...8.1 +6.7...8.2 +6.7...8.3 +6.7...8.5 +6.7...8.6 +6.7...8.7 +6.7...8.8 +6.7...8.9 +6.7...9.0 +6.7...9.1 +6.7...9.2 +6.7...9.5 +6.7...9.7 +6.7...9.8 +6.7...>10 +6.7...>7.0 +6.7...>7.5 +6.7...>8.0 +6.7...>8.5 +6.7...>8.6 +6.7...>9 +6.7...>9.0 +6.7...>9.3 +6.74...8.0 +6.75 +6.75... +6.75...9.5 +6.75...>9 +6.75...>9.0 +6.75...>9.5 +6.76...8.10 +6.8 +6.8... +6.8...10 +6.8...10.0 +6.8...10.5 +6.8...6.9 +6.8...7.0 +6.8...7.1 +6.8...7.2 +6.8...7.3 +6.8...7.5 +6.8...7.6 +6.8...7.7 +6.8...7.8 +6.8...7.9 +6.8...8.0 +6.8...8.2 +6.8...8.25 +6.8...8.3 +6.8...8.5 +6.8...8.6 +6.8...8.7 +6.8...8.8 +6.8...8.9 +6.8...9.0 +6.8...9.1 +6.8...9.3 +6.8...9.4 +6.8...9.5 +6.8...9.6 +6.8...9.9 +6.8...>10.0 +6.8...>7.9 +6.8...>8.0 +6.8...>8.1 +6.8...>8.5 +6.8...>9.0 +6.8...>9.1 +6.80...>8.5 +6.81...7.53 +6.85 +6.86 +6.88 +6.9 +6.9... +6.9...10.4 +6.9...12.2 +6.9...7.0 +6.9...7.1 +6.9...7.3 +6.9...7.6 +6.9...7.9 +6.9...8.0 +6.9...8.2 +6.9...8.4 +6.9...8.5 +6.9...8.6 +6.9...8.7 +6.9...8.8 +6.9...9.0 +6.9...9.1 +6.9...9.2 +6.9...9.5 +6.9...9.7 +6.9...>7.1 +6.9...>8 +6.9...>8.5 +6.9...>9 +6.9...>9.0 +6.9...>9.3 +6.9...>9.5 +6.9...>90 +7 +7...10 +7...10.5 +7...11 +7...7.5 +7...8 +7...8.5 +7...8.8 +7...9 +7...>10 +7...>10.5 +7...>9.5 +7.0 +7.0 +7.0... +7.0...10 +7.0...10.0 +7.0...10.2 +7.0...10.3 +7.0...10.5 +7.0...10.7 +7.0...11 +7.0...11.0 +7.0...11.5 +7.0...7.2 +7.0...7.2 +7.0...7.3 +7.0...7.4 +7.0...7.5 +7.0...7.6 +7.0...7.8 +7.0...7.9 +7.0...8.0 +7.0...8.1 +7.0...8.2 +7.0...8.3 +7.0...8.4 +7.0...8.5 +7.0...8.6 +7.0...8.67 +7.0...8.7 +7.0...8.8 +7.0...8.9 +7.0...9.0 +7.0...9.1 +7.0...9.2 +7.0...9.3 +7.0...9.4 +7.0...9.5 +7.0...9.7 +7.0...9.75 +7.0...9.8 +7.0...9.9 +7.0...<8.0 +7.0...>10 +7.0...>10.0 +7.0...>10.5 +7.0...>11 +7.0...>11.5 +7.0...>7.8 +7.0...>8.5 +7.0...>8.7 +7.0...>9 +7.0...>9.0 +7.0...>9.5 +7.00 +7.01 +7.03 +7.05 +7.07 +7.1 +7.1...10.1 +7.1...10.3 +7.1...7.9 +7.1...8.1 +7.1...8.2 +7.1...8.3 +7.1...8.4 +7.1...8.6 +7.1...8.7 +7.1...8.9 +7.1...9.0 +7.1...9.2 +7.1...9.3 +7.1...9.4 +7.1...9.8 +7.1...>8.3 +7.1...>8.5 +7.1...>9.0 +7.1...>9.5 +7.10 +7.15 +7.15...8.3 +7.2 +7.2...10.0 +7.2...10.2 +7.2...10.5 +7.2...13.5 +7.2...7.3 +7.2...7.4 +7.2...7.5 +7.2...7.6 +7.2...7.8 +7.2...8.0 +7.2...8.2 +7.2...8.3 +7.2...8.6 +7.2...8.7 +7.2...8.8 +7.2...8.9 +7.2...9.0 +7.2...9.1 +7.2...9.2 +7.2...9.3 +7.2...9.5 +7.2...9.6 +7.2...9.7 +7.2...9.8 +7.2...>10 +7.2...>10.0 +7.2...>11 +7.2...>8.0 +7.2...>8.5 +7.2...>8.7 +7.2...>9.0 +7.2...>9.1 +7.2...>9.2 +7.2...>9.5 +7.24 +7.25 +7.25...7.75 +7.25...8.1 +7.25...8.25 +7.25...8.4 +7.25...8.6 +7.25...8.7 +7.25...9.25 +7.25...>10.0 +7.25...>8.0 +7.25...>8.25 +7.25...>9.0 +7.26 +7.3 +7.3... +7.3...10.2 +7.3...10.5 +7.3...11 +7.3...7.5 +7.3...7.6 +7.3...7.8 +7.3...7.9 +7.3...8.0 +7.3...8.2 +7.3...8.3 +7.3...8.4 +7.3...8.5 +7.3...8.6 +7.3...8.8 +7.3...8.9 +7.3...9.0 +7.3...9.15 +7.3...9.2 +7.3...9.4 +7.3...9.5 +7.3...9.8 +7.3...9.9 +7.3...>10 +7.3...>10.0 +7.3...>10.5 +7.3...>7.8 +7.3...>8.0 +7.3...>8.3 +7.3...>9.0 +7.3...>9.2 +7.3...>9.3 +7.3...>9.5 +7.3...>9.75 +7.3...>90 +7.32 +7.35 +7.4 +7.4... +7.4...10 +7.4...10.0 +7.4...12.1 +7.4...7.6 +7.4...7.8 +7.4...8.0 +7.4...8.2 +7.4...8.3 +7.4...8.4 +7.4...8.5 +7.4...8.6 +7.4...8.7 +7.4...8.8 +7.4...9.0 +7.4...9.2 +7.4...9.3 +7.4...9.6 +7.4...9.7 +7.4...9.8 +7.4...>10.0 +7.4...>8 +7.4...>8.5 +7.4...>8.6 +7.4...>8.7 +7.4...>9.0 +7.45 +7.5 +7.5 +7.5... +7.5...10 +7.5...10.0 +7.5...10.1 +7.5...10.2 +7.5...10.3 +7.5...10.5 +7.5...10.8 +7.5...11 +7.5...11.0 +7.5...11.5 +7.5...12.0 +7.5...7.6 +7.5...7.8 +7.5...8 +7.5...8.0 +7.5...8.1 +7.5...8.2 +7.5...8.4 +7.5...8.5 +7.5...8.6 +7.5...8.7 +7.5...9.0 +7.5...9.1 +7.5...9.2 +7.5...9.3 +7.5...9.4 +7.5...9.5 +7.5...9.6 +7.5...9.7 +7.5...9.8 +7.5...>10 +7.5...>10.0 +7.5...>10.5 +7.5...>11.0 +7.5...>8.3 +7.5...>8.5 +7.5...>8.7 +7.5...>8.75 +7.5...>9 +7.5...>9.0 +7.5...>9.2 +7.5...>9.5 +7.54 +7.55 +7.6 +7.6 +7.6...10.3 +7.6...10.5 +7.6...7.8 +7.6...7.9 +7.6...8.0 +7.6...8.2 +7.6...8.3 +7.6...8.4 +7.6...8.5 +7.6...8.6 +7.6...8.8 +7.6...9.0 +7.6...9.2 +7.6...9.3 +7.6...9.4 +7.6...9.5 +7.6...9.7 +7.6...>10.0 +7.6...>10.3 +7.6...>10.5 +7.6...>11 +7.6...>8.25 +7.6...>8.8 +7.6...>9.0 +7.6...>9.5 +7.65 +7.7... +7.7...10 +7.7...10.0 +7.7...10.3 +7.7...10.5 +7.7...11.0 +7.7...11.5 +7.7...7.8 +7.7...8.0 +7.7...8.3 +7.7...8.5 +7.7...8.7 +7.7...9.0 +7.7...9.25 +7.7...9.4 +7.7...9.5 +7.7...9.8 +7.7...>10.5 +7.7...>8.5 +7.7...>8.6 +7.7...>9.0 +7.7...>9.5 +7.72...8.7 +7.75 +7.75... +7.75...8.1 +7.78 +7.8 +7.8...10.2 +7.8...7.9 +7.8...8.0 +7.8...8.1 +7.8...8.2 +7.8...8.4 +7.8...8.5 +7.8...8.7 +7.8...8.8 +7.8...8.9 +7.8...9.0 +7.8...9.2 +7.8...9.3 +7.8...9.4 +7.8...9.6 +7.8...<9.8 +7.8...>10.0 +7.8...>8.8 +7.8...>8.9 +7.8...>9.0 +7.8...>9.1 +7.8...>9.4 +7.80 +7.85 +7.9 +7.9...10.9 +7.9...8.1 +7.9...8.2 +7.9...8.3 +7.9...8.5 +7.9...8.6 +7.9...8.9 +7.9...9.0 +7.9...9.3 +7.96 +8 +8...10 +8...10.2 +8...10.5 +8...11.0 +8...8.5 +8...9 +8...>10 +8...>11 +8.0 +8.0...10 +8.0...10.0 +8.0...10.2 +8.0...10.3 +8.0...10.5 +8.0...10.8 +8.0...11.0 +8.0...11.2 +8.0...11.7 +8.0...12.0 +8.0...8.5 +8.0...8.12 +8.0...8.2 +8.0...8.4 +8.0...8.5 +8.0...8.6 +8.0...8.7 +8.0...8.8 +8.0...8.9 +8.0...9.0 +8.0...9.2 +8.0...9.4 +8.0...9.5 +8.0...9.7 +8.0...>10 +8.0...>10.0 +8.0...>10.5 +8.0...>11 +8.0...>13.0 +8.0...>8.75 +8.0...>9.0 +8.0...>9.2 +8.0...>9.5 +8.1 +8.1...10.5 +8.1...10.9 +8.1...8.2 +8.1...8.3 +8.1...8.4 +8.1...8.6 +8.1...8.7 +8.1...8.75 +8.1...8.9 +8.1...9.1 +8.1...9.9 +8.1...>9.5 +8.13 +8.15 +8.2 +8.2... +8.2...10.2 +8.2...10.4 +8.2...8.4 +8.2...8.5 +8.2...8.8 +8.2...8.9 +8.2...9.0 +8.2...9.6 +8.2...9.8 +8.2...>10 +8.2...>10.5 +8.2...>11 +8.2...>11.0 +8.2...>8.8 +8.2...>9.3 +8.20 +8.25 +8.25...10.2 +8.27 +8.27...10 +8.28 +8.3 +8.3... +8.3...10.2 +8.3...10.3 +8.3...10.8 +8.3...8.4 +8.3...8.5 +8.3...8.6 +8.3...8.8 +8.3...9.6 +8.3...9.9 +8.3...>9.5 +8.3...>9.8 +8.35 +8.4 +8.4...10.1 +8.4...8.5 +8.4...8.6 +8.4...8.7 +8.4...8.8 +8.4...8.9 +8.4...9.0 +8.4...9.2 +8.4...9.5 +8.4...<9.8 +8.4...>10.0 +8.4...>10.5 +8.4...>9.8 +8.48 +8.5 +8.5... +8.5...10.0 +8.5...10.3 +8.5...10.5 +8.5...10.7 +8.5...10.8 +8.5...11 +8.5...11.0 +8.5...12.5 +8.5...8.6 +8.5...8.8 +8.5...9.0 +8.5...9.1 +8.5...9.2 +8.5...9.3 +8.5...9.4 +8.5...9.5 +8.5...9.9 +8.5...>10 +8.5...>11 +8.5...>11.5 +8.5...>9.5 +8.6 +8.6...10.2 +8.6...10.3 +8.6...11 +8.6...8.7 +8.6...8.8 +8.6...8.9 +8.6...9.4 +8.6...>11 +8.6...>99 +8.65 +8.7 +8.7...10.6 +8.7...11.2 +8.7...11.3 +8.7...11.7 +8.7...8.9 +8.7...9.1 +8.7...9.6 +8.7...9.8 +8.75 +8.8 +8.8...10.3 +8.8...10.7 +8.8...9.0 +8.8...9.2 +8.8...9.8 +8.8...>9.8 +8.9 +8.9...10.3 +8.9...10.4 +8.9...10.9 +8.9...11.5 +8.9...9.2 +9 +9.8 +9...10 +9...11 +9...>12 +9.0 +9.0... +9.0...10 +9.0...10.0 +9.0...10.5 +9.0...10.7 +9.0...11 +9.0...11.0 +9.0...11.1 +9.0...11.2 +9.0...11.3 +9.0...11.5 +9.0...12 +9.0...9.2 +9.0...9.5 +9.0...>10.7 +9.0...>11.0 +9.1 +9.1...10 +9.1...10.1 +9.1...9.5 +9.15 +9.2 +9.2...10 +9.2...10.8 +9.2...12 +9.2...9.3 +9.2...9.4 +9.2...9.5 +9.2...9.6 +9.25 +9.3 +9.4 +9.4...10 +9.4...12.2 +9.4...9.7 +9.5 +9.5... +9.5...10 +9.5...10.0 +9.5...10.4 +9.5...10.5 +9.5...10.6 +9.5...11.2 +9.5...9.8 +9.5...>10.2 +9.5...>10.5 +9.55 +9.6 +9.6...10 +9.6...10.2 +9.6...11.5 +9.6...>11.2 +9.63 +9.7 +9.7...11 +9.7...11.5 +9.7...9.8 +9.7...>12 +9.75 +9.76 +9.8 +9.8...10.0 +9.8...10.1 +9.8...>12.5 +9.9 +9.99 +10 +10...10.5 +10...11 +10.0 +10.0...10.4 +10.0...10.5 +10.0...11.25 +10.0...11.5 +10.0...12.5 +10.0...>12.5 +10.2 +10.2...11.8 +10.25 +10.3 +10.32 +10.4 +10.45 +10.5 +10.5...11.0 +10.5...11.5 +10.5...<13.5 +10.6 +10.7 +10.7...12.3 +10.70 +10.75 +10.8 +11 +11 +11.0 +11.3 +11.5 +11.5...12.5 +11.75 +12 +12.0 +12.2 +14 +15 +16 +16.7 +17 +18 +19 +19.8 +20 +20.0 +22 +22 +22.9 +23 +23...25 +23.7 +24 +24.0 diff --git a/contrib/seg/expected/seg.out b/contrib/seg/expected/seg.out new file mode 100644 index 0000000000..9abfdc2ecb --- /dev/null +++ b/contrib/seg/expected/seg.out @@ -0,0 +1,1064 @@ +-- +-- Test seg datatype +-- +-- +-- first, define the datatype. Turn off echoing so that expected file +-- does not depend on contents of seg.sql. +-- +\set ECHO none +-- +-- testing the input and output functions +-- +-- Any number +SELECT '1'::seg AS seg; + seg +----- + 1 +(1 row) + +SELECT '-1'::seg AS seg; + seg +----- + -1 +(1 row) + +SELECT '1.0'::seg AS seg; + seg +----- + 1.0 +(1 row) + +SELECT '-1.0'::seg AS seg; + seg +------ + -1.0 +(1 row) + +SELECT '1e7'::seg AS seg; + seg +------- + 1e+07 +(1 row) + +SELECT '-1e7'::seg AS seg; + seg +-------- + -1e+07 +(1 row) + +SELECT '1.0e7'::seg AS seg; + seg +--------- + 1.0e+07 +(1 row) + +SELECT '-1.0e7'::seg AS seg; + seg +---------- + -1.0e+07 +(1 row) + +SELECT '1e+7'::seg AS seg; + seg +------- + 1e+07 +(1 row) + +SELECT '-1e+7'::seg AS seg; + seg +-------- + -1e+07 +(1 row) + +SELECT '1.0e+7'::seg AS seg; + seg +--------- + 1.0e+07 +(1 row) + +SELECT '-1.0e+7'::seg AS seg; + seg +---------- + -1.0e+07 +(1 row) + +SELECT '1e-7'::seg AS seg; + seg +------- + 1e-07 +(1 row) + +SELECT '-1e-7'::seg AS seg; + seg +-------- + -1e-07 +(1 row) + +SELECT '1.0e-7'::seg AS seg; + seg +--------- + 1.0e-07 +(1 row) + +SELECT '-1.0e-7'::seg AS seg; + seg +---------- + -1.0e-07 +(1 row) + +SELECT '2e-6'::seg AS seg; + seg +------- + 2e-06 +(1 row) + +SELECT '2e-5'::seg AS seg; + seg +------- + 2e-05 +(1 row) + +SELECT '2e-4'::seg AS seg; + seg +-------- + 0.0002 +(1 row) + +SELECT '2e-3'::seg AS seg; + seg +------- + 0.002 +(1 row) + +SELECT '2e-2'::seg AS seg; + seg +------ + 0.02 +(1 row) + +SELECT '2e-1'::seg AS seg; + seg +----- + 0.2 +(1 row) + +SELECT '2e-0'::seg AS seg; + seg +----- + 2 +(1 row) + +SELECT '2e+0'::seg AS seg; + seg +----- + 2 +(1 row) + +SELECT '2e+1'::seg AS seg; + seg +----- + 2e1 +(1 row) + +SELECT '2e+2'::seg AS seg; + seg +----- + 2e2 +(1 row) + +SELECT '2e+3'::seg AS seg; + seg +----- + 2e3 +(1 row) + +SELECT '2e+4'::seg AS seg; + seg +----- + 2e4 +(1 row) + +SELECT '2e+5'::seg AS seg; + seg +------- + 2e+05 +(1 row) + +SELECT '2e+6'::seg AS seg; + seg +------- + 2e+06 +(1 row) + +-- Significant digits preserved +SELECT '1'::seg AS seg; + seg +----- + 1 +(1 row) + +SELECT '1.0'::seg AS seg; + seg +----- + 1.0 +(1 row) + +SELECT '1.00'::seg AS seg; + seg +------ + 1.00 +(1 row) + +SELECT '1.000'::seg AS seg; + seg +------- + 1.000 +(1 row) + +SELECT '1.0000'::seg AS seg; + seg +-------- + 1.0000 +(1 row) + +SELECT '1.00000'::seg AS seg; + seg +--------- + 1.00000 +(1 row) + +SELECT '1.000000'::seg AS seg; + seg +--------- + 1.00000 +(1 row) + +SELECT '0.000000120'::seg AS seg; + seg +---------- + 1.20e-07 +(1 row) + +SELECT '3.400e5'::seg AS seg; + seg +----------- + 3.400e+05 +(1 row) + +-- Digits truncated +SELECT '12.34567890123456'::seg AS seg; + seg +--------- + 12.3457 +(1 row) + +-- Numbers with certainty indicators +SELECT '~6.5'::seg AS seg; + seg +------ + ~6.5 +(1 row) + +SELECT '<6.5'::seg AS seg; + seg +------ + <6.5 +(1 row) + +SELECT '>6.5'::seg AS seg; + seg +------ + >6.5 +(1 row) + +SELECT '~ 6.5'::seg AS seg; + seg +------ + ~6.5 +(1 row) + +SELECT '< 6.5'::seg AS seg; + seg +------ + <6.5 +(1 row) + +SELECT '> 6.5'::seg AS seg; + seg +------ + >6.5 +(1 row) + +-- Open intervals +SELECT '0..'::seg AS seg; + seg +------ + 0 .. +(1 row) + +SELECT '0...'::seg AS seg; + seg +------ + 0 .. +(1 row) + +SELECT '0 ..'::seg AS seg; + seg +------ + 0 .. +(1 row) + +SELECT '0 ...'::seg AS seg; + seg +------ + 0 .. +(1 row) + +SELECT '..0'::seg AS seg; + seg +------ + .. 0 +(1 row) + +SELECT '...0'::seg AS seg; + seg +------ + .. 0 +(1 row) + +SELECT '.. 0'::seg AS seg; + seg +------ + .. 0 +(1 row) + +SELECT '... 0'::seg AS seg; + seg +------ + .. 0 +(1 row) + +-- Finite intervals +SELECT '0 .. 1'::seg AS seg; + seg +-------- + 0 .. 1 +(1 row) + +SELECT '-1 .. 0'::seg AS seg; + seg +--------- + -1 .. 0 +(1 row) + +SELECT '-1 .. 1'::seg AS seg; + seg +--------- + -1 .. 1 +(1 row) + +-- (+/-) intervals +SELECT '0(+-)1'::seg AS seg; + seg +--------- + -1 .. 1 +(1 row) + +SELECT '0(+-)1.0'::seg AS seg; + seg +------------- + -1.0 .. 1.0 +(1 row) + +SELECT '1.0(+-)0.005'::seg AS seg; + seg +---------------- + 0.995 .. 1.005 +(1 row) + +SELECT '101(+-)1'::seg AS seg; + seg +------------------ + 1.00e2 .. 1.02e2 +(1 row) + +-- incorrect number of significant digits in 99.0: +SELECT '100(+-)1'::seg AS seg; + seg +---------------- + 99.0 .. 1.01e2 +(1 row) + +-- invalid input +SELECT ''::seg AS seg; +ERROR: seg_in: can't parse an empty string +SELECT 'ABC'::seg AS seg; +ERROR: parse error, expecting `FLOAT' or `RANGE' or `EXTENSION' at or near position 1, character ('A', \101), input: 'ABC' + +SELECT '1ABC'::seg AS seg; +ERROR: expecting end of input at or near position 2, character ('A', \101), input: '1ABC' + +SELECT '1.'::seg AS seg; +ERROR: expecting end of input at or near position 2, character ('.', \056), input: '1.' + +SELECT '1.....'::seg AS seg; +ERROR: expecting end of input at or near position 6, character ('.', \056), input: '1.....' + +SELECT '.1'::seg AS seg; +ERROR: parse error, expecting `FLOAT' or `RANGE' or `EXTENSION' at or near position 2, character ('1', \061), input: '.1' + +SELECT '1..2.'::seg AS seg; +ERROR: expecting end of input at or near position 5, character ('.', \056), input: '1..2.' + +SELECT '1 e7'::seg AS seg; +ERROR: expecting end of input at or near position 3, character ('e', \145), input: '1 e7' + +SELECT '1e700'::seg AS seg; +ERROR: numeric value 1e700 unrepresentable +-- +-- testing the operators +-- +-- equality/inequality: +-- +SELECT '24 .. 33.20'::seg = '24 .. 33.20'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '24 .. 33.20'::seg = '24 .. 33.21'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '24 .. 33.20'::seg != '24 .. 33.20'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '24 .. 33.20'::seg != '24 .. 33.21'::seg AS bool; + bool +------ + t +(1 row) + +-- overlap +-- +SELECT '1'::seg && '1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '1'::seg && '2'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 ..'::seg && '0 ..'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 1'::seg && '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '..0'::seg && '0..'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '-1 .. 0.1'::seg && '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '-1 .. 0'::seg && '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '-1 .. -0.0001'::seg && '0 .. 1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 ..'::seg && '1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 1'::seg && '1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 1'::seg && '2'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 2'::seg && '1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '1'::seg && '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '2'::seg && '0 .. 1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '1'::seg && '0 .. 2'::seg AS bool; + bool +------ + t +(1 row) + +-- overlap on the left +-- +SELECT '1'::seg &< '0'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '1'::seg &< '1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '1'::seg &< '2'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 1'::seg &< '0'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 1'::seg &< '1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 1'::seg &< '2'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 1'::seg &< '0 .. 0.5'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 1'::seg &< '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 1'::seg &< '0 .. 2'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 1'::seg &< '1 .. 2'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 1'::seg &< '2 .. 3'::seg AS bool; + bool +------ + f +(1 row) + +-- overlap on the right +-- +SELECT '0'::seg &> '1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '1'::seg &> '1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '2'::seg &> '1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0'::seg &> '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '1'::seg &> '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '2'::seg &> '0 .. 1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 0.5'::seg &> '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 1'::seg &> '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 2'::seg &> '0 .. 2'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '1 .. 2'::seg &> '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '2 .. 3'::seg &> '0 .. 1'::seg AS bool; + bool +------ + f +(1 row) + +-- left +-- +SELECT '1'::seg << '0'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '1'::seg << '1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '1'::seg << '2'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 1'::seg << '0'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 1'::seg << '1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 1'::seg << '2'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 1'::seg << '0 .. 0.5'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 1'::seg << '0 .. 1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 1'::seg << '0 .. 2'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 1'::seg << '1 .. 2'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 1'::seg << '2 .. 3'::seg AS bool; + bool +------ + t +(1 row) + +-- right +-- +SELECT '0'::seg >> '1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '1'::seg >> '1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '2'::seg >> '1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0'::seg >> '0 .. 1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '1'::seg >> '0 .. 1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '2'::seg >> '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. 0.5'::seg >> '0 .. 1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 1'::seg >> '0 .. 1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0 .. 2'::seg >> '0 .. 2'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '1 .. 2'::seg >> '0 .. 1'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '2 .. 3'::seg >> '0 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +-- "contained in" (the left value belongs within the interval specified in the right value): +-- +SELECT '0'::seg ~ '0'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0'::seg ~ '0 ..'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0'::seg ~ '.. 0'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0'::seg ~ '-1 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0'::seg ~ '-1 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '-1'::seg ~ '-1 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '1'::seg ~ '-1 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '-1 .. 1'::seg ~ '-1 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +-- "contains" (the left value contains the interval specified in the right value): +-- +SELECT '0'::seg @ '0'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '0 .. '::seg ~ '0'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '.. 0'::seg ~ '0'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '-1 .. 1'::seg ~ '0'::seg AS bool; + bool +------ + f +(1 row) + +SELECT '0'::seg ~ '-1 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '-1'::seg ~ '-1 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +SELECT '1'::seg ~ '-1 .. 1'::seg AS bool; + bool +------ + t +(1 row) + +-- Load some example data and build the index +-- +CREATE TABLE test_seg (s seg); +\copy test_seg from 'data/test_seg.data' +CREATE INDEX test_seg_ix ON test_seg USING gist (s); +SELECT count(*) FROM test_seg WHERE s @ '11..11.3'; + count +------- + 143 +(1 row) + +-- Test sorting +SELECT * FROM test_seg WHERE s @ '11..11.3' GROUP BY s; + s +----------------- + .. 4.0e1 + .. >8.2e1 + .. 9.0e1 + <1.0 .. >13.0 + 1.3 .. 12.0 + 2.0 .. 11.5 + 2.1 .. 11.8 + <2.3 .. + >2.3 .. + 2.4 .. 11.3 + 2.5 .. 11.5 + 2.5 .. 11.8 + 2.6 .. + 2.7 .. 12.0 + <3.0 .. + 3 .. 5.8e1 + 3.1 .. 11.5 + 3.5 .. 11.5 + 3.5 .. 12.2 + <4.0 .. >1.2e1 + <4.0 .. + 4 .. 1.2e1 + 4.0 .. 11.7 + 4.0 .. 12.5 + 4.0 .. 13.0 + 4.0 .. 6.0e1 + 4.0 .. + 4.2 .. 11.5 + 4.2 .. 11.7 + <4.5 .. >1.2e1 + 4.5 .. 11.5 + 4.5 .. <1.2e1 + 4.5 .. >1.2e1 + 4.5 .. 12.5 + 4.5 .. 1.15e2 + 4.7 .. 11.8 + 4.8 .. 11.5 + 4.8 .. 11.6 + 4.8 .. 12.5 + 4.8 .. + 4.9 .. >1.2e1 + 4.9 .. + 5 .. 11.5 + 5 .. 1.2e1 + 5 .. 3.0e1 + 5.0 .. 11.4 + 5.0 .. 11.5 + 5.0 .. 11.6 + 5.0 .. 11.7 + 5.0 .. 12.0 + 5.0 .. >12.0 + 5.0 .. >1.2e1 + 5.2 .. 11.5 + 5.2 .. >1.2e1 + 5.25 .. >1.2e1 + 5.3 .. 11.5 + 5.3 .. 1.3e1 + 5.3 .. >9.0e1 + 5.3 .. + 5.4 .. + 5.5 .. 11.5 + 5.5 .. 11.7 + 5.5 .. 1.2e1 + 5.5 .. >1.2e1 + 5.5 .. 12.5 + 5.5 .. 13.5 + 5.5 .. + >5.5 .. + 5.7 .. + 5.9 .. + 6 .. 11.5 + 6 .. >1.2e1 + 6.0 .. 11.5 + 6.0 .. 1.3e1 + >6.0 .. <11.5 + 6.1 .. >1.2e1 + 6.1 .. + 6.2 .. >11.5 + 6.3 .. + 6.5 .. 11.5 + 6.5 .. 12.0 + 6.5 .. >12.0 + 6.5 .. + 6.6 .. + 6.7 .. 11.5 + 6.7 .. + 6.75 .. + 6.8 .. + 6.9 .. 12.2 + 6.9 .. >9.0e1 + 6.9 .. + <7.0 .. >11.5 + 7.0 .. 11.5 + 7.0 .. >11.5 + 7.0 .. + >7.15 .. + 7.2 .. 13.5 + 7.3 .. >9.0e1 + 7.3 .. + >7.3 .. + 7.4 .. 12.1 + 7.4 .. + 7.5 .. 11.5 + 7.5 .. 12.0 + 7.5 .. + 7.7 .. 11.5 + 7.7 .. + 7.75 .. + 8.0 .. 11.7 + 8.0 .. 12.0 + 8.0 .. >13.0 + 8.2 .. + 8.3 .. + 8.5 .. >11.5 + 8.5 .. 12.5 + 8.5 .. + 8.6 .. >9.9e1 + 8.7 .. 11.3 + 8.7 .. 11.7 + 8.9 .. 11.5 + 9 .. >1.2e1 + 9.0 .. 11.3 + 9.0 .. 11.5 + 9.0 .. 1.2e1 + 9.0 .. + 9.2 .. 1.2e1 + 9.4 .. 12.2 + <9.5 .. 1.2e1 + <9.5 .. >12.2 + 9.5 .. + 9.6 .. 11.5 + 9.7 .. 11.5 + 9.7 .. >1.2e1 + 9.8 .. >12.5 + <1.0e1 .. >11.6 + 10.0 .. 11.5 + 10.0 .. 12.5 + 10.0 .. >12.5 + 10.2 .. 11.8 + <10.5 .. 11.5 + 10.5 .. 11.5 + 10.5 .. <13.5 + 10.7 .. 12.3 +(143 rows) + diff --git a/contrib/seg/seg-validate.pl b/contrib/seg/seg-validate.pl new file mode 100755 index 0000000000..9272936aef --- /dev/null +++ b/contrib/seg/seg-validate.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl +$integer = '[+-]?[0-9]+'; +$real = '[+-]?[0-9]+\.[0-9]+'; + +$RANGE = '(\.\.)(\.)?'; +$PLUMIN = q(\'\+\-\'); +$FLOAT = "(($integer)|($real))([eE]($integer))?"; +$EXTENSION = '<|>|~'; + +$boundary = "($EXTENSION)?$FLOAT"; +$deviation = $FLOAT; + +$rule_1 = $boundary . $PLUMIN . $deviation; +$rule_2 = $boundary . $RANGE . $boundary; +$rule_3 = $boundary . $RANGE; +$rule_4 = $RANGE . $boundary; +$rule_5 = $boundary; + + +print "$rule_5\n"; +while (<>) { +# s/ +//g; + if ( /^($rule_1)$/ ) { + print; + } + elsif ( /^($rule_2)$/ ) { + print; + } + elsif ( /^($rule_3)$/ ) { + print; + } + elsif ( /^($rule_4)$/ ) { + print; + } + elsif ( /^($rule_5)$/ ) { + print; + } + else { + print STDERR "error in $_\n"; + } + +} diff --git a/contrib/seg/seg.c b/contrib/seg/seg.c new file mode 100644 index 0000000000..1609b42b1e --- /dev/null +++ b/contrib/seg/seg.c @@ -0,0 +1,1049 @@ +/****************************************************************************** + 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 + +#include "access/gist.h" +#include "access/rtree.h" +#include "utils/elog.h" +#include "utils/palloc.h" +#include "utils/builtins.h" + +#include "segdata.h" + +#define max(a,b) ((a) > (b) ? (a) : (b)) +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#define abs(a) ((a) < (0) ? (-a) : (a)) + +/* +#define GIST_DEBUG +#define GIST_QUERY_DEBUG +*/ + +extern void set_parse_buffer(char *str); +extern int seg_yyparse(); +/* +extern int seg_yydebug; +*/ + +/* +** Input/Output routines +*/ +SEG * seg_in(char *str); +char * seg_out(SEG *seg); +float32 seg_lower(SEG *seg); +float32 seg_upper(SEG *seg); +float32 seg_center(SEG *seg); + +/* +** GiST support methods +*/ +bool gseg_consistent(GISTENTRY *entry, SEG *query, StrategyNumber strategy); +GISTENTRY * gseg_compress(GISTENTRY *entry); +GISTENTRY * gseg_decompress(GISTENTRY *entry); +float * gseg_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result); +GIST_SPLITVEC * gseg_picksplit(bytea *entryvec, GIST_SPLITVEC *v); +bool gseg_leaf_consistent(SEG *key, SEG *query, StrategyNumber strategy); +bool gseg_internal_consistent(SEG *key, SEG *query, StrategyNumber strategy); +SEG * gseg_union(bytea *entryvec, int *sizep); +SEG * gseg_binary_union(SEG *r1, SEG *r2, int *sizep); +bool * gseg_same(SEG *b1, SEG *b2, bool *result); + + +/* +** R-tree suport functions +*/ +bool seg_same(SEG *a, SEG *b); +bool seg_contains_int(SEG *a, int *b); +bool seg_contains_float4(SEG *a, float4 *b); +bool seg_contains_float8(SEG *a, float8 *b); +bool seg_contains(SEG *a, SEG *b); +bool seg_contained(SEG *a, SEG *b); +bool seg_overlap(SEG *a, SEG *b); +bool seg_left(SEG *a, SEG *b); +bool seg_over_left(SEG *a, SEG *b); +bool seg_right(SEG *a, SEG *b); +bool seg_over_right(SEG *a, SEG *b); +SEG * seg_union(SEG *a, SEG *b); +SEG * seg_inter(SEG *a, SEG *b); +void rt_seg_size(SEG *a, float* sz); +float * seg_size(SEG *a); + +/* +** Various operators +*/ +int32 seg_cmp(SEG *a, SEG *b); +bool seg_lt(SEG *a, SEG *b); +bool seg_le(SEG *a, SEG *b); +bool seg_gt(SEG *a, SEG *b); +bool seg_ge(SEG *a, SEG *b); +bool seg_different(SEG *a, SEG *b); + +/* +** Auxiliary funxtions +*/ +static int restore(char *s, float val, int n); +int significant_digits (char* s); + + +/***************************************************************************** + * Input/Output functions + *****************************************************************************/ + +SEG * +seg_in(char *str) +{ + SEG * result = palloc(sizeof(SEG)); + set_parse_buffer( str ); + + /* + seg_yydebug = 1; + */ + if ( seg_yyparse(result) != 0 ) { + pfree ( result ); + return NULL; + } + return ( result ); +} + +/* + * You might have noticed a slight inconsistency between the following + * declaration and the SQL definition: + * CREATE FUNCTION seg_out(opaque) RETURNS opaque ... + * The reason is that the argument passed into seg_out is really just a + * pointer. POSTGRES thinks all output functions are: + * char *out_func(char *); + */ +char * +seg_out(SEG *seg) +{ + char *result; + char *p; + + if (seg == NULL) return(NULL); + + p = result = (char *) palloc(40); + + if ( seg->l_ext == '>' || seg->l_ext == '<' || seg->l_ext == '~' ) { + p += sprintf(p, "%c", seg->l_ext); + } + + if ( seg->lower == seg->upper && seg->l_ext == seg->u_ext ) { + /* indicates that this interval was built by seg_in off a single point */ + p += restore(p, seg->lower, seg->l_sigd); + } + else { + if ( seg->l_ext != '-' ) { + /* print the lower boudary if exists */ + p += restore(p, seg->lower, seg->l_sigd); + p += sprintf(p, " "); + } + p += sprintf(p, ".."); + if ( seg->u_ext != '-' ) { + /* print the upper boudary if exists */ + p += sprintf(p, " "); + if ( seg->u_ext == '>' || seg->u_ext == '<' || seg->l_ext == '~' ) { + p += sprintf(p, "%c", seg->u_ext); + } + p += restore(p, seg->upper, seg->u_sigd); + } + } + + return(result); +} + +float32 +seg_center(SEG *seg) +{ + float32 result = (float32) palloc(sizeof(float32data)); + + if (!seg) + return (float32) NULL; + + *result = ((float)seg->lower + (float)seg->upper)/2.0; + return (result); +} + +float32 +seg_lower(SEG *seg) +{ + float32 result = (float32) palloc(sizeof(float32data)); + + if (!seg) + return (float32) NULL; + + *result = (float)seg->lower; + return (result); +} + +float32 +seg_upper(SEG *seg) +{ + float32 result = (float32) palloc(sizeof(float32data)); + + if (!seg) + return (float32) NULL; + + *result = (float)seg->upper; + return (result); +} + + +/***************************************************************************** + * GiST functions + *****************************************************************************/ + +/* +** The GiST Consistent method for segments +** 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. +*/ +bool +gseg_consistent(GISTENTRY *entry, + SEG *query, + StrategyNumber strategy) +{ + /* + ** if entry is not leaf, use gseg_internal_consistent, + ** else use gseg_leaf_consistent + */ + if (GIST_LEAF(entry)) + return(gseg_leaf_consistent((SEG *)(entry->pred), query, strategy)); + else + return(gseg_internal_consistent((SEG *)(entry->pred), query, strategy)); +} + +/* +** The GiST Union method for segments +** returns the minimal bounding seg that encloses all the entries in entryvec +*/ +SEG * +gseg_union(bytea *entryvec, int *sizep) +{ + int numranges, i; + SEG *out = (SEG *)NULL; + SEG *tmp; + +#ifdef GIST_DEBUG + fprintf(stderr, "union\n"); +#endif + + numranges = (VARSIZE(entryvec) - VARHDRSZ)/sizeof(GISTENTRY); + tmp = (SEG *)(((GISTENTRY *)(VARDATA(entryvec)))[0]).pred; + *sizep = sizeof(SEG); + + for (i = 1; i < numranges; i++) { + out = gseg_binary_union(tmp, (SEG *) + (((GISTENTRY *)(VARDATA(entryvec)))[i]).pred, + sizep); +#ifdef GIST_DEBUG + /* + fprintf(stderr, "\t%s ^ %s -> %s\n", seg_out(tmp), seg_out((SEG *)(((GISTENTRY *)(VARDATA(entryvec)))[i]).pred), seg_out(out)); + */ +#endif + + if (i > 1) pfree(tmp); + tmp = out; + } + + return(out); +} + +/* +** GiST Compress and Decompress methods for segments +** do not do anything. +*/ +GISTENTRY * +gseg_compress(GISTENTRY *entry) +{ + return(entry); +} + +GISTENTRY * +gseg_decompress(GISTENTRY *entry) +{ + return(entry); +} + +/* +** The GiST Penalty method for segments +** As in the R-tree paper, we use change in area as our penalty metric +*/ +float * +gseg_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result) +{ + Datum ud; + float tmp1, tmp2; + + ud = (Datum)seg_union((SEG *)(origentry->pred), (SEG *)(newentry->pred)); + rt_seg_size((SEG *)ud, &tmp1); + rt_seg_size((SEG *)(origentry->pred), &tmp2); + *result = tmp1 - tmp2; + pfree((char *)ud); + +#ifdef GIST_DEBUG + fprintf(stderr, "penalty\n"); + fprintf(stderr, "\t%g\n", *result); +#endif + + return(result); +} + + + +/* +** The GiST PickSplit method for segments +** We use Guttman's poly time split algorithm +*/ +GIST_SPLITVEC * +gseg_picksplit(bytea *entryvec, + GIST_SPLITVEC *v) +{ + OffsetNumber i, j; + SEG *datum_alpha, *datum_beta; + SEG *datum_l, *datum_r; + SEG *union_d, *union_dl, *union_dr; + SEG *inter_d; + bool firsttime; + float size_alpha, size_beta, size_union, size_inter; + float size_waste, waste; + float size_l, size_r; + int nbytes; + OffsetNumber seed_1 = 0, seed_2 = 0; + OffsetNumber *left, *right; + OffsetNumber maxoff; + +#ifdef GIST_DEBUG + fprintf(stderr, "picksplit\n"); +#endif + + maxoff = ((VARSIZE(entryvec) - VARHDRSZ)/sizeof(GISTENTRY)) - 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 = (SEG *)(((GISTENTRY *)(VARDATA(entryvec)))[i].pred); + for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j)) { + datum_beta = (SEG *)(((GISTENTRY *)(VARDATA(entryvec)))[j].pred); + + /* compute the wasted space by unioning these guys */ + /* size_waste = size_union - size_inter; */ + union_d = (SEG *)seg_union(datum_alpha, datum_beta); + rt_seg_size(union_d, &size_union); + inter_d = (SEG *)seg_inter(datum_alpha, datum_beta); + rt_seg_size(inter_d, &size_inter); + size_waste = size_union - size_inter; + + pfree(union_d); + + if (inter_d != (SEG *) NULL) + pfree(inter_d); + + /* + * are these a more promising split that 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 = (SEG *)(((GISTENTRY *)(VARDATA(entryvec)))[seed_1].pred); + datum_l = (SEG *)seg_union(datum_alpha, datum_alpha); + rt_seg_size((SEG *)datum_l, &size_l); + datum_beta = (SEG *)(((GISTENTRY *)(VARDATA(entryvec)))[seed_2].pred);; + datum_r = (SEG *)seg_union(datum_beta, datum_beta); + rt_seg_size((SEG *)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 = (SEG *)(((GISTENTRY *)(VARDATA(entryvec)))[i].pred); + union_dl = (SEG *)seg_union(datum_l, datum_alpha); + union_dr = (SEG *)seg_union(datum_r, datum_alpha); + rt_seg_size((SEG *)union_dl, &size_alpha); + rt_seg_size((SEG *)union_dr, &size_beta); + + /* pick which page to add it to */ + if (size_alpha - size_l < size_beta - size_r) { + pfree(datum_l); + pfree(union_dr); + datum_l = union_dl; + size_l = size_alpha; + *left++ = i; + v->spl_nleft++; + } else { + pfree(datum_r); + pfree(union_dl); + datum_r = union_dr; + size_r = size_alpha; + *right++ = i; + v->spl_nright++; + } + } + *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */ + + v->spl_ldatum = (char *)datum_l; + v->spl_rdatum = (char *)datum_r; + + return v; +} + +/* +** Equality methods +*/ +bool * +gseg_same(SEG *b1, SEG *b2, bool *result) +{ + if (seg_same(b1, b2)) + *result = TRUE; + else *result = FALSE; + +#ifdef GIST_DEBUG + fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE" )); +#endif + + return(result); +} + +/* +** SUPPORT ROUTINES +*/ +bool +gseg_leaf_consistent(SEG *key, + SEG *query, + StrategyNumber strategy) +{ + bool retval; + +#ifdef GIST_QUERY_DEBUG + fprintf(stderr, "leaf_consistent, %d\n", strategy); +#endif + + switch(strategy) { + case RTLeftStrategyNumber: + retval = (bool)seg_left(key, query); + break; + case RTOverLeftStrategyNumber: + retval = (bool)seg_over_left(key,query); + break; + case RTOverlapStrategyNumber: + retval = (bool)seg_overlap(key, query); + break; + case RTOverRightStrategyNumber: + retval = (bool)seg_over_right(key, query); + break; + case RTRightStrategyNumber: + retval = (bool)seg_right(key, query); + break; + case RTSameStrategyNumber: + retval = (bool)seg_same(key, query); + break; + case RTContainsStrategyNumber: + retval = (bool)seg_contains(key, query); + break; + case RTContainedByStrategyNumber: + retval = (bool)seg_contained(key,query); + break; + default: + retval = FALSE; + } + return(retval); +} + +bool +gseg_internal_consistent(SEG *key, + SEG *query, + StrategyNumber strategy) +{ + bool retval; + +#ifdef GIST_QUERY_DEBUG + fprintf(stderr, "internal_consistent, %d\n", strategy); +#endif + + switch(strategy) { + case RTLeftStrategyNumber: + case RTOverLeftStrategyNumber: + retval = (bool)seg_over_left(key,query); + break; + case RTOverlapStrategyNumber: + retval = (bool)seg_overlap(key, query); + break; + case RTOverRightStrategyNumber: + case RTRightStrategyNumber: + retval = (bool)seg_right(key, query); + break; + case RTSameStrategyNumber: + case RTContainsStrategyNumber: + retval = (bool)seg_contains(key, query); + break; + case RTContainedByStrategyNumber: + retval = (bool)seg_overlap(key, query); + break; + default: + retval = FALSE; + } + return(retval); +} + +SEG * +gseg_binary_union(SEG *r1, SEG *r2, int *sizep) +{ + SEG *retval; + + retval = seg_union(r1, r2); + *sizep = sizeof(SEG); + + return (retval); +} + + +bool +seg_contains(SEG *a, SEG *b) +{ + return ( (a->lower <= b->lower) && (a->upper >= b->upper) ); +} + +bool +seg_contained(SEG *a, SEG *b) +{ + return ( seg_contains(b, a) ); +} + +/***************************************************************************** + * Operator class for R-tree indexing + *****************************************************************************/ + +bool +seg_same(SEG *a, SEG *b) +{ + return seg_cmp(a, b) == 0; +} + +/* seg_overlap -- does a overlap b? + */ +bool +seg_overlap(SEG *a, SEG *b) +{ + return ( + ((a->upper >= b->upper) && (a->lower <= b->upper)) + || + ((b->upper >= a->upper) && (b->lower <= a->upper)) + ); +} + +/* seg_overleft -- is the right edge of (a) located to the left of the right edge of (b)? + */ +bool +seg_over_left(SEG *a, SEG *b) +{ + return ( a->upper <= b->upper && !seg_left(a, b) && !seg_right(a, b)); +} + +/* seg_left -- is (a) entirely on the left of (b)? + */ +bool +seg_left(SEG *a, SEG *b) +{ + return ( a->upper < b->lower ); +} + +/* seg_right -- is (a) entirely on the right of (b)? + */ +bool +seg_right(SEG *a, SEG *b) +{ + return ( a->lower > b->upper ); +} + +/* seg_overright -- is the left edge of (a) located to the right of the left edge of (b)? + */ +bool +seg_over_right(SEG *a, SEG *b) +{ + return (a->lower >= b->lower && !seg_left(a, b) && !seg_right(a, b)); +} + + +SEG * +seg_union(SEG *a, SEG *b) +{ + SEG *n; + + n = (SEG *) palloc(sizeof(*n)); + + /* take max of upper endpoints */ + if (a->upper > b->upper) + { + n->upper = a->upper; + n->u_sigd = a->u_sigd; + n->u_ext = a->u_ext; + } + else + { + n->upper = b->upper; + n->u_sigd = b->u_sigd; + n->u_ext = b->u_ext; + } + + /* take min of lower endpoints */ + if (a->lower < b->lower) + { + n->lower = a->lower; + n->l_sigd = a->l_sigd; + n->l_ext = a->l_ext; + } + else + { + n->lower = b->lower; + n->l_sigd = b->l_sigd; + n->l_ext = b->l_ext; + } + + return (n); +} + + +SEG * +seg_inter(SEG *a, SEG *b) +{ + SEG *n; + + n = (SEG *) palloc(sizeof(*n)); + + /* take min of upper endpoints */ + if (a->upper < b->upper) + { + n->upper = a->upper; + n->u_sigd = a->u_sigd; + n->u_ext = a->u_ext; + } + else + { + n->upper = b->upper; + n->u_sigd = b->u_sigd; + n->u_ext = b->u_ext; + } + + /* take max of lower endpoints */ + if (a->lower > b->lower) + { + n->lower = a->lower; + n->l_sigd = a->l_sigd; + n->l_ext = a->l_ext; + } + else + { + n->lower = b->lower; + n->l_sigd = b->l_sigd; + n->l_ext = b->l_ext; + } + + return (n); +} + +void +rt_seg_size(SEG *a, float *size) +{ + if (a == (SEG *) NULL || a->upper <= a->lower) + *size = 0.0; + else + *size = (float) abs(a->upper - a->lower); + + return; +} + +float * +seg_size(SEG *a) +{ + float *result; + + result = (float *) palloc(sizeof(float)); + + *result = (float) abs(a->upper - a->lower); + + return(result); +} + + +/***************************************************************************** + * Miscellaneous operators + *****************************************************************************/ +int32 +seg_cmp(SEG *a, SEG *b) +{ + /* + * First compare on lower boundary position + */ + if ( a->lower < b->lower ) + return -1; + if ( a->lower > b->lower ) + return 1; + /* + * a->lower == b->lower, so consider type of boundary. + * + * A '-' lower bound is < any other kind (this could only be relevant + * if -HUGE is used as a regular data value). + * A '<' lower bound is < any other kind except '-'. + * A '>' lower bound is > any other kind. + */ + if ( a->l_ext != b->l_ext ) + { + if ( a->l_ext == '-') + return -1; + if ( b->l_ext == '-') + return 1; + if ( a->l_ext == '<') + return -1; + if ( b->l_ext == '<') + return 1; + if ( a->l_ext == '>') + return 1; + if ( b->l_ext == '>') + return -1; + } + /* + * For other boundary types, consider # of significant digits first. + */ + if ( a->l_sigd < b->l_sigd ) /* (a) is blurred and is likely to include (b) */ + return -1; + if ( a->l_sigd > b->l_sigd ) /* (a) is less blurred and is likely to be included in (b) */ + return 1; + /* + * For same # of digits, an approximate boundary is more blurred than + * exact. + */ + if ( a->l_ext != b->l_ext ) + { + if ( a->l_ext == '~' ) /* (a) is approximate, while (b) is exact */ + return -1; + if ( b->l_ext == '~' ) + return 1; + /* can't get here unless data is corrupt */ + elog(ERROR, "seg_cmp: bogus lower boundary types %d %d", + (int) a->l_ext, (int) b->l_ext); + } + + /* at this point, the lower boundaries are identical */ + + /* + * First compare on upper boundary position + */ + if ( a->upper < b->upper ) + return -1; + if ( a->upper > b->upper ) + return 1; + /* + * a->upper == b->upper, so consider type of boundary. + * + * A '-' upper bound is > any other kind (this could only be relevant + * if HUGE is used as a regular data value). + * A '<' upper bound is < any other kind. + * A '>' upper bound is > any other kind except '-'. + */ + if ( a->u_ext != b->u_ext ) + { + if ( a->u_ext == '-') + return 1; + if ( b->u_ext == '-') + return -1; + if ( a->u_ext == '<') + return -1; + if ( b->u_ext == '<') + return 1; + if ( a->u_ext == '>') + return 1; + if ( b->u_ext == '>') + return -1; + } + /* + * For other boundary types, consider # of significant digits first. + * Note result here is converse of the lower-boundary case. + */ + if ( a->u_sigd < b->u_sigd ) /* (a) is blurred and is likely to include (b) */ + return 1; + if ( a->u_sigd > b->u_sigd ) /* (a) is less blurred and is likely to be included in (b) */ + return -1; + /* + * For same # of digits, an approximate boundary is more blurred than + * exact. Again, result is converse of lower-boundary case. + */ + if ( a->u_ext != b->u_ext ) + { + if ( a->u_ext == '~' ) /* (a) is approximate, while (b) is exact */ + return 1; + if ( b->u_ext == '~' ) + return -1; + /* can't get here unless data is corrupt */ + elog(ERROR, "seg_cmp: bogus upper boundary types %d %d", + (int) a->u_ext, (int) b->u_ext); + } + + return 0; +} + +bool +seg_lt(SEG *a, SEG *b) +{ + return seg_cmp(a, b) < 0; +} + +bool +seg_le(SEG *a, SEG *b) +{ + return seg_cmp(a, b) <= 0; +} + +bool +seg_gt(SEG *a, SEG *b) +{ + return seg_cmp(a, b) > 0; +} + + +bool +seg_ge(SEG *a, SEG *b) +{ + return seg_cmp(a, b) >= 0; +} + +bool +seg_different(SEG *a, SEG *b) +{ + return seg_cmp(a, b) != 0; +} + + + +/***************************************************************************** + * Auxiliary functions + *****************************************************************************/ + +/* The purpose of this routine is to print the floating point + * value with exact number of significant digits. Its behaviour + * is similar to %.ng except it prints 8.00 where %.ng would + * print 8 + */ +static int restore ( char * result, float val, int n ) +{ + static char efmt[8] = {'%', '-', '1', '5', '.', '#', 'e', 0}; + char buf[25] = { + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '\0' + }; + char *p; + char *mant; + int exp; + int i, dp, sign; + + /* put a cap on the number of siugnificant digits to avoid + nonsense in the output */ + n = min(n, FLT_DIG); + + /* remember the sign */ + sign = ( val < 0 ? 1 : 0 ); + + efmt[5] = '0' + (n-1)%10; /* makes %-15.(n-1)e -- this format guarantees that + the exponent is always present */ + + sprintf(result, efmt, val); + + /* trim the spaces left by the %e */ + for( p = result; *p != ' '; p++ ); *p = '\0'; + + /* get the exponent */ + mant = (char *)strtok( strdup(result), "e" ); + exp = atoi(strtok( NULL, "e" )); + + if ( exp == 0 ) { + /* use the supplied mantyssa with sign */ + strcpy((char *)index(result, 'e'), ""); + } + else { + if ( abs( exp ) <= 4 ) { + /* remove the decimal point from the mantyssa and write the digits to the buf array */ + for( p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++ ) { + buf[i] = *p; + if( *p == '.' ) { + dp = i--; /* skip the decimal point */ + } + } + if (dp == 0) dp = i--; /* no decimal point was found in the above for() loop */ + + if ( exp > 0 ) { + if ( dp - 10 + exp >= n ) { + /* + the decimal point is behind the last significant digit; + the digits in between must be converted to the exponent + and the decimal point placed after the first digit + */ + exp = dp - 10 + exp - n; + buf[10+n] = '\0'; + + /* insert the decimal point */ + if ( n > 1 ) { + dp = 11; + for ( i = 23; i > dp; i-- ) { + buf[i] = buf[i-1]; + } + buf[dp] = '.'; + } + + /* adjust the exponent by the number of digits after the decimal point */ + if ( n > 1 ) { + sprintf(&buf[11+n], "e%d", exp + n - 1); + } + else { + sprintf(&buf[11], "e%d", exp + n - 1); + } + + if ( sign ) { + buf[9] = '-'; + strcpy(result, &buf[9]); + } + else { + strcpy(result, &buf[10]); + } + } + else { /* insert the decimal point */ + dp += exp; + for ( i = 23; i > dp; i-- ) { + buf[i] = buf[i-1]; + } + buf[11+n] = '\0'; + buf[dp] = '.'; + if ( sign ) { + buf[9] = '-'; + strcpy(result, &buf[9]); + } + else { + strcpy(result, &buf[10]); + } + } + } + else { /* exp <= 0 */ + dp += exp - 1; + buf[10+n] = '\0'; + buf[dp] = '.'; + if ( sign ) { + buf[dp-2] = '-'; + strcpy(result, &buf[dp-2]); + } + else { + strcpy(result, &buf[dp-1]); + } + } + } + + /* do nothing for abs(exp) > 4; %e must be OK */ + /* just get rid of zeroes after [eE]- and +zeroes after [Ee]. */ + + /* ... this is not done yet. */ + } + return ( strlen ( result ) ); +} + + +/* +** Miscellany +*/ + +bool +seg_contains_int(SEG *a, int *b) +{ + return ( (a->lower <= *b) && (a->upper >= *b) ); +} + +bool +seg_contains_float4(SEG *a, float4 *b) +{ + return ( (a->lower <= *b) && (a->upper >= *b) ); +} + +bool +seg_contains_float8(SEG *a, float8 *b) +{ + return ( (a->lower <= *b) && (a->upper >= *b) ); +} + +/* find out the number of significant digits in a string representing + * a floating point number + */ +int significant_digits ( char* s ) +{ + char * p = s; + int n, c, zeroes; + + zeroes = 1; + /* skip leading zeroes and sign */ + for ( c = *p; (c == '0' || c == '+' || c == '-') && c != 0; c = *(++p) ); + + /* skip decimal point and following zeroes */ + for ( c = *p; (c == '0' || c == '.' ) && c != 0; c = *(++p) ) { + if ( c != '.') zeroes++; + } + + /* count significant digits (n) */ + for ( c = *p, n = 0; c != 0; c = *(++p) ) { + if ( !( (c >= '0' && c <= '9') || (c == '.') ) ) break; + if ( c != '.') n++; + } + + if (!n) return ( zeroes ); + + return( n ); +} diff --git a/contrib/seg/seg.sql.in b/contrib/seg/seg.sql.in new file mode 100644 index 0000000000..387989f742 --- /dev/null +++ b/contrib/seg/seg.sql.in @@ -0,0 +1,361 @@ +-- Create the user-defined type for 1-D floating point intervals (seg) +-- +BEGIN TRANSACTION; + +CREATE FUNCTION seg_in(opaque) +RETURNS opaque +AS 'MODULE_PATHNAME' +LANGUAGE 'c'; + +CREATE FUNCTION seg_out(opaque) +RETURNS opaque +AS 'MODULE_PATHNAME' +LANGUAGE 'c'; + +CREATE TYPE seg ( +internallength = 12, +input = seg_in, +output = seg_out +); + +COMMENT ON TYPE seg IS +'floating point interval ''FLOAT .. FLOAT'', ''.. FLOAT'', ''FLOAT ..'' or ''FLOAT'''; + +-- +-- External C-functions for R-tree methods +-- + +-- Left/Right methods + +CREATE FUNCTION seg_over_left(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_over_left(seg, seg) IS +'is over and left of'; + +CREATE FUNCTION seg_over_right(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_over_right(seg, seg) IS +'is over and right of'; + +CREATE FUNCTION seg_left(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_left(seg, seg) IS +'is left of'; + +CREATE FUNCTION seg_right(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_right(seg, seg) IS +'is right of'; + + +-- Comparison methods + +CREATE FUNCTION seg_lt(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_lt(seg, seg) IS +'less than'; + +CREATE FUNCTION seg_le(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_le(seg, seg) IS +'less than or equal'; + +CREATE FUNCTION seg_gt(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_gt(seg, seg) IS +'greater than'; + +CREATE FUNCTION seg_ge(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_ge(seg, seg) IS +'greater than or equal'; + +CREATE FUNCTION seg_contains(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_contains(seg, seg) IS +'contains'; + +CREATE FUNCTION seg_contained(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_contained(seg, seg) IS +'contained in'; + +CREATE FUNCTION seg_overlap(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_overlap(seg, seg) IS +'overlaps'; + +CREATE FUNCTION seg_same(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_same(seg, seg) IS +'same as'; + +CREATE FUNCTION seg_different(seg, seg) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +COMMENT ON FUNCTION seg_different(seg, seg) IS +'different'; + +-- support routines for indexing + +CREATE FUNCTION seg_union(seg, seg) RETURNS seg + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +CREATE FUNCTION seg_inter(seg, seg) RETURNS seg + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +CREATE FUNCTION seg_size(seg) RETURNS float4 + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +-- miscellaneous + +CREATE FUNCTION seg_upper(seg) RETURNS float4 + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +CREATE FUNCTION seg_lower(seg) RETURNS float4 + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + + +-- +-- OPERATORS +-- + +CREATE OPERATOR < ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_lt, + COMMUTATOR = '>', NEGATOR = '>=', + RESTRICT = scalarltsel, JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_le, + COMMUTATOR = '>=', NEGATOR = '>', + RESTRICT = scalarltsel, JOIN = scalarltjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_gt, + COMMUTATOR = '<', NEGATOR = '<=', + RESTRICT = scalargtsel, JOIN = scalargtjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_ge, + COMMUTATOR = '<=', NEGATOR = '<', + RESTRICT = scalargtsel, JOIN = scalargtjoinsel +); + +CREATE OPERATOR << ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_left, + COMMUTATOR = '>>', + RESTRICT = positionsel, JOIN = positionjoinsel +); + +CREATE OPERATOR &< ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_over_left, + COMMUTATOR = '&>', + RESTRICT = positionsel, JOIN = positionjoinsel +); + +CREATE OPERATOR && ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_overlap, + COMMUTATOR = '&&', + RESTRICT = positionsel, JOIN = positionjoinsel +); + +CREATE OPERATOR &> ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_over_right, + COMMUTATOR = '&<', + RESTRICT = positionsel, JOIN = positionjoinsel +); + +CREATE OPERATOR >> ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_right, + COMMUTATOR = '<<', + RESTRICT = positionsel, JOIN = positionjoinsel +); + +CREATE OPERATOR = ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_same, + COMMUTATOR = '=', NEGATOR = '<>', + RESTRICT = eqsel, JOIN = eqjoinsel, + SORT1 = '<', SORT2 = '<' +); + +CREATE OPERATOR <> ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_different, + COMMUTATOR = '<>', NEGATOR = '=', + RESTRICT = neqsel, JOIN = neqjoinsel +); + +CREATE OPERATOR @ ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_contains, + COMMUTATOR = '~', + RESTRICT = contsel, JOIN = contjoinsel +); + +CREATE OPERATOR ~ ( + LEFTARG = seg, RIGHTARG = seg, PROCEDURE = seg_contained, + COMMUTATOR = '@', + RESTRICT = contsel, JOIN = contjoinsel +); + + +-- define the GiST support methods +CREATE FUNCTION gseg_consistent(opaque,seg,int4) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +CREATE FUNCTION gseg_compress(opaque) RETURNS opaque + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +CREATE FUNCTION gseg_decompress(opaque) RETURNS opaque + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +CREATE FUNCTION gseg_penalty(opaque,opaque,opaque) RETURNS opaque + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +CREATE FUNCTION gseg_picksplit(opaque, opaque) RETURNS opaque + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +CREATE FUNCTION gseg_union(bytea, opaque) RETURNS seg + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + +CREATE FUNCTION gseg_same(seg, seg, opaque) RETURNS opaque + AS 'MODULE_PATHNAME' LANGUAGE 'c'; + + +-- register the default opclass for indexing +INSERT INTO pg_opclass (opcname, opcdeftype) + SELECT 'gist_seg_ops', oid + FROM pg_type + WHERE typname = 'seg'; + + +-- get the comparators for segments and store them in a tmp table +SELECT o.oid AS opoid, o.oprname +INTO TABLE seg_ops_tmp +FROM pg_operator o, pg_type t +WHERE o.oprleft = t.oid and o.oprright = t.oid + and t.typname = 'seg'; + +-- make sure we have the right operators +-- SELECT * from seg_ops_tmp; + +-- using the tmp table, generate the amop entries + +-- seg_left +INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) + SELECT am.oid, opcl.oid, c.opoid, 1 + FROM pg_am am, pg_opclass opcl, seg_ops_tmp c + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and c.oprname = '<<'; + +-- seg_overleft +INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) + SELECT am.oid, opcl.oid, c.opoid, 2 + FROM pg_am am, pg_opclass opcl, seg_ops_tmp c + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and c.oprname = '&<'; + +-- seg_overlap +INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) + SELECT am.oid, opcl.oid, c.opoid, 3 + FROM pg_am am, pg_opclass opcl, seg_ops_tmp c + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and c.oprname = '&&'; + +-- seg_overright +INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) + SELECT am.oid, opcl.oid, c.opoid, 4 + FROM pg_am am, pg_opclass opcl, seg_ops_tmp c + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and c.oprname = '&>'; + +-- seg_right +INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) + SELECT am.oid, opcl.oid, c.opoid, 5 + FROM pg_am am, pg_opclass opcl, seg_ops_tmp c + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and c.oprname = '>>'; + +-- seg_same +INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) + SELECT am.oid, opcl.oid, c.opoid, 6 + FROM pg_am am, pg_opclass opcl, seg_ops_tmp c + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and c.oprname = '='; + +-- seg_contains +INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) + SELECT am.oid, opcl.oid, c.opoid, 7 + FROM pg_am am, pg_opclass opcl, seg_ops_tmp c + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and c.oprname = '@'; + +-- seg_contained +INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) + SELECT am.oid, opcl.oid, c.opoid, 8 + FROM pg_am am, pg_opclass opcl, seg_ops_tmp c + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and c.oprname = '~'; + +DROP TABLE seg_ops_tmp; + + +-- add the entries to amproc for the support methods +-- note the amprocnum numbers associated with each are specific! + +INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) + SELECT am.oid, opcl.oid, pro.oid, 1 + FROM pg_am am, pg_opclass opcl, pg_proc pro + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and proname = 'gseg_consistent'; + +INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) + SELECT am.oid, opcl.oid, pro.oid, 2 + FROM pg_am am, pg_opclass opcl, pg_proc pro + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and proname = 'gseg_union'; + +INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) + SELECT am.oid, opcl.oid, pro.oid, 3 + FROM pg_am am, pg_opclass opcl, pg_proc pro + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and proname = 'gseg_compress'; + +INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) + SELECT am.oid, opcl.oid, pro.oid, 4 + FROM pg_am am, pg_opclass opcl, pg_proc pro + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and proname = 'gseg_decompress'; + +INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) + SELECT am.oid, opcl.oid, pro.oid, 5 + FROM pg_am am, pg_opclass opcl, pg_proc pro + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and proname = 'gseg_penalty'; + +INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) + SELECT am.oid, opcl.oid, pro.oid, 6 + FROM pg_am am, pg_opclass opcl, pg_proc pro + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and proname = 'gseg_picksplit'; + +INSERT INTO pg_amproc (amid, amopclaid, amproc, amprocnum) + SELECT am.oid, opcl.oid, pro.oid, 7 + FROM pg_am am, pg_opclass opcl, pg_proc pro + WHERE amname = 'gist' and opcname = 'gist_seg_ops' + and proname = 'gseg_same'; + +END TRANSACTION; diff --git a/contrib/seg/segdata.h b/contrib/seg/segdata.h new file mode 100644 index 0000000000..709f576340 --- /dev/null +++ b/contrib/seg/segdata.h @@ -0,0 +1,8 @@ +typedef struct SEG { + float lower; + float upper; + char l_sigd; + char u_sigd; + char l_ext; + char u_ext; +} SEG; diff --git a/contrib/seg/segparse.y b/contrib/seg/segparse.y new file mode 100644 index 0000000000..adce19c517 --- /dev/null +++ b/contrib/seg/segparse.y @@ -0,0 +1,183 @@ +%{ +#define YYERROR_VERBOSE +#define YYPARSE_PARAM result /* need this to pass a pointer (void *) to yyparse */ + +#include +#include +#include +#include "segdata.h" +#include "buffer.h" + +#include "postgres.h" +#include "utils/elog.h" + +#undef yylex /* falure to redefine yylex will result in calling the */ +#define yylex seg_yylex /* wrong scanner when running inside postgres backend */ + + extern int errno; + extern int yylex(); /* defined as seg_yylex in segscan.c */ + extern int significant_digits( char *str ); /* defined in seg.c */ + + int seg_yyerror( char *msg ); + int seg_yyparse( void *result ); + + float seg_atof( char *value ); + +#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) +#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) +#define ABS(X) ((X) < 0 ? (-X) : (X)) + + long threshold; + char strbuf[25] = { + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', + '0', '0', '0', '0', '\0' + }; + +%} + +/* BISON Declarations */ +%union { + struct BND { + float val; + char ext; + char sigd; + } bnd; + char * text; +} +%token FLOAT +%token RANGE +%token PLUMIN +%token EXTENSION +%type boundary +%type deviation +%start range + +/* Grammar follows */ +%% + + +range: + boundary PLUMIN deviation { + ((SEG *)result)->lower = $1.val - $3.val; + ((SEG *)result)->upper = $1.val + $3.val; + sprintf(strbuf, "%g", ((SEG *)result)->lower); + ((SEG *)result)->l_sigd = MAX(MIN(6, significant_digits(strbuf)), MAX($1.sigd, $3.sigd)); + sprintf(strbuf, "%g", ((SEG *)result)->upper); + ((SEG *)result)->u_sigd = MAX(MIN(6, significant_digits(strbuf)), MAX($1.sigd, $3.sigd)); + ((SEG *)result)->l_ext = '\0'; + ((SEG *)result)->u_ext = '\0'; + } + | + boundary RANGE boundary { + ((SEG *)result)->lower = $1.val; + ((SEG *)result)->upper = $3.val; + if ( ((SEG *)result)->lower > ((SEG *)result)->upper ) { + reset_parse_buffer(); + elog(ERROR, "swapped boundaries: %g is greater than %g", ((SEG *)result)->lower, ((SEG *)result)->upper ); + YYERROR; + } + ((SEG *)result)->l_sigd = $1.sigd; + ((SEG *)result)->u_sigd = $3.sigd; + ((SEG *)result)->l_ext = ( $1.ext ? $1.ext : '\0' ); + ((SEG *)result)->u_ext = ( $3.ext ? $3.ext : '\0' ); + } + | + boundary RANGE { + ((SEG *)result)->lower = $1.val; + ((SEG *)result)->upper = HUGE; + ((SEG *)result)->l_sigd = $1.sigd; + ((SEG *)result)->u_sigd = 0; + ((SEG *)result)->l_ext = ( $1.ext ? $1.ext : '\0' ); + ((SEG *)result)->u_ext = '-'; + } + ; + | + RANGE boundary { + ((SEG *)result)->lower = -HUGE; + ((SEG *)result)->upper = $2.val; + ((SEG *)result)->l_sigd = 0; + ((SEG *)result)->u_sigd = $2.sigd; + ((SEG *)result)->l_ext = '-'; + ((SEG *)result)->u_ext = ( $2.ext ? $2.ext : '\0' ); + } + | + boundary { + ((SEG *)result)->lower = ((SEG *)result)->upper = $1.val; + ((SEG *)result)->l_sigd = ((SEG *)result)->u_sigd = $1.sigd; + ((SEG *)result)->l_ext = ((SEG *)result)->u_ext = ( $1.ext ? $1.ext : '\0' ); + } + ; + +boundary: + FLOAT { + $$.ext = '\0'; + $$.sigd = significant_digits($1); + $$.val = seg_atof($1); + } + | + EXTENSION FLOAT { + $$.ext = $1[0]; + $$.sigd = significant_digits($2); + $$.val = seg_atof($2); + } + ; + +deviation: + FLOAT { + $$.ext = '\0'; + $$.sigd = significant_digits($1); + $$.val = seg_atof($1); + } + ; + +%% + + +float seg_atof ( char *value ) { + float result; + char *buf = (char *) palloc(256); + + errno = 0; + sscanf(value, "%f", &result); + + if ( errno ) { + sprintf(buf, "numeric value %s unrepresentable", value); + reset_parse_buffer(); + elog(ERROR, buf); + } + + return result; +} + + +int seg_yyerror ( char *msg ) { + char *buf = (char *) palloc(256); + int position; + + yyclearin; + + if ( !strcmp(msg, "parse error, expecting `$'") ) { + msg = "expecting end of input"; + } + + position = parse_buffer_pos() > parse_buffer_size() ? parse_buffer_pos() - 1 : parse_buffer_pos(); + + sprintf( + buf, + "%s at or near position %d, character ('%c', \\%03o), input: '%s'\n", + msg, + position, + parse_buffer()[position - 1], + parse_buffer()[position - 1], + parse_buffer() + ); + + reset_parse_buffer(); + elog(ERROR, buf); + return 0; +} + + diff --git a/contrib/seg/segscan.l b/contrib/seg/segscan.l new file mode 100644 index 0000000000..ea9032685a --- /dev/null +++ b/contrib/seg/segscan.l @@ -0,0 +1,53 @@ +%{ +/* +** A scanner for EMP-style numeric ranges +*/ + +#include +#include +#include "segparse.h" +#include "buffer.h" + +#define YY_NO_UNPUT 1 +#undef yywrap + +/* flex screws a couple symbols when used with the -P otion; fix those */ +#define YY_DECL int seg_yylex YY_PROTO(( void )); \ +int seg_yylex YY_PROTO(( void )) +#define yylval seg_yylval + +/* redefined YY_INPUT reads byte-wise from the memory area defined in buffer.c */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ +{ \ + int c = read_parse_buffer(); \ + result = (c == '\0') ? YY_NULL : (buf[0] = c, 1); \ +} + +void seg_flush_scanner_buffer(void); +%} + +range (\.\.)(\.)? +plumin (\'\+\-\')|(\(\+\-)\) +integer [+-]?[0-9]+ +real [+-]?[0-9]+\.[0-9]+ +float ({integer}|{real})([eE]{integer})? + +%% + +{range} yylval.text = yytext; return RANGE; +{plumin} yylval.text = yytext; return PLUMIN; +{float} yylval.text = yytext; return FLOAT; +\< yylval.text = "<"; return EXTENSION; +\> yylval.text = ">"; return EXTENSION; +\~ yylval.text = "~"; return EXTENSION; +[ ]+ /* discard spaces */ +. return yytext[0]; /* alert parser of the garbage */ + +%% + +int seg_yylex(); + +void seg_flush_scanner_buffer(void) { + YY_FLUSH_BUFFER; +} diff --git a/contrib/seg/sort-segments.pl b/contrib/seg/sort-segments.pl new file mode 100755 index 0000000000..1205d3b972 --- /dev/null +++ b/contrib/seg/sort-segments.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl + +# this script will sort any table with the segment data type in its last column + +while (<>) { + chomp; + push @rows, $_; +} + +foreach ( sort { + @ar = split("\t", $a); + $valA = pop @ar; + $valA =~ s/[~<> ]+//g; + @ar = split("\t", $b); + $valB = pop @ar; + $valB =~ s/[~<> ]+//g; + $valA <=> $valB +} @rows ) { + print "$_\n";; +} diff --git a/contrib/seg/sql/seg.sql b/contrib/seg/sql/seg.sql new file mode 100644 index 0000000000..95394c95d0 --- /dev/null +++ b/contrib/seg/sql/seg.sql @@ -0,0 +1,223 @@ +-- +-- Test seg datatype +-- + +-- +-- first, define the datatype. Turn off echoing so that expected file +-- does not depend on contents of seg.sql. +-- +\set ECHO none +\i seg.sql +\set ECHO all + +-- +-- testing the input and output functions +-- + +-- Any number +SELECT '1'::seg AS seg; +SELECT '-1'::seg AS seg; +SELECT '1.0'::seg AS seg; +SELECT '-1.0'::seg AS seg; +SELECT '1e7'::seg AS seg; +SELECT '-1e7'::seg AS seg; +SELECT '1.0e7'::seg AS seg; +SELECT '-1.0e7'::seg AS seg; +SELECT '1e+7'::seg AS seg; +SELECT '-1e+7'::seg AS seg; +SELECT '1.0e+7'::seg AS seg; +SELECT '-1.0e+7'::seg AS seg; +SELECT '1e-7'::seg AS seg; +SELECT '-1e-7'::seg AS seg; +SELECT '1.0e-7'::seg AS seg; +SELECT '-1.0e-7'::seg AS seg; +SELECT '2e-6'::seg AS seg; +SELECT '2e-5'::seg AS seg; +SELECT '2e-4'::seg AS seg; +SELECT '2e-3'::seg AS seg; +SELECT '2e-2'::seg AS seg; +SELECT '2e-1'::seg AS seg; +SELECT '2e-0'::seg AS seg; +SELECT '2e+0'::seg AS seg; +SELECT '2e+1'::seg AS seg; +SELECT '2e+2'::seg AS seg; +SELECT '2e+3'::seg AS seg; +SELECT '2e+4'::seg AS seg; +SELECT '2e+5'::seg AS seg; +SELECT '2e+6'::seg AS seg; + + +-- Significant digits preserved +SELECT '1'::seg AS seg; +SELECT '1.0'::seg AS seg; +SELECT '1.00'::seg AS seg; +SELECT '1.000'::seg AS seg; +SELECT '1.0000'::seg AS seg; +SELECT '1.00000'::seg AS seg; +SELECT '1.000000'::seg AS seg; +SELECT '0.000000120'::seg AS seg; +SELECT '3.400e5'::seg AS seg; + +-- Digits truncated +SELECT '12.34567890123456'::seg AS seg; + +-- Numbers with certainty indicators +SELECT '~6.5'::seg AS seg; +SELECT '<6.5'::seg AS seg; +SELECT '>6.5'::seg AS seg; +SELECT '~ 6.5'::seg AS seg; +SELECT '< 6.5'::seg AS seg; +SELECT '> 6.5'::seg AS seg; + +-- Open intervals +SELECT '0..'::seg AS seg; +SELECT '0...'::seg AS seg; +SELECT '0 ..'::seg AS seg; +SELECT '0 ...'::seg AS seg; +SELECT '..0'::seg AS seg; +SELECT '...0'::seg AS seg; +SELECT '.. 0'::seg AS seg; +SELECT '... 0'::seg AS seg; + +-- Finite intervals +SELECT '0 .. 1'::seg AS seg; +SELECT '-1 .. 0'::seg AS seg; +SELECT '-1 .. 1'::seg AS seg; + +-- (+/-) intervals +SELECT '0(+-)1'::seg AS seg; +SELECT '0(+-)1.0'::seg AS seg; +SELECT '1.0(+-)0.005'::seg AS seg; +SELECT '101(+-)1'::seg AS seg; +-- incorrect number of significant digits in 99.0: +SELECT '100(+-)1'::seg AS seg; + +-- invalid input +SELECT ''::seg AS seg; +SELECT 'ABC'::seg AS seg; +SELECT '1ABC'::seg AS seg; +SELECT '1.'::seg AS seg; +SELECT '1.....'::seg AS seg; +SELECT '.1'::seg AS seg; +SELECT '1..2.'::seg AS seg; +SELECT '1 e7'::seg AS seg; +SELECT '1e700'::seg AS seg; + +-- +-- testing the operators +-- + +-- equality/inequality: +-- +SELECT '24 .. 33.20'::seg = '24 .. 33.20'::seg AS bool; +SELECT '24 .. 33.20'::seg = '24 .. 33.21'::seg AS bool; +SELECT '24 .. 33.20'::seg != '24 .. 33.20'::seg AS bool; +SELECT '24 .. 33.20'::seg != '24 .. 33.21'::seg AS bool; + +-- overlap +-- +SELECT '1'::seg && '1'::seg AS bool; +SELECT '1'::seg && '2'::seg AS bool; +SELECT '0 ..'::seg && '0 ..'::seg AS bool; +SELECT '0 .. 1'::seg && '0 .. 1'::seg AS bool; +SELECT '..0'::seg && '0..'::seg AS bool; +SELECT '-1 .. 0.1'::seg && '0 .. 1'::seg AS bool; +SELECT '-1 .. 0'::seg && '0 .. 1'::seg AS bool; +SELECT '-1 .. -0.0001'::seg && '0 .. 1'::seg AS bool; +SELECT '0 ..'::seg && '1'::seg AS bool; +SELECT '0 .. 1'::seg && '1'::seg AS bool; +SELECT '0 .. 1'::seg && '2'::seg AS bool; +SELECT '0 .. 2'::seg && '1'::seg AS bool; +SELECT '1'::seg && '0 .. 1'::seg AS bool; +SELECT '2'::seg && '0 .. 1'::seg AS bool; +SELECT '1'::seg && '0 .. 2'::seg AS bool; + +-- overlap on the left +-- +SELECT '1'::seg &< '0'::seg AS bool; +SELECT '1'::seg &< '1'::seg AS bool; +SELECT '1'::seg &< '2'::seg AS bool; +SELECT '0 .. 1'::seg &< '0'::seg AS bool; +SELECT '0 .. 1'::seg &< '1'::seg AS bool; +SELECT '0 .. 1'::seg &< '2'::seg AS bool; +SELECT '0 .. 1'::seg &< '0 .. 0.5'::seg AS bool; +SELECT '0 .. 1'::seg &< '0 .. 1'::seg AS bool; +SELECT '0 .. 1'::seg &< '0 .. 2'::seg AS bool; +SELECT '0 .. 1'::seg &< '1 .. 2'::seg AS bool; +SELECT '0 .. 1'::seg &< '2 .. 3'::seg AS bool; + +-- overlap on the right +-- +SELECT '0'::seg &> '1'::seg AS bool; +SELECT '1'::seg &> '1'::seg AS bool; +SELECT '2'::seg &> '1'::seg AS bool; +SELECT '0'::seg &> '0 .. 1'::seg AS bool; +SELECT '1'::seg &> '0 .. 1'::seg AS bool; +SELECT '2'::seg &> '0 .. 1'::seg AS bool; +SELECT '0 .. 0.5'::seg &> '0 .. 1'::seg AS bool; +SELECT '0 .. 1'::seg &> '0 .. 1'::seg AS bool; +SELECT '0 .. 2'::seg &> '0 .. 2'::seg AS bool; +SELECT '1 .. 2'::seg &> '0 .. 1'::seg AS bool; +SELECT '2 .. 3'::seg &> '0 .. 1'::seg AS bool; + +-- left +-- +SELECT '1'::seg << '0'::seg AS bool; +SELECT '1'::seg << '1'::seg AS bool; +SELECT '1'::seg << '2'::seg AS bool; +SELECT '0 .. 1'::seg << '0'::seg AS bool; +SELECT '0 .. 1'::seg << '1'::seg AS bool; +SELECT '0 .. 1'::seg << '2'::seg AS bool; +SELECT '0 .. 1'::seg << '0 .. 0.5'::seg AS bool; +SELECT '0 .. 1'::seg << '0 .. 1'::seg AS bool; +SELECT '0 .. 1'::seg << '0 .. 2'::seg AS bool; +SELECT '0 .. 1'::seg << '1 .. 2'::seg AS bool; +SELECT '0 .. 1'::seg << '2 .. 3'::seg AS bool; + +-- right +-- +SELECT '0'::seg >> '1'::seg AS bool; +SELECT '1'::seg >> '1'::seg AS bool; +SELECT '2'::seg >> '1'::seg AS bool; +SELECT '0'::seg >> '0 .. 1'::seg AS bool; +SELECT '1'::seg >> '0 .. 1'::seg AS bool; +SELECT '2'::seg >> '0 .. 1'::seg AS bool; +SELECT '0 .. 0.5'::seg >> '0 .. 1'::seg AS bool; +SELECT '0 .. 1'::seg >> '0 .. 1'::seg AS bool; +SELECT '0 .. 2'::seg >> '0 .. 2'::seg AS bool; +SELECT '1 .. 2'::seg >> '0 .. 1'::seg AS bool; +SELECT '2 .. 3'::seg >> '0 .. 1'::seg AS bool; + + +-- "contained in" (the left value belongs within the interval specified in the right value): +-- +SELECT '0'::seg ~ '0'::seg AS bool; +SELECT '0'::seg ~ '0 ..'::seg AS bool; +SELECT '0'::seg ~ '.. 0'::seg AS bool; +SELECT '0'::seg ~ '-1 .. 1'::seg AS bool; +SELECT '0'::seg ~ '-1 .. 1'::seg AS bool; +SELECT '-1'::seg ~ '-1 .. 1'::seg AS bool; +SELECT '1'::seg ~ '-1 .. 1'::seg AS bool; +SELECT '-1 .. 1'::seg ~ '-1 .. 1'::seg AS bool; + +-- "contains" (the left value contains the interval specified in the right value): +-- +SELECT '0'::seg @ '0'::seg AS bool; +SELECT '0 .. '::seg ~ '0'::seg AS bool; +SELECT '.. 0'::seg ~ '0'::seg AS bool; +SELECT '-1 .. 1'::seg ~ '0'::seg AS bool; +SELECT '0'::seg ~ '-1 .. 1'::seg AS bool; +SELECT '-1'::seg ~ '-1 .. 1'::seg AS bool; +SELECT '1'::seg ~ '-1 .. 1'::seg AS bool; + +-- Load some example data and build the index +-- +CREATE TABLE test_seg (s seg); + +\copy test_seg from 'data/test_seg.data' + +CREATE INDEX test_seg_ix ON test_seg USING gist (s); +SELECT count(*) FROM test_seg WHERE s @ '11..11.3'; + +-- Test sorting +SELECT * FROM test_seg WHERE s @ '11..11.3' GROUP BY s;