mirror of https://github.com/postgres/postgres
parent
5bb4f723d2
commit
9892ddf5ee
@ -0,0 +1,83 @@ |
||||
#
|
||||
# $Header: /cvsroot/pgsql/contrib/cube/Makefile,v 1.1 2000/12/11 20:39:14 tgl Exp $
|
||||
#
|
||||
|
||||
subdir = contrib/cube
|
||||
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= cube
|
||||
SO_MAJOR_VERSION= 1
|
||||
SO_MINOR_VERSION= 0
|
||||
|
||||
override CPPFLAGS += -I$(srcdir)
|
||||
|
||||
OBJS= cube.o cubeparse.o cubescan.o buffer.o
|
||||
|
||||
all: all-lib $(NAME).sql |
||||
|
||||
# Shared library stuff
|
||||
include $(top_srcdir)/src/Makefile.shlib |
||||
|
||||
|
||||
cubeparse.c cubeparse.h: cubeparse.y |
||||
$(YACC) -d $(YFLAGS) -p cube_yy $<
|
||||
mv -f y.tab.c cubeparse.c
|
||||
mv -f y.tab.h cubeparse.h
|
||||
|
||||
cubescan.c: cubescan.l |
||||
ifdef FLEX |
||||
$(FLEX) $(FLEXFLAGS) -Pcube_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 cube
|
||||
|
||||
# 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 cubeparse.c cubeparse.h cubescan.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 |
@ -0,0 +1,289 @@ |
||||
This directory contains the code for the user-defined type, |
||||
CUBE, representing multidimensional cubes. |
||||
|
||||
|
||||
FILES |
||||
----- |
||||
|
||||
Makefile building instructions for the shared library |
||||
|
||||
README.cube the file you are now reading |
||||
|
||||
buffer.c globals and buffer access utilities shared between |
||||
the parser (cubeparse.y) and the scanner (cubescan.l) |
||||
|
||||
buffer.h function prototypes for buffer.c |
||||
|
||||
cube.c the implementation of this data type in c |
||||
|
||||
cube.sql.in SQL code needed to register this type with postgres |
||||
(transformed to cube.sql by make) |
||||
|
||||
cubedata.h the data structure used to store the cubes |
||||
|
||||
cubeparse.y the grammar file for the parser (used by cube_in() in cube.c) |
||||
|
||||
cubescan.l scanner rules (used by cube_yyparse() in cubeparse.y) |
||||
|
||||
|
||||
INSTALLATION |
||||
============ |
||||
|
||||
To install the type, run |
||||
|
||||
make |
||||
make install |
||||
|
||||
For this to work, make sure that: |
||||
|
||||
. the cube 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 < cube.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 following are valid external representations for the CUBE type: |
||||
|
||||
'x' A floating point value representing |
||||
a one-dimensional point or one-dimensional |
||||
zero length cubement |
||||
|
||||
'(x)' Same as above |
||||
|
||||
'x1,x2,x3,...,xn' A point in n-dimensional space, |
||||
represented internally as a zero volume box |
||||
|
||||
'(x1,x2,x3,...,xn)' Same as above |
||||
|
||||
'(x),(y)' 1-D cubement starting at x and ending at y |
||||
or vice versa; the order does not matter |
||||
|
||||
'(x1,...,xn),(y1,...,yn)' n-dimensional box represented by |
||||
a pair of its opposite corners, no matter which. |
||||
Functions take care of swapping to achieve |
||||
"lower left -- upper right" representation |
||||
before computing any values |
||||
|
||||
Grammar |
||||
------- |
||||
|
||||
rule 1 box -> O_BRACKET paren_list COMMA paren_list C_BRACKET |
||||
rule 2 box -> paren_list COMMA paren_list |
||||
rule 3 box -> paren_list |
||||
rule 4 box -> list |
||||
rule 5 paren_list -> O_PAREN list C_PAREN |
||||
rule 6 list -> FLOAT |
||||
rule 7 list -> list COMMA FLOAT |
||||
|
||||
Tokens |
||||
------ |
||||
|
||||
n [0-9]+ |
||||
integer [+-]?{n} |
||||
real [+-]?({n}\.{n}?)|(\.{n}) |
||||
FLOAT ({integer}|{real})([eE]{integer})? |
||||
O_BRACKET \[ |
||||
C_BRACKET \] |
||||
O_PAREN \( |
||||
C_PAREN \) |
||||
COMMA \, |
||||
|
||||
|
||||
Examples of valid CUBE representations: |
||||
-------------------------------------- |
||||
|
||||
'x' A floating point value representing |
||||
a one-dimensional point (or, zero-length |
||||
one-dimensional interval) |
||||
|
||||
'(x)' Same as above |
||||
|
||||
'x1,x2,x3,...,xn' A point in n-dimensional space, |
||||
represented internally as a zero volume cube |
||||
|
||||
'(x1,x2,x3,...,xn)' Same as above |
||||
|
||||
'(x),(y)' A 1-D interval starting at x and ending at y |
||||
or vice versa; the order does not matter |
||||
|
||||
'[(x),(y)]' Same as above |
||||
|
||||
'(x1,...,xn),(y1,...,yn)' An n-dimensional box represented by |
||||
a pair of its diagonally opposite corners, |
||||
regardless of order. Swapping is provided |
||||
by all comarison routines to ensure the |
||||
"lower left -- upper right" representation |
||||
before actaul comparison takes place. |
||||
|
||||
'[(x1,...,xn),(y1,...,yn)]' Same as above |
||||
|
||||
|
||||
White space is ignored, so '[(x),(y)]' can be: '[ ( x ), ( y ) ]' |
||||
|
||||
|
||||
DEFAULTS |
||||
======== |
||||
|
||||
I believe this union: |
||||
|
||||
select cube_union('(0,5,2),(2,3,1)','0'); |
||||
cube_union |
||||
------------------- |
||||
(0, 0, 0),(2, 5, 2) |
||||
(1 row) |
||||
|
||||
does not contradict to the common sense, neither does the intersection |
||||
|
||||
select cube_inter('(0,-1),(1,1)','(-2),(2)'); |
||||
cube_inter |
||||
------------- |
||||
(0, 0),(1, 0) |
||||
(1 row) |
||||
|
||||
In all binary operations on differently sized boxes, I assume the smaller |
||||
one to be a cartesian projection, i. e., having zeroes in place of coordinates |
||||
omitted in the string representation. The above examples are equivalent to: |
||||
|
||||
cube_union('(0,5,2),(2,3,1)','(0,0,0),(0,0,0)'); |
||||
cube_inter('(0,-1),(1,1)','(-2,0),(2,0)'); |
||||
|
||||
|
||||
The following containment predicate uses the point syntax, |
||||
while in fact the second argument is internally represented by a box. |
||||
This syntax makes it unnecessary to define the special Point type |
||||
and functions for (box,point) predicates. |
||||
|
||||
select cube_contains('(0,0),(1,1)', '0.5,0.5'); |
||||
cube_contains |
||||
-------------- |
||||
t |
||||
(1 row) |
||||
|
||||
|
||||
PRECISION |
||||
========= |
||||
|
||||
Values are stored internally as 32-bit floating point numbers. This means that |
||||
numbers with more than 7 significant digits will be truncated. |
||||
|
||||
|
||||
USAGE |
||||
===== |
||||
|
||||
The access method for CUBE is a GiST (gist_cube_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/seg). |
||||
|
||||
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 cubement [a, b] overlaps the cubement [c, d] in such a way |
||||
that a <= c <= b and b <= d |
||||
|
||||
[a, b] &> [c, d] Over right |
||||
|
||||
The cubement [a, b] overlaps the cubement [c, d] in such a way |
||||
that a > c and b <= c <= d |
||||
|
||||
[a, b] = [c, d] Same as |
||||
|
||||
The cubements [a, b] and [c, d] are identical, that is, a == b |
||||
and c == d |
||||
|
||||
[a, b] @ [c, d] Contains |
||||
|
||||
The cubement [a, b] contains the cubement [c, d], that is, |
||||
a <= c and b >= d |
||||
|
||||
[a, b] @ [c, d] Contained in |
||||
|
||||
The cubement [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 cube.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/cube.sql |
||||
|
||||
|
||||
CREDITS |
||||
======= |
||||
|
||||
This code is essentially based on the example written for |
||||
Illustra, http://garcia.me.berkeley.edu/~adong/rtree |
||||
|
||||
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/), and to his former student, Andy Dong |
||||
(http://best.me.berkeley.edu/~adong/), for his exemplar. |
||||
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 |
@ -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 cube_flush_scanner_buffer(void); /* defined in cubescan.l */ |
||||
|
||||
void set_parse_buffer( char* s ) |
||||
{ |
||||
PARSE_BUFFER = s; |
||||
PARSE_BUFFER_SIZE = strlen(s); |
||||
if ( PARSE_BUFFER_SIZE == 0 ) { |
||||
elog(ERROR, "cube_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; |
||||
cube_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; |
||||
} |
||||
|
||||
|
@ -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 ); |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,337 @@ |
||||
-- Create the user-defined type for N-dimensional boxes |
||||
-- |
||||
BEGIN TRANSACTION; |
||||
|
||||
CREATE FUNCTION cube_in(opaque) |
||||
RETURNS opaque |
||||
AS 'MODULE_PATHNAME' |
||||
LANGUAGE 'c'; |
||||
|
||||
CREATE FUNCTION cube_out(opaque) |
||||
RETURNS opaque |
||||
AS 'MODULE_PATHNAME' |
||||
LANGUAGE 'c'; |
||||
|
||||
CREATE TYPE cube ( |
||||
internallength = variable, |
||||
input = cube_in, |
||||
output = cube_out |
||||
); |
||||
|
||||
COMMENT ON TYPE cube IS |
||||
'multi-dimensional cube ''(FLOAT-1, FLOAT-2, ..., FLOAT-N), (FLOAT-1, FLOAT-2, ..., FLOAT-N)'''; |
||||
|
||||
-- |
||||
-- External C-functions for R-tree methods |
||||
-- |
||||
|
||||
-- Left/Right methods |
||||
|
||||
CREATE FUNCTION cube_over_left(cube, cube) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
COMMENT ON FUNCTION cube_over_left(cube, cube) IS |
||||
'is over and left of (NOT IMPLEMENTED)'; |
||||
|
||||
CREATE FUNCTION cube_over_right(cube, cube) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
COMMENT ON FUNCTION cube_over_right(cube, cube) IS |
||||
'is over and right of (NOT IMPLEMENTED)'; |
||||
|
||||
CREATE FUNCTION cube_left(cube, cube) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
COMMENT ON FUNCTION cube_left(cube, cube) IS |
||||
'is left of (NOT IMPLEMENTED)'; |
||||
|
||||
CREATE FUNCTION cube_right(cube, cube) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
COMMENT ON FUNCTION cube_right(cube, cube) IS |
||||
'is right of (NOT IMPLEMENTED)'; |
||||
|
||||
|
||||
-- Comparison methods |
||||
|
||||
CREATE FUNCTION cube_lt(cube, cube) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
COMMENT ON FUNCTION cube_lt(cube, cube) IS |
||||
'lower than'; |
||||
|
||||
CREATE FUNCTION cube_gt(cube, cube) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
COMMENT ON FUNCTION cube_gt(cube, cube) IS |
||||
'greater than'; |
||||
|
||||
CREATE FUNCTION cube_contains(cube, cube) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
COMMENT ON FUNCTION cube_contains(cube, cube) IS |
||||
'contains'; |
||||
|
||||
CREATE FUNCTION cube_contained(cube, cube) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
COMMENT ON FUNCTION cube_contained(cube, cube) IS |
||||
'contained in'; |
||||
|
||||
CREATE FUNCTION cube_overlap(cube, cube) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
COMMENT ON FUNCTION cube_overlap(cube, cube) IS |
||||
'overlaps'; |
||||
|
||||
CREATE FUNCTION cube_same(cube, cube) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
COMMENT ON FUNCTION cube_same(cube, cube) IS |
||||
'same as'; |
||||
|
||||
CREATE FUNCTION cube_different(cube, cube) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
COMMENT ON FUNCTION cube_different(cube, cube) IS |
||||
'different'; |
||||
|
||||
-- support routines for indexing |
||||
|
||||
CREATE FUNCTION cube_union(cube, cube) RETURNS cube |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
CREATE FUNCTION cube_inter(cube, cube) RETURNS cube |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
CREATE FUNCTION cube_size(cube) RETURNS float4 |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
|
||||
-- Misc N-dimensional functions |
||||
|
||||
-- proximity routines |
||||
|
||||
CREATE FUNCTION cube_distance(cube, cube) RETURNS float4 |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
|
||||
-- |
||||
-- OPERATORS |
||||
-- |
||||
|
||||
CREATE OPERATOR < ( |
||||
LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_lt, |
||||
COMMUTATOR = '>', |
||||
RESTRICT = scalarltsel, JOIN = scalarltjoinsel |
||||
); |
||||
|
||||
CREATE OPERATOR > ( |
||||
LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_gt, |
||||
COMMUTATOR = '<', |
||||
RESTRICT = scalargtsel, JOIN = scalargtjoinsel |
||||
); |
||||
|
||||
CREATE OPERATOR << ( |
||||
LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_left, |
||||
COMMUTATOR = '>>', |
||||
RESTRICT = positionsel, JOIN = positionjoinsel |
||||
); |
||||
|
||||
CREATE OPERATOR &< ( |
||||
LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_over_left, |
||||
COMMUTATOR = '&>', |
||||
RESTRICT = positionsel, JOIN = positionjoinsel |
||||
); |
||||
|
||||
CREATE OPERATOR && ( |
||||
LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_overlap, |
||||
COMMUTATOR = '&&', |
||||
RESTRICT = positionsel, JOIN = positionjoinsel |
||||
); |
||||
|
||||
CREATE OPERATOR &> ( |
||||
LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_over_right, |
||||
COMMUTATOR = '&<', |
||||
RESTRICT = positionsel, JOIN = positionjoinsel |
||||
); |
||||
|
||||
CREATE OPERATOR >> ( |
||||
LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_right, |
||||
COMMUTATOR = '<<', |
||||
RESTRICT = positionsel, JOIN = positionjoinsel |
||||
); |
||||
|
||||
CREATE OPERATOR = ( |
||||
LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_same, |
||||
COMMUTATOR = '=', NEGATOR = '<>', |
||||
RESTRICT = eqsel, JOIN = eqjoinsel, |
||||
SORT1 = '<', SORT2 = '<' |
||||
); |
||||
|
||||
CREATE OPERATOR <> ( |
||||
LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_different, |
||||
COMMUTATOR = '<>', NEGATOR = '=', |
||||
RESTRICT = neqsel, JOIN = neqjoinsel |
||||
); |
||||
|
||||
CREATE OPERATOR @ ( |
||||
LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contains, |
||||
COMMUTATOR = '~', |
||||
RESTRICT = contsel, JOIN = contjoinsel |
||||
); |
||||
|
||||
CREATE OPERATOR ~ ( |
||||
LEFTARG = cube, RIGHTARG = cube, PROCEDURE = cube_contained, |
||||
COMMUTATOR = '@', |
||||
RESTRICT = contsel, JOIN = contjoinsel |
||||
); |
||||
|
||||
|
||||
-- define the GiST support methods |
||||
CREATE FUNCTION g_cube_consistent(opaque,cube,int4) RETURNS bool |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
CREATE FUNCTION g_cube_compress(opaque) RETURNS opaque |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
CREATE FUNCTION g_cube_decompress(opaque) RETURNS opaque |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
CREATE FUNCTION g_cube_penalty(opaque,opaque,opaque) RETURNS opaque |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
CREATE FUNCTION g_cube_picksplit(opaque, opaque) RETURNS opaque |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
CREATE FUNCTION g_cube_union(bytea, opaque) RETURNS cube |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
CREATE FUNCTION g_cube_same(cube, cube, opaque) RETURNS opaque |
||||
AS 'MODULE_PATHNAME' LANGUAGE 'c'; |
||||
|
||||
|
||||
-- register the default opclass for indexing |
||||
INSERT INTO pg_opclass (opcname, opcdeftype) |
||||
SELECT 'gist_cube_ops', oid |
||||
FROM pg_type |
||||
WHERE typname = 'cube'; |
||||
|
||||
|
||||
-- get the comparators for boxes and store them in a tmp table |
||||
SELECT o.oid AS opoid, o.oprname |
||||
INTO TABLE gist_cube_ops_tmp |
||||
FROM pg_operator o, pg_type t |
||||
WHERE o.oprleft = t.oid and o.oprright = t.oid |
||||
and t.typname = 'cube'; |
||||
|
||||
-- make sure we have the right operators |
||||
-- SELECT * from gist_cube_ops_tmp; |
||||
|
||||
-- using the tmp table, generate the amop entries |
||||
|
||||
-- cube_left |
||||
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) |
||||
SELECT am.oid, opcl.oid, c.opoid, 1 |
||||
FROM pg_am am, pg_opclass opcl, gist_cube_ops_tmp c |
||||
WHERE amname = 'gist' and opcname = 'gist_cube_ops' |
||||
and c.oprname = '<<'; |
||||
|
||||
-- cube_over_left |
||||
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) |
||||
SELECT am.oid, opcl.oid, c.opoid, 2 |
||||
FROM pg_am am, pg_opclass opcl, gist_cube_ops_tmp c |
||||
WHERE amname = 'gist' and opcname = 'gist_cube_ops' |
||||
and c.oprname = '&<'; |
||||
|
||||
-- cube_overlap |
||||
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) |
||||
SELECT am.oid, opcl.oid, c.opoid, 3 |
||||
FROM pg_am am, pg_opclass opcl, gist_cube_ops_tmp c |
||||
WHERE amname = 'gist' and opcname = 'gist_cube_ops' |
||||
and c.oprname = '&&'; |
||||
|
||||
-- cube_over_right |
||||
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) |
||||
SELECT am.oid, opcl.oid, c.opoid, 4 |
||||
FROM pg_am am, pg_opclass opcl, gist_cube_ops_tmp c |
||||
WHERE amname = 'gist' and opcname = 'gist_cube_ops' |
||||
and c.oprname = '&>'; |
||||
|
||||
-- cube_right |
||||
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) |
||||
SELECT am.oid, opcl.oid, c.opoid, 5 |
||||
FROM pg_am am, pg_opclass opcl, gist_cube_ops_tmp c |
||||
WHERE amname = 'gist' and opcname = 'gist_cube_ops' |
||||
and c.oprname = '>>'; |
||||
|
||||
-- cube_same |
||||
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) |
||||
SELECT am.oid, opcl.oid, c.opoid, 6 |
||||
FROM pg_am am, pg_opclass opcl, gist_cube_ops_tmp c |
||||
WHERE amname = 'gist' and opcname = 'gist_cube_ops' |
||||
and c.oprname = '='; |
||||
|
||||
-- cube_contains |
||||
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) |
||||
SELECT am.oid, opcl.oid, c.opoid, 7 |
||||
FROM pg_am am, pg_opclass opcl, gist_cube_ops_tmp c |
||||
WHERE amname = 'gist' and opcname = 'gist_cube_ops' |
||||
and c.oprname = '@'; |
||||
|
||||
-- cube_contained |
||||
INSERT INTO pg_amop (amopid, amopclaid, amopopr, amopstrategy) |
||||
SELECT am.oid, opcl.oid, c.opoid, 8 |
||||
FROM pg_am am, pg_opclass opcl, gist_cube_ops_tmp c |
||||
WHERE amname = 'gist' and opcname = 'gist_cube_ops' |
||||
and c.oprname = '~'; |
||||
|
||||
DROP TABLE gist_cube_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_cube_ops' |
||||
and proname = 'g_cube_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_cube_ops' |
||||
and proname = 'g_cube_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_cube_ops' |
||||
and proname = 'g_cube_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_cube_ops' |
||||
and proname = 'g_cube_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_cube_ops' |
||||
and proname = 'g_cube_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_cube_ops' |
||||
and proname = 'g_cube_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_cube_ops' |
||||
and proname = 'g_cube_same'; |
||||
|
||||
END TRANSACTION; |
@ -0,0 +1,7 @@ |
||||
/*#include "postgres.h"*/ |
||||
|
||||
typedef struct NDBOX { |
||||
unsigned int size; /* required to be a Postgres varlena type */ |
||||
unsigned int dim; |
||||
float x[1]; |
||||
} NDBOX; |
@ -0,0 +1,252 @@ |
||||
%{ |
||||
/* NdBox = [(lowerleft),(upperright)] */ |
||||
/* [(xLL(1)...xLL(N)),(xUR(1)...xUR(n))] */ |
||||
|
||||
#define YYERROR_VERBOSE |
||||
#define YYPARSE_PARAM result /* need this to pass a pointer (void *) to yyparse */ |
||||
#define YYSTYPE char * |
||||
#define YYDEBUG 1 |
||||
|
||||
#include <string.h> |
||||
#include "cubedata.h" |
||||
#include "buffer.h" |
||||
|
||||
#include "postgres.h" |
||||
#include "utils/palloc.h" |
||||
#include "utils/elog.h" |
||||
|
||||
#undef yylex /* falure to redefine yylex will result in a call to the */ |
||||
#define yylex cube_yylex /* wrong scanner when running inside the postgres backend */ |
||||
|
||||
extern int yylex(); /* defined as cube_yylex in cubescan.c */ |
||||
extern int errno; |
||||
|
||||
int cube_yyerror( char *msg ); |
||||
int cube_yyparse(void *result); |
||||
|
||||
static int delim_count(char *s, char delim); |
||||
static NDBOX * write_box(unsigned int dim, char *str1, char *str2); |
||||
static NDBOX * write_point_as_box(char *s); |
||||
|
||||
%} |
||||
|
||||
/* BISON Declarations */ |
||||
%token FLOAT O_PAREN C_PAREN O_BRACKET C_BRACKET COMMA |
||||
%start box |
||||
|
||||
/* Grammar follows */ |
||||
%% |
||||
|
||||
box: |
||||
O_BRACKET paren_list COMMA paren_list C_BRACKET { |
||||
|
||||
int dim; |
||||
int c = parse_buffer_curr_char(); |
||||
int pos = parse_buffer_pos(); |
||||
|
||||
/* We can't let the parser recognize more than one valid expression: |
||||
the job is done and memory is allocated. */ |
||||
if ( c != '\0' ) { |
||||
/* Not at EOF */ |
||||
reset_parse_buffer(); |
||||
elog(ERROR, "(0) bad cube representation; garbage at or before char %d, ('%c', \\%03o)\n", pos, c, c ); |
||||
YYERROR; |
||||
} |
||||
|
||||
dim = delim_count($2, ',') + 1; |
||||
if ( (delim_count($4, ',') + 1) != dim ) { |
||||
reset_parse_buffer(); |
||||
elog(ERROR, "(1) bad cube representation; different point dimensions in (%s) and (%s)\n", $2, $4); |
||||
YYABORT; |
||||
} |
||||
|
||||
*((void **)result) = write_box( dim, $2, $4 ); |
||||
|
||||
} |
||||
| |
||||
paren_list COMMA paren_list { |
||||
int dim; |
||||
int c = parse_buffer_curr_char(); |
||||
int pos = parse_buffer_pos(); |
||||
|
||||
if ( c != '\0' ) { /* Not at EOF */ |
||||
reset_parse_buffer(); |
||||
elog(ERROR, "(2) bad cube representation; garbage at or before char %d, ('%c', \\%03o)\n", pos, c, c ); |
||||
YYABORT; |
||||
} |
||||
|
||||
dim = delim_count($1, ',') + 1; |
||||
|
||||
if ( (delim_count($3, ',') + 1) != dim ) { |
||||
reset_parse_buffer(); |
||||
elog(ERROR, "(3) bad cube representation; different point dimensions in (%s) and (%s)\n", $1, $3); |
||||
YYABORT; |
||||
} |
||||
|
||||
*((void **)result) = write_box( dim, $1, $3 ); |
||||
} |
||||
| |
||||
|
||||
paren_list { |
||||
int c = parse_buffer_curr_char(); |
||||
int pos = parse_buffer_pos(); |
||||
|
||||
if ( c != '\0') { /* Not at EOF */ |
||||
reset_parse_buffer(); |
||||
elog(ERROR, "(4) bad cube representation; garbage at or before char %d, ('%c', \\%03o)\n", pos, c, c ); |
||||
YYABORT; |
||||
} |
||||
|
||||
if ( yychar != YYEOF) { |
||||
/* There's still a lookahead token to be parsed */ |
||||
reset_parse_buffer(); |
||||
elog(ERROR, "(5) bad cube representation; garbage at or before char %d, ('end of input', \\%03o)\n", pos, c); |
||||
YYABORT; |
||||
} |
||||
|
||||
*((void **)result) = write_point_as_box($1); |
||||
} |
||||
|
||||
| |
||||
|
||||
list { |
||||
int c = parse_buffer_curr_char(); |
||||
int pos = parse_buffer_pos(); |
||||
|
||||
if ( c != '\0') { /* Not at EOF */ |
||||
reset_parse_buffer(); |
||||
elog(ERROR, "(6) bad cube representation; garbage at or before char %d, ('%c', \\%03o)\n", pos, c, c); |
||||
YYABORT; |
||||
} |
||||
|
||||
if ( yychar != YYEOF) { |
||||
/* There's still a lookahead token to be parsed */ |
||||
reset_parse_buffer(); |
||||
elog(ERROR, "(7) bad cube representation; garbage at or before char %d, ('end of input', \\%03o)\n", pos, c); |
||||
YYABORT; |
||||
} |
||||
|
||||
*((void **)result) = write_point_as_box($1); |
||||
} |
||||
; |
||||
|
||||
paren_list: |
||||
O_PAREN list C_PAREN { |
||||
$$ = $2; |
||||
} |
||||
; |
||||
|
||||
list: |
||||
FLOAT { |
||||
$$ = palloc(strlen(parse_buffer()) + 1); |
||||
strcpy($$, $1); |
||||
} |
||||
| |
||||
list COMMA FLOAT { |
||||
$$ = $1; |
||||
strcat($$, ","); |
||||
strcat($$, $3); |
||||
} |
||||
; |
||||
|
||||
%% |
||||
|
||||
|
||||
int cube_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 before 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; |
||||
} |
||||
|
||||
static int |
||||
delim_count(char *s, char delim) |
||||
{ |
||||
int ndelim = 0; |
||||
|
||||
while ((s = strchr(s, delim)) != NULL) |
||||
{ |
||||
ndelim++; |
||||
s++; |
||||
} |
||||
return (ndelim); |
||||
} |
||||
|
||||
static NDBOX * |
||||
write_box(unsigned int dim, char *str1, char *str2) |
||||
{ |
||||
NDBOX * bp; |
||||
char * s; |
||||
int i; |
||||
int size = offsetof(NDBOX, x[0]) + sizeof(float) * dim * 2; |
||||
|
||||
bp = palloc(size); |
||||
bp->size = size; |
||||
bp->dim = dim; |
||||
|
||||
s = str1; |
||||
bp->x[i=0] = strtod(s, NULL); |
||||
while ((s = strchr(s, ',')) != NULL) { |
||||
s++; i++; |
||||
bp->x[i] = strtod(s, NULL); |
||||
} |
||||
|
||||
s = str2; |
||||
bp->x[i=dim] = strtod(s, NULL); |
||||
while ((s = strchr(s, ',')) != NULL) { |
||||
s++; i++; |
||||
bp->x[i] = strtod(s, NULL); |
||||
} |
||||
|
||||
return(bp); |
||||
} |
||||
|
||||
|
||||
static NDBOX * write_point_as_box(char *str) |
||||
{ |
||||
NDBOX * bp; |
||||
int i, size; |
||||
double x; |
||||
int dim = delim_count(str, ',') + 1; |
||||
char * s = str; |
||||
|
||||
size = offsetof(NDBOX, x[0]) + sizeof(float) * dim * 2; |
||||
|
||||
bp = palloc(size); |
||||
bp->size = size; |
||||
bp->dim = dim; |
||||
|
||||
i = 0; |
||||
x = strtod(s, NULL); |
||||
bp->x[0] = x; |
||||
bp->x[dim] = x; |
||||
while ((s = strchr(s, ',')) != NULL) { |
||||
s++; i++; |
||||
x = strtod(s, NULL); |
||||
bp->x[i] = x; |
||||
bp->x[i+dim] = x; |
||||
} |
||||
|
||||
return(bp); |
||||
} |
||||
|
@ -0,0 +1,54 @@ |
||||
%{ |
||||
/* |
||||
** A scanner for EMP-style numeric ranges |
||||
*/ |
||||
|
||||
#define YYSTYPE char * |
||||
#define yylval cube_yylval |
||||
|
||||
#include <stdio.h> |
||||
#include "cubeparse.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 cube_yylex YY_PROTO(( void )); \ |
||||
int cube_yylex YY_PROTO(( void )) |
||||
|
||||
/* 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 cube_flush_scanner_buffer(void); |
||||
%} |
||||
|
||||
n [0-9]+ |
||||
integer [+-]?{n} |
||||
real [+-]?({n}\.{n}?)|(\.{n}) |
||||
float ({integer}|{real})([eE]{integer})? |
||||
|
||||
%% |
||||
|
||||
{float} yylval = yytext; return FLOAT; |
||||
\[ yylval = "("; return O_BRACKET; |
||||
\] yylval = ")"; return C_BRACKET; |
||||
\( yylval = "("; return O_PAREN; |
||||
\) yylval = ")"; return C_PAREN; |
||||
\, yylval = ")"; return COMMA; |
||||
[ ]+ /* discard spaces */ |
||||
. return yytext[0]; /* alert parser of the garbage */ |
||||
|
||||
%% |
||||
|
||||
int cube_yylex(); |
||||
|
||||
void cube_flush_scanner_buffer(void) { |
||||
fprintf(stderr, "cube_flush_scanner_buffer called\n"); |
||||
YY_FLUSH_BUFFER; |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,962 @@ |
||||
-- |
||||
-- Test cube datatype |
||||
-- |
||||
-- |
||||
-- first, define the datatype. Turn off echoing so that expected file |
||||
-- does not depend on contents of cube.sql. |
||||
-- |
||||
\set ECHO none |
||||
-- |
||||
-- testing the input and output functions |
||||
-- |
||||
-- Any number (a one-dimensional point) |
||||
SELECT '1'::cube AS cube; |
||||
cube |
||||
------ |
||||
(1) |
||||
(1 row) |
||||
|
||||
SELECT '-1'::cube AS cube; |
||||
cube |
||||
------ |
||||
(-1) |
||||
(1 row) |
||||
|
||||
SELECT '1.'::cube AS cube; |
||||
cube |
||||
------ |
||||
(1) |
||||
(1 row) |
||||
|
||||
SELECT '-1.'::cube AS cube; |
||||
cube |
||||
------ |
||||
(-1) |
||||
(1 row) |
||||
|
||||
SELECT '.1'::cube AS cube; |
||||
cube |
||||
------- |
||||
(0.1) |
||||
(1 row) |
||||
|
||||
SELECT '-.1'::cube AS cube; |
||||
ERROR: parse error, expecting `FLOAT' or `O_PAREN' or `O_BRACKET' at or before position 2, character ('.', \056), input: '-.1' |
||||
|
||||
SELECT '1.0'::cube AS cube; |
||||
cube |
||||
------ |
||||
(1) |
||||
(1 row) |
||||
|
||||
SELECT '-1.0'::cube AS cube; |
||||
cube |
||||
------ |
||||
(-1) |
||||
(1 row) |
||||
|
||||
SELECT '1e7'::cube AS cube; |
||||
cube |
||||
--------- |
||||
(1e+07) |
||||
(1 row) |
||||
|
||||
SELECT '-1e7'::cube AS cube; |
||||
cube |
||||
---------- |
||||
(-1e+07) |
||||
(1 row) |
||||
|
||||
SELECT '1.0e7'::cube AS cube; |
||||
cube |
||||
--------- |
||||
(1e+07) |
||||
(1 row) |
||||
|
||||
SELECT '-1.0e7'::cube AS cube; |
||||
cube |
||||
---------- |
||||
(-1e+07) |
||||
(1 row) |
||||
|
||||
SELECT '1e+7'::cube AS cube; |
||||
cube |
||||
--------- |
||||
(1e+07) |
||||
(1 row) |
||||
|
||||
SELECT '-1e+7'::cube AS cube; |
||||
cube |
||||
---------- |
||||
(-1e+07) |
||||
(1 row) |
||||
|
||||
SELECT '1.0e+7'::cube AS cube; |
||||
cube |
||||
--------- |
||||
(1e+07) |
||||
(1 row) |
||||
|
||||
SELECT '-1.0e+7'::cube AS cube; |
||||
cube |
||||
---------- |
||||
(-1e+07) |
||||
(1 row) |
||||
|
||||
SELECT '1e-7'::cube AS cube; |
||||
cube |
||||
--------- |
||||
(1e-07) |
||||
(1 row) |
||||
|
||||
SELECT '-1e-7'::cube AS cube; |
||||
cube |
||||
---------- |
||||
(-1e-07) |
||||
(1 row) |
||||
|
||||
SELECT '1.0e-7'::cube AS cube; |
||||
cube |
||||
--------- |
||||
(1e-07) |
||||
(1 row) |
||||
|
||||
SELECT '-1.0e-7'::cube AS cube; |
||||
cube |
||||
---------- |
||||
(-1e-07) |
||||
(1 row) |
||||
|
||||
SELECT '1e700'::cube AS cube; |
||||
cube |
||||
------- |
||||
(inf) |
||||
(1 row) |
||||
|
||||
SELECT '-1e700'::cube AS cube; |
||||
cube |
||||
-------- |
||||
(-inf) |
||||
(1 row) |
||||
|
||||
SELECT '1e-700'::cube AS cube; |
||||
cube |
||||
------ |
||||
(0) |
||||
(1 row) |
||||
|
||||
SELECT '-1e-700'::cube AS cube; |
||||
cube |
||||
------ |
||||
(0) |
||||
(1 row) |
||||
|
||||
-- simple lists (points) |
||||
SELECT '1,2'::cube AS cube; |
||||
cube |
||||
-------- |
||||
(1, 2) |
||||
(1 row) |
||||
|
||||
SELECT '(1,2)'::cube AS cube; |
||||
cube |
||||
-------- |
||||
(1, 2) |
||||
(1 row) |
||||
|
||||
SELECT '1,2,3,4,5'::cube AS cube; |
||||
cube |
||||
----------------- |
||||
(1, 2, 3, 4, 5) |
||||
(1 row) |
||||
|
||||
SELECT '(1,2,3,4,5)'::cube AS cube; |
||||
cube |
||||
----------------- |
||||
(1, 2, 3, 4, 5) |
||||
(1 row) |
||||
|
||||
-- double lists (cubes) |
||||
SELECT '(0),(0)'::cube AS cube; |
||||
cube |
||||
------ |
||||
(0) |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube AS cube; |
||||
cube |
||||
--------- |
||||
(0),(1) |
||||
(1 row) |
||||
|
||||
SELECT '[(0),(0)]'::cube AS cube; |
||||
cube |
||||
------ |
||||
(0) |
||||
(1 row) |
||||
|
||||
SELECT '[(0),(1)]'::cube AS cube; |
||||
cube |
||||
--------- |
||||
(0),(1) |
||||
(1 row) |
||||
|
||||
SELECT '(0,0,0,0),(0,0,0,0)'::cube AS cube; |
||||
cube |
||||
-------------- |
||||
(0, 0, 0, 0) |
||||
(1 row) |
||||
|
||||
SELECT '(0,0,0,0),(1,0,0,0)'::cube AS cube; |
||||
cube |
||||
--------------------------- |
||||
(0, 0, 0, 0),(1, 0, 0, 0) |
||||
(1 row) |
||||
|
||||
SELECT '[(0,0,0,0),(0,0,0,0)]'::cube AS cube; |
||||
cube |
||||
-------------- |
||||
(0, 0, 0, 0) |
||||
(1 row) |
||||
|
||||
SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube; |
||||
cube |
||||
--------------------------- |
||||
(0, 0, 0, 0),(1, 0, 0, 0) |
||||
(1 row) |
||||
|
||||
-- invalid input: parse errors |
||||
SELECT ''::cube AS cube; |
||||
ERROR: cube_in: can't parse an empty string |
||||
SELECT 'ABC'::cube AS cube; |
||||
ERROR: parse error, expecting `FLOAT' or `O_PAREN' or `O_BRACKET' at or before position 1, character ('A', \101), input: 'ABC' |
||||
|
||||
SELECT '()'::cube AS cube; |
||||
ERROR: parse error, expecting `FLOAT' at or before position 2, character (')', \051), input: '()' |
||||
|
||||
SELECT '[]'::cube AS cube; |
||||
ERROR: parse error, expecting `O_PAREN' at or before position 2, character (']', \135), input: '[]' |
||||
|
||||
SELECT '[()]'::cube AS cube; |
||||
ERROR: parse error, expecting `FLOAT' at or before position 3, character (')', \051), input: '[()]' |
||||
|
||||
SELECT '[(1)]'::cube AS cube; |
||||
ERROR: parse error, expecting `COMMA' at or before position 5, character (']', \135), input: '[(1)]' |
||||
|
||||
SELECT '[(1),]'::cube AS cube; |
||||
ERROR: parse error, expecting `O_PAREN' at or before position 6, character (']', \135), input: '[(1),]' |
||||
|
||||
SELECT '[(1),2]'::cube AS cube; |
||||
ERROR: parse error, expecting `O_PAREN' at or before position 7, character (']', \135), input: '[(1),2]' |
||||
|
||||
SELECT '[(1),(2),(3)]'::cube AS cube; |
||||
ERROR: parse error, expecting `C_BRACKET' at or before position 9, character (',', \054), input: '[(1),(2),(3)]' |
||||
|
||||
SELECT '1,'::cube AS cube; |
||||
ERROR: parse error, expecting `FLOAT' at or before position 2, character (',', \054), input: '1,' |
||||
|
||||
SELECT '1,2,'::cube AS cube; |
||||
ERROR: parse error, expecting `FLOAT' at or before position 4, character (',', \054), input: '1,2,' |
||||
|
||||
SELECT '1,,2'::cube AS cube; |
||||
ERROR: parse error, expecting `FLOAT' at or before position 3, character (',', \054), input: '1,,2' |
||||
|
||||
SELECT '(1,)'::cube AS cube; |
||||
ERROR: parse error, expecting `FLOAT' at or before position 4, character (')', \051), input: '(1,)' |
||||
|
||||
SELECT '(1,2,)'::cube AS cube; |
||||
ERROR: parse error, expecting `FLOAT' at or before position 6, character (')', \051), input: '(1,2,)' |
||||
|
||||
SELECT '(1,,2)'::cube AS cube; |
||||
ERROR: parse error, expecting `FLOAT' at or before position 4, character (',', \054), input: '(1,,2)' |
||||
|
||||
-- invalid input: semantic errors and trailing garbage |
||||
SELECT '[(1),(2)],'::cube AS cube; -- 0 |
||||
ERROR: (0) bad cube representation; garbage at or before char 9, (',', \054) |
||||
|
||||
SELECT '[(1,2,3),(2,3)]'::cube AS cube; -- 1 |
||||
ERROR: (1) bad cube representation; different point dimensions in (1,2,3) and (2,3) |
||||
|
||||
SELECT '[(1,2),(1,2,3)]'::cube AS cube; -- 1 |
||||
ERROR: (1) bad cube representation; different point dimensions in (1,2) and (1,2,3) |
||||
|
||||
SELECT '(1),(2),'::cube AS cube; -- 2 |
||||
ERROR: (2) bad cube representation; garbage at or before char 7, (',', \054) |
||||
|
||||
SELECT '(1,2,3),(2,3)'::cube AS cube; -- 3 |
||||
ERROR: (3) bad cube representation; different point dimensions in (1,2,3) and (2,3) |
||||
|
||||
SELECT '(1,2),(1,2,3)'::cube AS cube; -- 3 |
||||
ERROR: (3) bad cube representation; different point dimensions in (1,2) and (1,2,3) |
||||
|
||||
SELECT '(1,2,3)ab'::cube AS cube; -- 4 |
||||
ERROR: (4) bad cube representation; garbage at or before char 8, ('b', \142) |
||||
|
||||
SELECT '(1,2,3)a'::cube AS cube; -- 5 |
||||
ERROR: (5) bad cube representation; garbage at or before char 8, ('end of input', \000) |
||||
|
||||
SELECT '(1,2)('::cube AS cube; -- 5 |
||||
ERROR: (5) bad cube representation; garbage at or before char 6, ('end of input', \000) |
||||
|
||||
SELECT '1,2ab'::cube AS cube; -- 6 |
||||
ERROR: (6) bad cube representation; garbage at or before char 4, ('b', \142) |
||||
|
||||
SELECT '1 e7'::cube AS cube; -- 6 |
||||
ERROR: (6) bad cube representation; garbage at or before char 3, ('7', \067) |
||||
|
||||
SELECT '1,2a'::cube AS cube; -- 7 |
||||
ERROR: (7) bad cube representation; garbage at or before char 4, ('end of input', \000) |
||||
|
||||
SELECT '1..2'::cube AS cube; -- 7 |
||||
ERROR: (7) bad cube representation; garbage at or before char 4, ('end of input', \000) |
||||
|
||||
-- |
||||
-- testing the operators |
||||
-- |
||||
-- equality/inequality: |
||||
-- |
||||
SELECT '24, 33.20'::cube = '24, 33.20'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '24, 33.20'::cube != '24, 33.20'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '24, 33.20'::cube = '24, 33.21'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '24, 33.20'::cube != '24, 33.21'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
-- "lower than" / "greater than" |
||||
-- (these operators are not useful for anything but ordering) |
||||
-- |
||||
SELECT '1'::cube > '2'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '1'::cube < '2'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '1,1'::cube > '1,2'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '1,1'::cube < '1,2'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube > '(2,0),(3,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube < '(2,0),(3,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
-- "overlap" |
||||
-- |
||||
SELECT '1'::cube && '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '1'::cube && '2'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '0'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1,1,1'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1,1),(2,2,2)]'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1),(2,2)]'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(2,1,1),(2,2,2)]'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
-- "overlap on the left" / "overlap on the right" |
||||
-- (these operators are not useful at all but R-tree seems to be |
||||
-- sensitive to their presence) |
||||
-- |
||||
SELECT '1'::cube &< '0'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '1'::cube &< '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '1'::cube &< '2'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube &< '0'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube &< '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube &< '(0),(0.5)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube &< '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube &< '(0),(2)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube &< '(1),(2)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube &< '(2),(3)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '0'::cube &> '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '1'::cube &> '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '2'::cube &> '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '0'::cube &> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '1'::cube &> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(0),(0.5)' &> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube &> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(0),(2)'::cube &> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(1),(2)'::cube &> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(2),(3)'::cube &> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
-- "left" / "right" |
||||
-- (these operators are not useful but for 1-D or 2-D cubes, but R-tree |
||||
-- seems to want them defined) |
||||
-- |
||||
SELECT '1'::cube << '0'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '1'::cube << '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '1'::cube << '2'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube << '0'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube << '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube << '(0),(0.5)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube << '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube << '(0),(2)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube << '(1),(2)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube << '(2),(3)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '0'::cube >> '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '1'::cube >> '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '2'::cube >> '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '0'::cube >> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '1'::cube >> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(0),(0.5)' >> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(0),(1)'::cube >> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(0),(2)'::cube >> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(1),(2)'::cube >> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(2),(3)'::cube >> '(0),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
-- "contained in" (the left operand is the cube entirely enclosed by |
||||
-- the right operand): |
||||
-- |
||||
SELECT '0'::cube ~ '0'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '0,0,0'::cube ~ '0,0,0'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '0,0'::cube ~ '0,0,1'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '0,0,0'::cube ~ '0,0,1'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '1,0,0'::cube ~ '0,0,1'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(1,0,0),(0,0,1)'::cube ~ '(1,0,0),(0,0,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(1,0,0),(0,0,1)'::cube ~ '(-1,-1,-1),(1,1,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(1,0,0),(0,0,1)'::cube ~ '(-1,-1,-1,-1),(1,1,1,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '0'::cube ~ '(-1),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '1'::cube ~ '(-1),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '-1'::cube ~ '(-1),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(-1),(1)'::cube ~ '(-1),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(-1),(1)'::cube ~ '(-1,-1),(1,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(-2),(1)'::cube ~ '(-1),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(-2),(1)'::cube ~ '(-1,-1),(1,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
-- "contains" (the left operand is the cube that entirely encloses the |
||||
-- right operand) |
||||
-- |
||||
SELECT '0'::cube @ '0'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '0,0,0'::cube @ '0,0,0'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '0,0,1'::cube @ '0,0'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '0,0,1'::cube @ '0,0,0'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '0,0,1'::cube @ '1,0,0'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(1,0,0),(0,0,1)'::cube @ '(1,0,0),(0,0,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(-1,-1,-1),(1,1,1)'::cube @ '(1,0,0),(0,0,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(-1,-1,-1,-1),(1,1,1,1)'::cube @ '(1,0,0),(0,0,1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(-1),(1)'::cube @ '0'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(-1),(1)'::cube @ '1'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(-1),(1)'::cube @ '-1'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(-1),(1)'::cube @ '(-1),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(-1,-1),(1,1)'::cube @ '(-1),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
t |
||||
(1 row) |
||||
|
||||
SELECT '(-1),(1)'::cube @ '(-2),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
SELECT '(-1,-1),(1,1)'::cube @ '(-2),(1)'::cube AS bool; |
||||
bool |
||||
------ |
||||
f |
||||
(1 row) |
||||
|
||||
-- Load some example data and build the index |
||||
-- |
||||
CREATE TABLE test_cube (c cube); |
||||
\copy test_cube from 'data/test_cube.data' |
||||
CREATE INDEX test_cube_ix ON test_cube USING gist (c); |
||||
SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)'; |
||||
c |
||||
-------------------------- |
||||
(2424, 160),(2424, 81) |
||||
(759, 187),(662, 163) |
||||
(1444, 403),(1346, 344) |
||||
(337, 455),(240, 359) |
||||
(1594, 1043),(1517, 971) |
||||
(5 rows) |
||||
|
||||
-- Test sorting |
||||
SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c; |
||||
c |
||||
-------------------------- |
||||
(337, 455),(240, 359) |
||||
(759, 187),(662, 163) |
||||
(1444, 403),(1346, 344) |
||||
(1594, 1043),(1517, 971) |
||||
(2424, 160),(2424, 81) |
||||
(5 rows) |
||||
|
@ -0,0 +1,246 @@ |
||||
-- |
||||
-- Test cube datatype |
||||
-- |
||||
|
||||
-- |
||||
-- first, define the datatype. Turn off echoing so that expected file |
||||
-- does not depend on contents of cube.sql. |
||||
-- |
||||
\set ECHO none |
||||
\i cube.sql |
||||
\set ECHO all |
||||
|
||||
-- |
||||
-- testing the input and output functions |
||||
-- |
||||
|
||||
-- Any number (a one-dimensional point) |
||||
SELECT '1'::cube AS cube; |
||||
SELECT '-1'::cube AS cube; |
||||
SELECT '1.'::cube AS cube; |
||||
SELECT '-1.'::cube AS cube; |
||||
SELECT '.1'::cube AS cube; |
||||
SELECT '-.1'::cube AS cube; |
||||
SELECT '1.0'::cube AS cube; |
||||
SELECT '-1.0'::cube AS cube; |
||||
SELECT '1e7'::cube AS cube; |
||||
SELECT '-1e7'::cube AS cube; |
||||
SELECT '1.0e7'::cube AS cube; |
||||
SELECT '-1.0e7'::cube AS cube; |
||||
SELECT '1e+7'::cube AS cube; |
||||
SELECT '-1e+7'::cube AS cube; |
||||
SELECT '1.0e+7'::cube AS cube; |
||||
SELECT '-1.0e+7'::cube AS cube; |
||||
SELECT '1e-7'::cube AS cube; |
||||
SELECT '-1e-7'::cube AS cube; |
||||
SELECT '1.0e-7'::cube AS cube; |
||||
SELECT '-1.0e-7'::cube AS cube; |
||||
SELECT '1e700'::cube AS cube; |
||||
SELECT '-1e700'::cube AS cube; |
||||
SELECT '1e-700'::cube AS cube; |
||||
SELECT '-1e-700'::cube AS cube; |
||||
|
||||
-- simple lists (points) |
||||
SELECT '1,2'::cube AS cube; |
||||
SELECT '(1,2)'::cube AS cube; |
||||
SELECT '1,2,3,4,5'::cube AS cube; |
||||
SELECT '(1,2,3,4,5)'::cube AS cube; |
||||
|
||||
-- double lists (cubes) |
||||
SELECT '(0),(0)'::cube AS cube; |
||||
SELECT '(0),(1)'::cube AS cube; |
||||
SELECT '[(0),(0)]'::cube AS cube; |
||||
SELECT '[(0),(1)]'::cube AS cube; |
||||
SELECT '(0,0,0,0),(0,0,0,0)'::cube AS cube; |
||||
SELECT '(0,0,0,0),(1,0,0,0)'::cube AS cube; |
||||
SELECT '[(0,0,0,0),(0,0,0,0)]'::cube AS cube; |
||||
SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube; |
||||
|
||||
-- invalid input: parse errors |
||||
SELECT ''::cube AS cube; |
||||
SELECT 'ABC'::cube AS cube; |
||||
SELECT '()'::cube AS cube; |
||||
SELECT '[]'::cube AS cube; |
||||
SELECT '[()]'::cube AS cube; |
||||
SELECT '[(1)]'::cube AS cube; |
||||
SELECT '[(1),]'::cube AS cube; |
||||
SELECT '[(1),2]'::cube AS cube; |
||||
SELECT '[(1),(2),(3)]'::cube AS cube; |
||||
SELECT '1,'::cube AS cube; |
||||
SELECT '1,2,'::cube AS cube; |
||||
SELECT '1,,2'::cube AS cube; |
||||
SELECT '(1,)'::cube AS cube; |
||||
SELECT '(1,2,)'::cube AS cube; |
||||
SELECT '(1,,2)'::cube AS cube; |
||||
|
||||
-- invalid input: semantic errors and trailing garbage |
||||
SELECT '[(1),(2)],'::cube AS cube; -- 0 |
||||
SELECT '[(1,2,3),(2,3)]'::cube AS cube; -- 1 |
||||
SELECT '[(1,2),(1,2,3)]'::cube AS cube; -- 1 |
||||
SELECT '(1),(2),'::cube AS cube; -- 2 |
||||
SELECT '(1,2,3),(2,3)'::cube AS cube; -- 3 |
||||
SELECT '(1,2),(1,2,3)'::cube AS cube; -- 3 |
||||
SELECT '(1,2,3)ab'::cube AS cube; -- 4 |
||||
SELECT '(1,2,3)a'::cube AS cube; -- 5 |
||||
SELECT '(1,2)('::cube AS cube; -- 5 |
||||
SELECT '1,2ab'::cube AS cube; -- 6 |
||||
SELECT '1 e7'::cube AS cube; -- 6 |
||||
SELECT '1,2a'::cube AS cube; -- 7 |
||||
SELECT '1..2'::cube AS cube; -- 7 |
||||
|
||||
-- |
||||
-- testing the operators |
||||
-- |
||||
|
||||
-- equality/inequality: |
||||
-- |
||||
SELECT '24, 33.20'::cube = '24, 33.20'::cube AS bool; |
||||
SELECT '24, 33.20'::cube != '24, 33.20'::cube AS bool; |
||||
SELECT '24, 33.20'::cube = '24, 33.21'::cube AS bool; |
||||
SELECT '24, 33.20'::cube != '24, 33.21'::cube AS bool; |
||||
SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; |
||||
SELECT '(2,0),(3,1)'::cube = '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; |
||||
|
||||
-- "lower than" / "greater than" |
||||
-- (these operators are not useful for anything but ordering) |
||||
-- |
||||
SELECT '1'::cube > '2'::cube AS bool; |
||||
SELECT '1'::cube < '2'::cube AS bool; |
||||
SELECT '1,1'::cube > '1,2'::cube AS bool; |
||||
SELECT '1,1'::cube < '1,2'::cube AS bool; |
||||
|
||||
SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; |
||||
SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,1)'::cube AS bool; |
||||
SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; |
||||
SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,1),(3,1,0,0,0)'::cube AS bool; |
||||
SELECT '(2,0),(3,1)'::cube > '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; |
||||
SELECT '(2,0),(3,1)'::cube < '(2,0,0,0,0),(3,1,0,0,0)'::cube AS bool; |
||||
SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube > '(2,0),(3,1)'::cube AS bool; |
||||
SELECT '(2,0,0,0,0),(3,1,0,0,1)'::cube < '(2,0),(3,1)'::cube AS bool; |
||||
SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; |
||||
SELECT '(2,0,0,0,1),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; |
||||
SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube > '(2,0),(3,1)'::cube AS bool; |
||||
SELECT '(2,0,0,0,0),(3,1,0,0,0)'::cube < '(2,0),(3,1)'::cube AS bool; |
||||
|
||||
|
||||
-- "overlap" |
||||
-- |
||||
SELECT '1'::cube && '1'::cube AS bool; |
||||
SELECT '1'::cube && '2'::cube AS bool; |
||||
|
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '0'::cube AS bool; |
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1'::cube AS bool; |
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '1,1,1'::cube AS bool; |
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1,1),(2,2,2)]'::cube AS bool; |
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(1,1),(2,2)]'::cube AS bool; |
||||
SELECT '[(-1,-1,-1),(1,1,1)]'::cube && '[(2,1,1),(2,2,2)]'::cube AS bool; |
||||
|
||||
-- "overlap on the left" / "overlap on the right" |
||||
-- (these operators are not useful at all but R-tree seems to be |
||||
-- sensitive to their presence) |
||||
-- |
||||
SELECT '1'::cube &< '0'::cube AS bool; |
||||
SELECT '1'::cube &< '1'::cube AS bool; |
||||
SELECT '1'::cube &< '2'::cube AS bool; |
||||
|
||||
SELECT '(0),(1)'::cube &< '0'::cube AS bool; |
||||
SELECT '(0),(1)'::cube &< '1'::cube AS bool; |
||||
SELECT '(0),(1)'::cube &< '(0),(0.5)'::cube AS bool; |
||||
SELECT '(0),(1)'::cube &< '(0),(1)'::cube AS bool; |
||||
SELECT '(0),(1)'::cube &< '(0),(2)'::cube AS bool; |
||||
SELECT '(0),(1)'::cube &< '(1),(2)'::cube AS bool; |
||||
SELECT '(0),(1)'::cube &< '(2),(3)'::cube AS bool; |
||||
|
||||
SELECT '0'::cube &> '1'::cube AS bool; |
||||
SELECT '1'::cube &> '1'::cube AS bool; |
||||
SELECT '2'::cube &> '1'::cube AS bool; |
||||
|
||||
SELECT '0'::cube &> '(0),(1)'::cube AS bool; |
||||
SELECT '1'::cube &> '(0),(1)'::cube AS bool; |
||||
SELECT '(0),(0.5)' &> '(0),(1)'::cube AS bool; |
||||
SELECT '(0),(1)'::cube &> '(0),(1)'::cube AS bool; |
||||
SELECT '(0),(2)'::cube &> '(0),(1)'::cube AS bool; |
||||
SELECT '(1),(2)'::cube &> '(0),(1)'::cube AS bool; |
||||
SELECT '(2),(3)'::cube &> '(0),(1)'::cube AS bool; |
||||
|
||||
|
||||
-- "left" / "right" |
||||
-- (these operators are not useful but for 1-D or 2-D cubes, but R-tree |
||||
-- seems to want them defined) |
||||
-- |
||||
SELECT '1'::cube << '0'::cube AS bool; |
||||
SELECT '1'::cube << '1'::cube AS bool; |
||||
SELECT '1'::cube << '2'::cube AS bool; |
||||
|
||||
SELECT '(0),(1)'::cube << '0'::cube AS bool; |
||||
SELECT '(0),(1)'::cube << '1'::cube AS bool; |
||||
SELECT '(0),(1)'::cube << '(0),(0.5)'::cube AS bool; |
||||
SELECT '(0),(1)'::cube << '(0),(1)'::cube AS bool; |
||||
SELECT '(0),(1)'::cube << '(0),(2)'::cube AS bool; |
||||
SELECT '(0),(1)'::cube << '(1),(2)'::cube AS bool; |
||||
SELECT '(0),(1)'::cube << '(2),(3)'::cube AS bool; |
||||
|
||||
SELECT '0'::cube >> '1'::cube AS bool; |
||||
SELECT '1'::cube >> '1'::cube AS bool; |
||||
SELECT '2'::cube >> '1'::cube AS bool; |
||||
|
||||
SELECT '0'::cube >> '(0),(1)'::cube AS bool; |
||||
SELECT '1'::cube >> '(0),(1)'::cube AS bool; |
||||
SELECT '(0),(0.5)' >> '(0),(1)'::cube AS bool; |
||||
SELECT '(0),(1)'::cube >> '(0),(1)'::cube AS bool; |
||||
SELECT '(0),(2)'::cube >> '(0),(1)'::cube AS bool; |
||||
SELECT '(1),(2)'::cube >> '(0),(1)'::cube AS bool; |
||||
SELECT '(2),(3)'::cube >> '(0),(1)'::cube AS bool; |
||||
|
||||
|
||||
-- "contained in" (the left operand is the cube entirely enclosed by |
||||
-- the right operand): |
||||
-- |
||||
SELECT '0'::cube ~ '0'::cube AS bool; |
||||
SELECT '0,0,0'::cube ~ '0,0,0'::cube AS bool; |
||||
SELECT '0,0'::cube ~ '0,0,1'::cube AS bool; |
||||
SELECT '0,0,0'::cube ~ '0,0,1'::cube AS bool; |
||||
SELECT '1,0,0'::cube ~ '0,0,1'::cube AS bool; |
||||
SELECT '(1,0,0),(0,0,1)'::cube ~ '(1,0,0),(0,0,1)'::cube AS bool; |
||||
SELECT '(1,0,0),(0,0,1)'::cube ~ '(-1,-1,-1),(1,1,1)'::cube AS bool; |
||||
SELECT '(1,0,0),(0,0,1)'::cube ~ '(-1,-1,-1,-1),(1,1,1,1)'::cube AS bool; |
||||
SELECT '0'::cube ~ '(-1),(1)'::cube AS bool; |
||||
SELECT '1'::cube ~ '(-1),(1)'::cube AS bool; |
||||
SELECT '-1'::cube ~ '(-1),(1)'::cube AS bool; |
||||
SELECT '(-1),(1)'::cube ~ '(-1),(1)'::cube AS bool; |
||||
SELECT '(-1),(1)'::cube ~ '(-1,-1),(1,1)'::cube AS bool; |
||||
SELECT '(-2),(1)'::cube ~ '(-1),(1)'::cube AS bool; |
||||
SELECT '(-2),(1)'::cube ~ '(-1,-1),(1,1)'::cube AS bool; |
||||
|
||||
|
||||
-- "contains" (the left operand is the cube that entirely encloses the |
||||
-- right operand) |
||||
-- |
||||
SELECT '0'::cube @ '0'::cube AS bool; |
||||
SELECT '0,0,0'::cube @ '0,0,0'::cube AS bool; |
||||
SELECT '0,0,1'::cube @ '0,0'::cube AS bool; |
||||
SELECT '0,0,1'::cube @ '0,0,0'::cube AS bool; |
||||
SELECT '0,0,1'::cube @ '1,0,0'::cube AS bool; |
||||
SELECT '(1,0,0),(0,0,1)'::cube @ '(1,0,0),(0,0,1)'::cube AS bool; |
||||
SELECT '(-1,-1,-1),(1,1,1)'::cube @ '(1,0,0),(0,0,1)'::cube AS bool; |
||||
SELECT '(-1,-1,-1,-1),(1,1,1,1)'::cube @ '(1,0,0),(0,0,1)'::cube AS bool; |
||||
SELECT '(-1),(1)'::cube @ '0'::cube AS bool; |
||||
SELECT '(-1),(1)'::cube @ '1'::cube AS bool; |
||||
SELECT '(-1),(1)'::cube @ '-1'::cube AS bool; |
||||
SELECT '(-1),(1)'::cube @ '(-1),(1)'::cube AS bool; |
||||
SELECT '(-1,-1),(1,1)'::cube @ '(-1),(1)'::cube AS bool; |
||||
SELECT '(-1),(1)'::cube @ '(-2),(1)'::cube AS bool; |
||||
SELECT '(-1,-1),(1,1)'::cube @ '(-2),(1)'::cube AS bool; |
||||
|
||||
|
||||
-- Load some example data and build the index |
||||
-- |
||||
CREATE TABLE test_cube (c cube); |
||||
|
||||
\copy test_cube from 'data/test_cube.data' |
||||
|
||||
CREATE INDEX test_cube_ix ON test_cube USING gist (c); |
||||
SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)'; |
||||
|
||||
-- Test sorting |
||||
SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c; |
Loading…
Reference in new issue