*** a/doc/src/sgml/datatype.sgml
--- b/doc/src/sgml/datatype.sgml
***************
*** 4131,4136 **** SET xmloption TO { DOCUMENT | CONTENT };
--- 4131,4138 ----
&rowtypes;
+ &rangetypes;
+
Object Identifier Types
***************
*** 4402,4407 **** SELECT * FROM pg_attribute
--- 4404,4413 ----
+ anyrange
+
+
+ void
***************
*** 4474,4479 **** SELECT * FROM pg_attribute
--- 4480,4492 ----
+ anyrange>
+ Indicates that a function accepts any range data type
+ (see and
+ ).
+
+
+ anynonarray>Indicates that a function accepts any non-array data type
(see ).
***************
*** 4532,4538 **** SELECT * FROM pg_attribute
only void> and record> as a result type (plus
trigger> when the function is used as a trigger). Some also
support polymorphic functions using the types anyarray>,
! anyelement>, anyenum>, and anynonarray>.
--- 4545,4552 ----
only void> and record> as a result type (plus
trigger> when the function is used as a trigger). Some also
support polymorphic functions using the types anyarray>,
! anyelement>, anyenum>, anyrange>, and
! anynonarray>.
*** a/doc/src/sgml/extend.sgml
--- b/doc/src/sgml/extend.sgml
***************
*** 193,206 ****
! Four pseudo-types of special interest are anyelement>,
! anyarray>, anynonarray>, and anyenum>,
! which are collectively called polymorphic types>.
! Any function declared using these types is said to be
! a polymorphic function>. A polymorphic function can
! operate on many different data types, with the specific data type(s)
! being determined by the data types actually passed to it in a particular
! call.
--- 193,207 ----
! Five pseudo-types of special interest are anyelement>,
! anyarray>, anynonarray>, anyenum>,
! and anyrange>, which are collectively
! called polymorphic types>. Any function declared
! using these types is said to be a polymorphic
! function>. A polymorphic function can operate on many
! different data types, with the specific data type(s) being
! determined by the data types actually passed to it in a
! particular call.
***************
*** 216,221 ****
--- 217,227 ----
anyelement, the actual array type in the
anyarray positions must be an array whose elements are
the same type appearing in the anyelement positions.
+ Similarly, if there are positions declared anyrange
+ and others declared
+ anyelement, the actual range type in the
+ anyrange positions must be a range whose subtype is
+ the same type appearing in the anyelement positions.
anynonarray> is treated exactly the same as anyelement>,
but adds the additional constraint that the actual type must not be
an array type.
*** a/doc/src/sgml/filelist.sgml
--- b/doc/src/sgml/filelist.sgml
***************
*** 25,30 ****
--- 25,31 ----
+
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 10426,10431 **** SELECT NULLIF(value, '(none)') ...
--- 10426,10889 ----
+
+ Range Functions and Operators
+
+
+ shows the operators
+ available for range types.
+
+
+
+ Range Operators
+
+
+
+ Operator
+ Description
+ Example
+ Result
+
+
+
+
+ =
+ equal
+ range(1,5) = '[1,4]'::int4range
+ t
+
+
+
+ <>
+ not equal
+ range(1.1,2.2) <> range(1.1,2.3)
+ t
+
+
+
+ <
+ less than
+ range(1,10) < range(2,3)
+ t
+
+
+
+ >
+ greater than
+ range(1,10) > range(1,5)
+
+ t
+
+
+
+ <=
+ less than or equal
+ range(1.1,2.2) <= range(1.1,2.2)
+ t
+
+
+
+ >=
+ greater than or equal
+ range(1.1,2.2) >= range(1.1,2.0)
+ t
+
+
+
+ @>
+ contains
+ '[2011-01-01,2011-03-01)'::tsrange @> '2011-01-10'::timestamp
+ t
+
+
+
+ <@
+ is contained by
+ range(2,4) <@ range(1,7)
+ t
+
+
+
+ &&
+ overlap (have points in common)
+ range(3,7) && range(4,12)
+ t
+
+
+
+ <<
+ strictly left of
+ range(1,10) << range(100,110)
+ t
+
+
+
+ >>
+ strictly right of
+ range(50,60) >> range(20,30)
+ t
+
+
+
+ &<
+ Does not extend to the right of?
+ range(1,20) &< range(18,20)
+ t
+
+
+
+ &>
+ Does not extend to the left of?
+ range(7,20) &> range(5,10)
+ t
+
+
+
+ -|-
+ adjacent?
+ range(1.1,2.2) -|- range(2.2,3.3)
+ t
+
+
+
+ +
+ Union
+ range(5,15) + range(10,20)
+ [5,20)
+
+
+
+ -
+ Difference
+ range(5,15) - range(10,20)
+ [5,10)
+
+
+
+ *
+ Intersection
+ range(5,15) * range(10,20)
+ [10,15)
+
+
+
+ !?
+ Is empty?
+ '-'::int4range !?
+ t
+
+
+
+ ?
+ Is non-empty?
+ range(1.0,2.0)?
+ t
+
+
+
+
+
+
+ Range comparisons compare the lower bounds first, and only if
+ equal, compare the upper bounds. This is generally most useful for
+ B-tree indexes, rather than being useful comparisons by themselves.
+
+
+
+ Array comparisons compare the array contents element-by-element,
+ using the default B-tree comparison function for the element data type.
+ In multidimensional arrays the elements are visited in row-major order
+ (last subscript varies most rapidly).
+ If the contents of two arrays are equal but the dimensionality is
+ different, the first difference in the dimensionality information
+ determines the sort order. (This is a change from versions of
+ PostgreSQL> prior to 8.2: older versions would claim
+ that two arrays with the same contents were equal, even if the
+ number of dimensions or subscript ranges were different.)
+
+
+
+ See for more details about range operator
+ behavior.
+
+
+
+ shows the functions
+ available for use with range types. See
+ for more information and examples of the use of these functions.
+
+
+
+ range
+
+
+ range__
+
+
+ range_i
+
+
+ rangei_
+
+
+ rangeii
+
+
+ range_linf_
+
+
+ range_uinf_
+
+
+ range_linfi
+
+
+ range_uinfi
+
+
+ lower
+
+
+ upper
+
+
+ empty
+
+
+ non_empty
+
+
+ lower_inc
+
+
+ upper_inc
+
+
+ lower_inf
+
+
+ upper_inf
+
+
+ length
+
+
+
+ Range Functions
+
+
+
+ Function
+ Return Type
+ Description
+ Example
+ Result
+
+
+
+
+
+
+ range(anyelement, anyelement)
+
+
+ anyrange
+ alias for rangei_
+ range(1.1,2.2)
+ [1.1,2.2)
+
+
+
+
+ range__(anyelement, anyelement)
+
+
+ anyrange
+ construct a range with exclusive lower bound and exclusive upper bound
+ range__(1.1,2.2)
+ (1.1,2.2)
+
+
+
+
+ range_i(anyelement, anyelement)
+
+
+ anyrange
+ construct a range with exclusive lower bound and inclusive upper bound
+ range_i(1.1,2.2)
+ (1.1,2.2]
+
+
+
+
+ rangei_(anyelement, anyelement)
+
+
+ anyrange
+ construct a range with inclusive lower bound and exclusive upper bound
+ rangei_(1.1,2.2)
+ [1.1,2.2)
+
+
+
+
+ rangeii(anyelement, anyelement)
+
+
+ anyrange
+ construct a range with inclusive lower bound and inclusive upper bound
+ rangeii(1.1,2.2)
+ [1.1,2.2]
+
+
+
+
+ range_linf_(anyelement)
+
+
+ anyrange
+ construct a range with infinite lower bound and exclusive upper bound
+ range_linf_(1.1)
+ (-INF,1.1)
+
+
+
+
+ range_uinf_(anyelement)
+
+
+ anyrange
+ construct a range with exclusive lower bound and infinite upper bound
+ range_uinf_(1.1)
+ (1.1,INF)
+
+
+
+
+ range_linfi(anyelement)
+
+
+ anyrange
+ construct a range with infinite lower bound and inclusive upper bound
+ range_linfi(1.1)
+ (-INF,1.1]
+
+
+
+
+ range_uinfi(anyelement)
+
+
+ anyrange
+ construct a range with inclusive lower bound and infinite upper bound
+ range_uinfi(1.1)
+ [1.1,INF)
+
+
+
+
+ lower(anyrange)
+
+
+ anyrange
+ lower bound of range
+ lower(range(1.1,2.2))
+ 1.1
+
+
+
+
+ upper(anyrange)
+
+
+ anyrange
+ upper bound of range
+ upper(range(1.1,2.2))
+ 2.2
+
+
+
+
+ empty(anyrange)
+
+
+ anyrange
+ is the range empty?
+ empty(range(1.1,2.2))
+ false
+
+
+
+
+ non_empty(anyrange)
+
+
+ anyrange
+ is the range non-empty?
+ non_empty(range(1.1,2.2))
+ true
+
+
+
+
+ lower_inc(anyrange)
+
+
+ anyrange
+ is the lower bound of the range inclusive?
+ lower_inc(range(1.1,2.2))
+ true
+
+
+
+
+ upper_inc(anyrange)
+
+
+ anyrange
+ is the upper bound of the range inclusive?
+ upper_inc(range(1.1,2.2))
+ false
+
+
+
+
+ lower_inf(anyrange)
+
+
+ anyrange
+ is the lower bound of the range infinite?
+ lower_inf('(-INF,INF)'::daterange)
+ true
+
+
+
+
+ upper_inf(anyrange)
+
+
+ anyrange
+ is the upper bound of the range infinite?
+ upper_inf('(-INF,INF)'::daterange)
+ true
+
+
+
+
+ length(anyrange)
+
+
+ anyelement
+ what is the upper bound of the range minus the lower bound?
+ length(range(10.1,20.1))
+ 10.0
+
+
+
+
+
+
Aggregate Functions
*** a/doc/src/sgml/plpgsql.sgml
--- b/doc/src/sgml/plpgsql.sgml
***************
*** 139,145 ****
PL/pgSQL> functions can also be declared to accept
and return the polymorphic types
anyelement, anyarray, anynonarray,
! and anyenum>. The actual
data types handled by a polymorphic function can vary from call to
call, as discussed in .
An example is shown in .
--- 139,145 ----
PL/pgSQL> functions can also be declared to accept
and return the polymorphic types
anyelement, anyarray, anynonarray,
! anyenum>, and anyrange. The actual
data types handled by a polymorphic function can vary from call to
call, as discussed in .
An example is shown in .
***************
*** 498,505 **** $$ LANGUAGE plpgsql;
When the return type of a PL/pgSQL
function is declared as a polymorphic type (anyelement,
! anyarray, anynonarray, or anyenum>),
! a special parameter $0
is created. Its data type is the actual return type of the function,
as deduced from the actual input types (see ).
--- 498,505 ----
When the return type of a PL/pgSQL
function is declared as a polymorphic type (anyelement,
! anyarray, anynonarray, anyenum,
! or anyrange), a special parameter $0
is created. Its data type is the actual return type of the function,
as deduced from the actual input types (see ).
*** /dev/null
--- b/doc/src/sgml/rangetypes.sgml
***************
*** 0 ****
--- 1,328 ----
+
+
+
+ Range Types
+
+
+ range type
+
+
+
+ Range types are data types representing a range of values over some
+ sub-type with a total order. For instance, ranges
+ of timestamp might be used to represent the ranges of
+ time that a meeting room is reserved. In this case the data type
+ is tsrange (short for "timestamp range"),
+ and timestamp is the sub-type with a total order.
+
+
+
+ Range types are useful because they represent many points in a
+ single value. The use of time and date ranges for scheduling
+ purposes is the clearest example; but price ranges, measurement
+ ranges from an instrument, etc., are also useful.
+
+
+
+ Built-in Range Types
+
+ Built-in range types:
+
+
+
+ INT4RANGE -- Range of INTEGER. This is a discrete range type, see .
+
+
+
+
+ INT8RANGE -- Range of BIGINT. This is a discrete range type, see .
+
+
+
+
+ NUMRANGE -- Range of NUMERIC.
+
+
+
+
+ TSRANGE -- Range of TIMESTAMP WITHOUT TIME ZONE.
+
+
+
+
+ TSTZRANGE -- Range of TIMESTAMP WITH TIME ZONE.
+
+
+
+
+ DATERANGE -- Range of DATE. This is a discrete range type, see .
+
+
+
+
+
+
+
+ Examples
+
+
+ CREATE TABLE reservation ( during TSRANGE );
+ INSERT INTO reservation VALUES
+ ( '[2010-01-01 14:30, 2010-01-01 15:30)' );
+
+ -- Containment
+ SELECT range(10, 20) @> 3;
+
+ -- Overlaps
+ SELECT range(11.1, 22.2) && range(20.0, 30.0)
+
+ -- Find the upper bound:
+ SELECT upper(range(15, 25));
+
+ -- Compute the intersection:
+ SELECT range(10, 20) * range(15, 25);
+
+ -- Is the range non-empty?
+ SELECT range(1, 5)? ;
+
+
+
+ See
+ and for complete lists of
+ functions and operators on range types.
+
+
+
+
+ Inclusive and Exclusive Bounds
+
+ Every range has two bounds, the lower bound and the upper bound. All
+ points in between those values are included in the range. An
+ inclusive bound means that the boundary point itself is included in
+ the range as well, while an exclusive bound means that the boundary
+ point is not included in the range.
+
+
+ An inclusive lower bound is represented by "["
+ while an exclusive lower bound is represented
+ by "(". Likewise, an inclusive upper bound is
+ represented by "]", while an exclusive upper bound
+ is represented by ")".
+
+
+ Functions lower_inc
+ and upper_inc test the inclusivity of the lower
+ and upper bounds of a range, respectively.
+
+
+
+
+ Infinite (unbounded) Ranges
+
+ The lower bound of a range can be -INF, meaning
+ that all points less than the upper bound are included in the
+ range. Likewise, if the upper bound of the range
+ is INF, then all points greater than the lower
+ bound are included in the range. If both lower and upper bounds are
+ infinite, all points are considered to be in the range.
+
+
+ Functions lower_inf
+ and upper_inf test the range for infinite lower
+ and upper bounds of a range, respectively.
+
+
+
+
+ Input/Output
+
+ The input follows one of the following patterns:
+
+ ( lower-bound , upper-bound )
+ ( lower-bound , upper-bound ]
+ [ lower-bound , upper-bound )
+ [ lower-bound , upper-bound ]
+ -
+
+ Notice that the final pattern is a "-", which
+ represents an empty range (a range that contains no points).
+
+
+ The lower-bound may be either a string
+ that is valid input for the sub-type, or -INF;
+ and upper-bound may be either a string
+ that is valid input for the sub-type, or INF.
+
+
+ Either the lower-bound or
+ the upper-bound may be quoted
+ using "..." (double quotation), which will
+ preserve internal whitespace and special characters such as
+ ",". Within quotation marks,
+ "\" (backslash) serves as an escape character.
+
+
+ The choice between the other input formats affects the inclusivity
+ of the bounds. See .
+
+
+
+
+ Constructing Ranges
+
+ Some examples of constructing ranges from existing values:
+
+ SELECT range_i(1.0, 14.0);
+
+ -- the int4range result will appear in the canonical format
+ SELECT range_i(1, 14);
+
+ SELECT range_uinfi(11.1);
+
+ SELECT range_linf_(2.2);
+
+
+
+ The function names follow a pattern at the end where
+ "_" is used to mean "exclusive" and
+ "" is used to mean "inclusive". Where two appear
+ together, the first is used to mean the lower bound, and the second
+ is used to mean the upper bound. The
+ function range assumes an inclusive lower bound
+ and an exclusive upper bound; and is an alias
+ for rangei_.
+
+
+ For a complete set of constructors, see .
+
+
+
+
+ Discrete Range Types
+
+ Discrete ranges are those that have a
+ defined canonical function. Loosely speaking, a
+ discrete range has a sub-type with a well-defined "step";
+ e.g. INTEGER or DATE.
+
+
+ The canonical function should take an input range
+ value, and return an equal range value that may have a different
+ formatting. For instance, the integer range [1,
+ 7] could be represented by the equal integer
+ range [1, 8). The two values are equal because
+ there are no points within the integer domain
+ between 7 and 8, so not
+ including the end point 8 is the same as
+ including the end point 7.
+
+
+ For types such as NUMRANGE, this is not possible,
+ because there are always points in between two
+ distinct NUMERIC values.
+
+
+
+
+ Defining New Range Types
+
+ To define a new range type of sub-type DOUBLE PRECISION:
+
+ CREATE TYPE FLOATRANGE AS RANGE (
+ SUBTYPE = DOUBLE PRECISION,
+ SUBTYPE_CMP = btfloat8cmp
+ );
+
+ SELECT '[1.234, 5.678]'::floatrange;
+
+ Because DOUBLE PRECISION has no meaningful "step", we
+ do not define a canonical
+ function. See for more
+ information.
+
+
+
+
+
+ range type
+ gist
+
+ GiST Indexing
+
+ GiST indexes can be applied to a table containing a range type. For instance:
+
+ CREATE INDEX reservation_idx ON reservation USING gist (during);
+
+ This index may speed up queries
+ involving &&
+ (overlaps), @> (contains), and many other
+ operators found in this
+ table: .
+
+
+
+
+
+ range type
+ exclude
+
+ Constraints on Ranges
+
+ While UNIQUE is a natural constraint for scalar
+ values, it is usually unsuitable for range types. Instead, an
+ exclusion constraint is often more appropriate
+ (see CREATE TABLE
+ ... CONSTRAINT ... EXCLUDE). Exclusion constraints allow the
+ specification of constraints such as "non-overlapping" on a range
+ type. For example:
+
+ ALTER TABLE reservation
+ ADD EXCLUDE USING gist (during WITH &&);
+
+ That constraint will prevent any overlapping values from existing
+ in the table at the same time:
+
+ INSERT INTO reservation VALUES
+ ( '[2010-01-01 11:30, 2010-01-01 13:00)' );
+ -- Result: INSERT 0 1
+ INSERT INTO reservation VALUES
+ ( '[2010-01-01 14:45, 2010-01-01 15:45)' );
+ -- Result:
+ -- ERROR: conflicting key value violates exclusion constraint "reservation_during_excl"
+ -- DETAIL: Key (during)=([ 2010-01-01 14:45:00, 2010-01-01 15:45:00 )) conflicts with
+ -- existing key (during)=([ 2010-01-01 14:30:00, 2010-01-01 15:30:00 )).
+
+
+
+ Combine range types and exclusion constraints
+ with btree_gist for maximum
+ flexibility defining
+ constraints. After btree_gist is installed, the
+ following constraint will prevent overlapping ranges only if the
+ meeting room numbers are equal:
+
+
+ CREATE TABLE room_reservation
+ (
+ room TEXT,
+ during TSRANGE,
+ EXCLUDE USING gist (room WITH =, during WITH &&)
+ );
+
+ INSERT INTO room_reservation VALUES
+ ( '123A', '[2010-01-01 14:00, 2010-01-01 15:00)' );
+ -- Result: INSERT 0 1
+ INSERT INTO room_reservation VALUES
+ ( '123A', '[2010-01-01 14:30, 2010-01-01 15:30)' );
+ -- Result:
+ -- ERROR: conflicting key value violates exclusion constraint "room_reservation_room_during_excl"
+ -- DETAIL: Key (room, during)=(123A, [ 2010-01-01 14:30:00, 2010-01-01 15:30:00 )) conflicts with
+ -- existing key (room, during)=(123A, [ 2010-01-01 14:00:00, 2010-01-01 15:00:00 )).
+ INSERT INTO room_reservation VALUES
+ ( '123B', '[2010-01-01 14:30, 2010-01-01 15:30)' );
+ -- Result: INSERT 0 1
+
+
+
+
+
*** a/doc/src/sgml/ref/create_type.sgml
--- b/doc/src/sgml/ref/create_type.sgml
***************
*** 27,32 **** CREATE TYPE name AS
--- 27,40 ----
CREATE TYPE name AS ENUM
( [ 'label' [, ... ] ] )
+ CREATE TYPE name AS RANGE (
+ SUBTYPE = subtype,
+ SUBTYPE_CMP = subtype_cmp_function
+ [ , SUBTYPE_FLOAT = subtype_float_function ]
+ [ , CANONICAL = canonical_function ]
+ [ , ANALYZE = analyze_function ]
+ )
+
CREATE TYPE name (
INPUT = input_function,
OUTPUT = output_function
***************
*** 96,106 **** CREATE TYPE nameBase Types
! The third form of CREATE TYPE creates a new base type
(scalar type). To create a new base type, you must be a superuser.
(This restriction is made because an erroneous type definition could
confuse or even crash the server.)
--- 104,163 ----
+
+ Range Types
+
+
+ The third form of CREATE TYPE creates a new
+ range type, as described in . To create
+ a new range type, you must be a superuser.
+
+
+
+ The subtype parameter
+ can be any type. The
+ function subtype_cmp
+ must take two arguments of
+ type subtype, and
+ compare them in a total order,
+ returning -1, 0,
+ or 1 when the first argument is less than,
+ equal to, or greater than the second argument, respectively.
+
+
+
+ The subtype_float
+ function takes a value of
+ type subtype and
+ returns a value of type double precision. This
+ function is used for GiST indexing (see for
+ more information), and should be provided for efficiency.
+
+
+
+ The canonical
+ function takes an argument and returns a value, both of the same
+ type being defined. This is used to convert the range value to a
+ canonical form when applicable. See
+ for more information. To define
+ a canonical function,
+ you must first create a shell type>, which is a
+ placeholder type that has no properties except a name and an
+ owner. This is done by issuing the command CREATE TYPE
+ name>, with no additional parameters.
+
+
+
+ The analyze
+ function is the same as for creating a base type.
+
+
+
Base Types
! The fourth form of CREATE TYPE creates a new base type
(scalar type). To create a new base type, you must be a superuser.
(This restriction is made because an erroneous type definition could
confuse or even crash the server.)
*** a/doc/src/sgml/xfunc.sgml
--- b/doc/src/sgml/xfunc.sgml
***************
*** 997,1004 **** $$ LANGUAGE SQL;
SQL functions can be declared to accept and
return the polymorphic types anyelement,
! anyarray, anynonarray, and
! anyenum. See for a more detailed
explanation of polymorphic functions. Here is a polymorphic
function make_array that builds up an array
--- 997,1004 ----
SQL functions can be declared to accept and
return the polymorphic types anyelement,
! anyarray, anynonarray,
! anyenum, and anyrange. See for a more detailed
explanation of polymorphic functions. Here is a polymorphic
function make_array that builds up an array
***************
*** 3244,3250 **** CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
C-language functions can be declared to accept and
return the polymorphic types
anyelement, anyarray, anynonarray,
! and anyenum.
See for a more detailed explanation
of polymorphic functions. When function arguments or return types
are defined as polymorphic types, the function author cannot know
--- 3244,3250 ----
C-language functions can be declared to accept and
return the polymorphic types
anyelement, anyarray, anynonarray,
! anyenum, and anyrange.
See for a more detailed explanation
of polymorphic functions. When function arguments or return types
are defined as polymorphic types, the function author cannot know
*** a/src/backend/catalog/Makefile
--- b/src/backend/catalog/Makefile
***************
*** 13,20 **** include $(top_builddir)/src/Makefile.global
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
objectaddress.o pg_aggregate.o pg_constraint.o pg_conversion.o \
pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
! pg_operator.o pg_proc.o pg_db_role_setting.o pg_shdepend.o pg_type.o \
! storage.o toasting.o
BKIFILES = postgres.bki postgres.description postgres.shdescription
--- 13,20 ----
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
objectaddress.o pg_aggregate.o pg_constraint.o pg_conversion.o \
pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
! pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \
! pg_type.o storage.o toasting.o
BKIFILES = postgres.bki postgres.description postgres.shdescription
***************
*** 39,45 **** POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_ts_parser.h pg_ts_template.h \
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
pg_foreign_table.h \
! pg_default_acl.h pg_seclabel.h \
toasting.h indexing.h \
)
--- 39,45 ----
pg_ts_parser.h pg_ts_template.h \
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
pg_foreign_table.h \
! pg_default_acl.h pg_seclabel.h pg_range.h\
toasting.h indexing.h \
)
*** a/src/backend/catalog/pg_proc.c
--- b/src/backend/catalog/pg_proc.c
***************
*** 165,170 **** ProcedureCreate(const char *procedureName,
--- 165,171 ----
case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID:
+ case ANYRANGEOID:
genericInParam = true;
break;
case INTERNALOID:
***************
*** 189,194 **** ProcedureCreate(const char *procedureName,
--- 190,196 ----
case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID:
+ case ANYRANGEOID:
genericOutParam = true;
break;
case INTERNALOID:
*** /dev/null
--- b/src/backend/catalog/pg_range.c
***************
*** 0 ****
--- 1,122 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pg_range.c
+ * routines to support manipulation of the pg_range relation
+ *
+ * Copyright (c) 2006-2010, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/catalog/pg_range.c
+ *
+ *-------------------------------------------------------------------------
+ */
+ #include "postgres.h"
+
+ #include "access/genam.h"
+ #include "access/heapam.h"
+ #include "catalog/dependency.h"
+ #include "catalog/indexing.h"
+ #include "catalog/pg_proc.h"
+ #include "catalog/pg_range.h"
+ #include "catalog/pg_type.h"
+ #include "utils/fmgroids.h"
+ #include "utils/tqual.h"
+
+ /*
+ * RangeCreate
+ * Create an entry in pg_range.
+ */
+ void
+ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, regproc rangeSubtypeCmp,
+ regproc rangeCanonical, regproc rangeSubFloat)
+ {
+ Relation pg_range;
+ Datum values[Natts_pg_range];
+ bool nulls[Natts_pg_range];
+ HeapTuple tup;
+ ObjectAddress myself;
+ ObjectAddress referenced;
+
+ pg_range = heap_open(RangeRelationId, RowExclusiveLock);
+
+ memset(nulls, 0, Natts_pg_range * sizeof(bool));
+
+ values[Anum_pg_range_rngtypid - 1] = ObjectIdGetDatum(rangeTypeOid);
+ values[Anum_pg_range_rngsubtype - 1] = ObjectIdGetDatum(rangeSubType);
+ values[Anum_pg_range_rngsubcmp - 1] = ObjectIdGetDatum(rangeSubtypeCmp);
+ values[Anum_pg_range_rngcanonical - 1] = ObjectIdGetDatum(rangeCanonical);
+ values[Anum_pg_range_rngsubfloat - 1] = ObjectIdGetDatum(rangeSubFloat);
+
+ tup = heap_form_tuple(RelationGetDescr(pg_range), values, nulls);
+ simple_heap_insert(pg_range, tup);
+ CatalogUpdateIndexes(pg_range, tup);
+ heap_freetuple(tup);
+
+ /* record dependencies */
+
+ myself.classId = TypeRelationId;
+ myself.objectId = rangeTypeOid;
+ myself.objectSubId = 0;
+
+ referenced.classId = TypeRelationId;
+ referenced.objectId = rangeSubType;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ referenced.classId = ProcedureRelationId;
+ referenced.objectId = rangeSubtypeCmp;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ if (OidIsValid(rangeCanonical))
+ {
+ referenced.classId = ProcedureRelationId;
+ referenced.objectId = rangeCanonical;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ }
+
+ if (OidIsValid(rangeSubFloat))
+ {
+ referenced.classId = ProcedureRelationId;
+ referenced.objectId = rangeSubFloat;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ }
+
+ heap_close(pg_range, RowExclusiveLock);
+ }
+
+
+ /*
+ * RangeDelete
+ * Remove the pg_range entry.
+ */
+ void
+ RangeDelete(Oid rangeTypeOid)
+ {
+ Relation pg_range;
+ ScanKeyData key[1];
+ SysScanDesc scan;
+ HeapTuple tup;
+
+ pg_range = heap_open(RangeRelationId, RowExclusiveLock);
+
+ ScanKeyInit(&key[0],
+ Anum_pg_range_rngtypid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(rangeTypeOid));
+
+ scan = systable_beginscan(pg_range, RangeTypidIndexId, true,
+ SnapshotNow, 1, key);
+
+ while (HeapTupleIsValid(tup = systable_getnext(scan)))
+ {
+ simple_heap_delete(pg_range, &tup->t_self);
+ }
+
+ systable_endscan(scan);
+
+ heap_close(pg_range, RowExclusiveLock);
+ }
*** a/src/backend/commands/typecmds.c
--- b/src/backend/commands/typecmds.c
***************
*** 42,47 ****
--- 42,49 ----
#include "catalog/pg_depend.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_namespace.h"
+ #include "catalog/pg_proc.h"
+ #include "catalog/pg_range.h"
#include "catalog/pg_type.h"
#include "catalog/pg_type_fn.h"
#include "commands/defrem.h"
***************
*** 84,89 **** static Oid findTypeSendFunction(List *procname, Oid typeOid);
--- 86,94 ----
static Oid findTypeTypmodinFunction(List *procname);
static Oid findTypeTypmodoutFunction(List *procname);
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
+ static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
+ static Oid findRangeSubtypeCmpFunction(List *procname, Oid typeOid);
+ static Oid findRangeSubtypeFloatFunction(List *procname, Oid typeOid);
static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
static void checkDomainOwner(HeapTuple tup);
static void checkEnumOwner(HeapTuple tup);
***************
*** 723,728 **** RemoveTypeById(Oid typeOid)
--- 728,741 ----
if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
EnumValuesDelete(typeOid);
+ /*
+ * If it is a range type, delete the pg_range entries too; we
+ * don't bother with making dependency entries for those, so it
+ * has to be done "by hand" here.
+ */
+ if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
+ RangeDelete(typeOid);
+
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
***************
*** 1194,1199 **** DefineEnum(CreateEnumStmt *stmt)
--- 1207,1461 ----
}
/*
+ * DefineRange
+ * Registers a new range type.
+ */
+ void
+ DefineRange(CreateRangeStmt *stmt)
+ {
+ char *typeName;
+ char *rangeArrayName;
+ Oid typeNamespace;
+ Oid typoid;
+ Oid rangeArrayOid;
+ List *parameters = stmt->params;
+
+ ListCell *lc;
+ List *rangeSubtypeCmpName = NIL;
+ List *rangeSubtypeFloatName = NIL;
+ regproc rangeAnalyze = InvalidOid;
+ Oid rangeSubtype = InvalidOid;
+ regproc rangeSubtypeCmp = InvalidOid;
+ regproc rangeCanonical = InvalidOid;
+ regproc rangeSubtypeFloat = InvalidOid;
+
+
+ /*
+ * As of Postgres 8.4, we require superuser privilege to create a base
+ * type. This is simple paranoia: there are too many ways to mess up the
+ * system with an incorrect type definition (for instance, representation
+ * parameters that don't match what the C code expects). In practice it
+ * takes superuser privilege to create the I/O functions, and so the
+ * former requirement that you own the I/O functions pretty much forced
+ * superuserness anyway. We're just making doubly sure here.
+ *
+ * XXX re-enable NOT_USED code sections below if you remove this test.
+ */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to create a range type")));
+
+ /* Convert list of names to a name and namespace */
+ typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
+ &typeName);
+
+ #ifdef NOT_USED
+ /* XXX this is unnecessary given the superuser check above */
+ /* Check we have creation rights in target namespace */
+ aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ get_namespace_name(typeNamespace));
+ #endif
+
+ /*
+ * Look to see if type already exists (presumably as a shell; if not,
+ * TypeCreate will complain).
+ */
+ typoid = GetSysCacheOid2(TYPENAMENSP,
+ CStringGetDatum(typeName),
+ ObjectIdGetDatum(typeNamespace));
+
+ /*
+ * If it's not a shell, see if it's an autogenerated array type, and if so
+ * rename it out of the way.
+ */
+ if (OidIsValid(typoid) && get_typisdefined(typoid))
+ {
+ if (moveArrayTypeName(typoid, typeName, typeNamespace))
+ typoid = InvalidOid;
+ }
+
+ /*
+ * If it doesn't exist, create it as a shell, so that the OID is known for
+ * use in the I/O function definitions.
+ */
+ if (!OidIsValid(typoid))
+ {
+ typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
+ /* Make new shell type visible for modification below */
+ CommandCounterIncrement();
+
+ /*
+ * If the command was a parameterless CREATE TYPE, we're done ---
+ * creating the shell type was all we're supposed to do.
+ */
+ if (parameters == NIL)
+ return;
+ }
+ else
+ {
+ /* Complain if dummy CREATE TYPE and entry already exists */
+ if (parameters == NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("type \"%s\" already exists", typeName)));
+ }
+
+ /* TODO: parse parameters */
+ foreach(lc, stmt->params)
+ {
+ DefElem *defel = lfirst(lc);
+
+ if (pg_strcasecmp(defel->defname, "subtype") == 0)
+ {
+ if (OidIsValid(rangeSubtype))
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
+ }
+ else if (pg_strcasecmp(defel->defname, "canonical") == 0)
+ {
+ if (OidIsValid(rangeCanonical))
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ rangeCanonical = findRangeCanonicalFunction(
+ defGetQualifiedName(defel), typoid);
+ }
+ else if (pg_strcasecmp(defel->defname, "analyze") == 0)
+ {
+ if (OidIsValid(rangeAnalyze))
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ rangeAnalyze = findTypeAnalyzeFunction(defGetQualifiedName(defel),
+ typoid);
+ }
+ else if (pg_strcasecmp(defel->defname, "subtype_cmp") == 0)
+ {
+ if (rangeSubtypeCmpName != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ rangeSubtypeCmpName = defGetQualifiedName(defel);
+ }
+ else if (pg_strcasecmp(defel->defname, "subtype_float") == 0)
+ {
+ if (rangeSubtypeFloatName != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options")));
+ rangeSubtypeFloatName = defGetQualifiedName(defel);
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("type attribute \"%s\" not recognized",
+ defel->defname)));
+ continue;
+ }
+ }
+
+ if (!OidIsValid(rangeSubtype))
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("type attribute \"subtype\" is required")));
+
+ if (rangeSubtypeCmpName == NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("type attribute \"subtype_cmp\" is required")));
+
+ rangeSubtypeCmp = findRangeSubtypeCmpFunction(
+ rangeSubtypeCmpName, rangeSubtype);
+
+ if (rangeSubtypeFloatName != NIL)
+ rangeSubtypeFloat = findRangeSubtypeFloatFunction(
+ rangeSubtypeFloatName, rangeSubtype);
+
+ rangeArrayOid = AssignTypeArrayOid();
+
+ /* Create the pg_type entry */
+ typoid =
+ TypeCreate(InvalidOid, /* no predetermined type OID */
+ typeName, /* type name */
+ typeNamespace, /* namespace */
+ InvalidOid, /* relation oid (n/a here) */
+ 0, /* relation kind (ditto) */
+ GetUserId(), /* owner's ID */
+ -1, /* internal size */
+ TYPTYPE_RANGE, /* type-type (range type) */
+ TYPCATEGORY_RANGE, /* type-category (range type) */
+ false, /* range types are never preferred */
+ DEFAULT_TYPDELIM, /* array element delimiter */
+ F_RANGE_IN, /* input procedure */
+ F_RANGE_OUT, /* output procedure */
+ F_RANGE_RECV, /* receive procedure */
+ F_RANGE_SEND, /* send procedure */
+ InvalidOid, /* typmodin procedure - none */
+ InvalidOid, /* typmodout procedure - none */
+ rangeAnalyze, /* analyze procedure - default */
+ InvalidOid, /* element type ID */
+ false, /* this is not an array type */
+ rangeArrayOid, /* array type we are about to create */
+ InvalidOid, /* base type ID (only for domains) */
+ NULL, /* never a default type value */
+ NULL, /* binary default isn't sent either */
+ false, /* never passed by value */
+ 'i', /* int alignment */
+ 'x', /* TOAST strategy always plain */
+ -1, /* typMod (Domains only) */
+ 0, /* Array dimensions of typbasetype */
+ false); /* Type NOT NULL */
+
+ /* create the entry in pg_range */
+ RangeCreate(typoid, rangeSubtype, rangeSubtypeCmp, rangeCanonical,
+ rangeSubtypeFloat);
+
+ /*
+ * Create the array type that goes with it.
+ */
+ rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
+
+ TypeCreate(rangeArrayOid, /* force assignment of this type OID */
+ rangeArrayName, /* type name */
+ typeNamespace, /* namespace */
+ InvalidOid, /* relation oid (n/a here) */
+ 0, /* relation kind (ditto) */
+ GetUserId(), /* owner's ID */
+ -1, /* internal size (always varlena) */
+ TYPTYPE_BASE, /* type-type (base type) */
+ TYPCATEGORY_ARRAY, /* type-category (array) */
+ false, /* array types are never preferred */
+ DEFAULT_TYPDELIM, /* array element delimiter */
+ F_ARRAY_IN, /* input procedure */
+ F_ARRAY_OUT, /* output procedure */
+ F_ARRAY_RECV, /* receive procedure */
+ F_ARRAY_SEND, /* send procedure */
+ InvalidOid, /* typmodin procedure - none */
+ InvalidOid, /* typmodout procedure - none */
+ InvalidOid, /* analyze procedure - default */
+ typoid, /* element type ID */
+ true, /* yes this is an array type */
+ InvalidOid, /* no further array type */
+ InvalidOid, /* base type ID */
+ NULL, /* never a default type value */
+ NULL, /* binary default isn't sent either */
+ false, /* never passed by value */
+ 'i', /* ranges have align i, so do their arrays */
+ 'x', /* ARRAY is always toastable */
+ -1, /* typMod (Domains only) */
+ 0, /* Array dimensions of typbasetype */
+ false); /* Type NOT NULL */
+
+ pfree(rangeArrayName);
+ }
+
+ /*
* AlterEnum
* Adds a new label to an existing enum.
*/
***************
*** 1509,1514 **** findTypeAnalyzeFunction(List *procname, Oid typeOid)
--- 1771,1893 ----
}
/*
+ * Used to find comparison function that operates on a range's subtype.
+ */
+ static Oid
+ findRangeSubtypeCmpFunction(List *procname, Oid subType)
+ {
+ Oid argList[2];
+ Oid procOid;
+ FuncCandidateList best_candidate;
+ FuncCandidateList raw_candidates;
+ FuncCandidateList cur_candidates;
+
+ /*
+ * Binary functions take two arguments of type 'typeOid'.
+ */
+ argList[0] = subType;
+ argList[1] = subType;
+
+ /*
+ * Find a matching function. We're more permissive regarding the
+ * subtype_cmp function.
+ */
+ raw_candidates = FuncnameGetCandidates(procname, 2, NIL, false, false);
+ func_match_argtypes(2, argList, raw_candidates, &cur_candidates);
+ best_candidate = func_select_candidate(2, argList, cur_candidates);
+
+ if (best_candidate == NULL || !OidIsValid(best_candidate->oid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(procname, 2, NIL, argList))));
+
+ procOid = best_candidate->oid;
+
+ if (get_func_rettype(procOid) != INT4OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("range subtype comparison function %s must return type \"integer\"",
+ func_signature_string(procname, 2, NIL, argList))));
+
+ if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("range subtype comparison function %s must be immutable",
+ func_signature_string(procname, 2, NIL, argList))));
+
+ return procOid;
+ }
+
+ /*
+ * Used to find a range's 'canonical' function.
+ */
+ static Oid
+ findRangeSubtypeFloatFunction(List *procname, Oid typeOid)
+ {
+ Oid argList[1];
+ Oid procOid;
+
+ argList[0] = typeOid;
+
+ procOid = LookupFuncName(procname, 1, argList, true);
+
+ if (!OidIsValid(procOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(procname, 1, NIL, argList))));
+
+ if (get_func_rettype(procOid) != FLOAT8OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("range subtype float function %s must return type \"float8\"",
+ func_signature_string(procname, 1, NIL, argList))));
+
+ if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("range subtype float function %s must be immutable",
+ func_signature_string(procname, 1, NIL, argList))));
+
+ return procOid;
+ }
+
+ /*
+ * Used to find a range's 'canonical' function.
+ */
+ static Oid
+ findRangeCanonicalFunction(List *procname, Oid typeOid)
+ {
+ Oid argList[1];
+ Oid procOid;
+
+ argList[0] = typeOid;
+
+ procOid = LookupFuncName(procname, 1, argList, true);
+
+ if (!OidIsValid(procOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(procname, 1, NIL, argList))));
+
+ if (get_func_rettype(procOid) != typeOid)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("range canonical function %s must return range type",
+ NameListToString(procname))));
+
+ if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("range canonical function %s must be immutable",
+ func_signature_string(procname, 1, NIL, argList))));
+
+ return procOid;
+ }
+
+ /*
* AssignTypeArrayOid
*
* Pre-assign the type's array OID for use in pg_type.typarray
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 2933,2938 **** _copyCreateEnumStmt(CreateEnumStmt *from)
--- 2933,2949 ----
return newnode;
}
+ static CreateRangeStmt *
+ _copyCreateRangeStmt(CreateRangeStmt *from)
+ {
+ CreateRangeStmt *newnode = makeNode(CreateRangeStmt);
+
+ COPY_NODE_FIELD(typeName);
+ COPY_NODE_FIELD(params);
+
+ return newnode;
+ }
+
static AlterEnumStmt *
_copyAlterEnumStmt(AlterEnumStmt *from)
{
***************
*** 4129,4134 **** copyObject(void *from)
--- 4140,4148 ----
case T_CreateEnumStmt:
retval = _copyCreateEnumStmt(from);
break;
+ case T_CreateRangeStmt:
+ retval = _copyCreateRangeStmt(from);
+ break;
case T_AlterEnumStmt:
retval = _copyAlterEnumStmt(from);
break;
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 1406,1411 **** _equalCreateEnumStmt(CreateEnumStmt *a, CreateEnumStmt *b)
--- 1406,1420 ----
}
static bool
+ _equalCreateRangeStmt(CreateRangeStmt *a, CreateRangeStmt *b)
+ {
+ COMPARE_NODE_FIELD(typeName);
+ COMPARE_NODE_FIELD(params);
+
+ return true;
+ }
+
+ static bool
_equalAlterEnumStmt(AlterEnumStmt *a, AlterEnumStmt *b)
{
COMPARE_NODE_FIELD(typeName);
***************
*** 2742,2747 **** equal(void *a, void *b)
--- 2751,2759 ----
case T_CreateEnumStmt:
retval = _equalCreateEnumStmt(a, b);
break;
+ case T_CreateRangeStmt:
+ retval = _equalCreateRangeStmt(a, b);
+ break;
case T_AlterEnumStmt:
retval = _equalAlterEnumStmt(a, b);
break;
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 3908,3913 **** DefineStmt:
--- 3908,3920 ----
n->vals = $7;
$$ = (Node *)n;
}
+ | CREATE TYPE_P any_name AS RANGE definition
+ {
+ CreateRangeStmt *n = makeNode(CreateRangeStmt);
+ n->typeName = $3;
+ n->params = $6;
+ $$ = (Node *)n;
+ }
| CREATE TEXT_P SEARCH PARSER any_name definition
{
DefineStmt *n = makeNode(DefineStmt);
*** a/src/backend/parser/parse_coerce.c
--- b/src/backend/parser/parse_coerce.c
***************
*** 142,147 **** coerce_type(ParseState *pstate, Node *node,
--- 142,148 ----
targetTypeId == ANYELEMENTOID ||
targetTypeId == ANYNONARRAYOID ||
(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID) ||
+ (targetTypeId == ANYRANGEOID && inputTypeId != UNKNOWNOID) ||
(targetTypeId == ANYENUMOID && inputTypeId != UNKNOWNOID))
{
/*
***************
*** 1246,1251 **** check_generic_type_consistency(Oid *actual_arg_types,
--- 1247,1254 ----
Oid elem_typeid = InvalidOid;
Oid array_typeid = InvalidOid;
Oid array_typelem;
+ Oid range_typeid = InvalidOid;
+ Oid range_typelem;
bool have_anyelement = false;
bool have_anynonarray = false;
bool have_anyenum = false;
***************
*** 1282,1287 **** check_generic_type_consistency(Oid *actual_arg_types,
--- 1285,1298 ----
return false;
array_typeid = actual_type;
}
+ else if (decl_type == ANYRANGEOID)
+ {
+ if (actual_type == UNKNOWNOID)
+ continue;
+ if (OidIsValid(range_typeid) && actual_type != range_typeid)
+ return false;
+ range_typeid = actual_type;
+ }
}
/* Get the element type based on the array type, if we have one */
***************
*** 1327,1332 **** check_generic_type_consistency(Oid *actual_arg_types,
--- 1338,1364 ----
return false;
}
+ /* Get the element type based on the range type, if we have one */
+ if (OidIsValid(range_typeid))
+ {
+ range_typelem = get_range_subtype(range_typeid);
+ if (!OidIsValid(range_typelem))
+ return false; /* should be an array, but isn't */
+
+ if (!OidIsValid(elem_typeid))
+ {
+ /*
+ * if we don't have an element type yet, use the one we just got
+ */
+ elem_typeid = range_typelem;
+ }
+ else if (range_typelem != elem_typeid)
+ {
+ /* otherwise, they better match */
+ return false;
+ }
+ }
+
/* Looks valid */
return true;
}
***************
*** 1403,1409 **** enforce_generic_type_consistency(Oid *actual_arg_types,
--- 1435,1443 ----
bool have_unknowns = false;
Oid elem_typeid = InvalidOid;
Oid array_typeid = InvalidOid;
+ Oid range_typeid = InvalidOid;
Oid array_typelem;
+ Oid range_typelem;
bool have_anyelement = (rettype == ANYELEMENTOID ||
rettype == ANYNONARRAYOID ||
rettype == ANYENUMOID);
***************
*** 1463,1468 **** enforce_generic_type_consistency(Oid *actual_arg_types,
--- 1497,1521 ----
format_type_be(actual_type))));
array_typeid = actual_type;
}
+ else if (decl_type == ANYRANGEOID)
+ {
+ have_generics = true;
+ if (actual_type == UNKNOWNOID)
+ {
+ have_unknowns = true;
+ continue;
+ }
+ if (allow_poly && decl_type == actual_type)
+ continue; /* no new information here */
+ if (OidIsValid(range_typeid) && actual_type != range_typeid)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("arguments declared \"anyrange\" are not all alike"),
+ errdetail("%s versus %s",
+ format_type_be(range_typeid),
+ format_type_be(actual_type))));
+ range_typeid = actual_type;
+ }
}
/*
***************
*** 1508,1513 **** enforce_generic_type_consistency(Oid *actual_arg_types,
--- 1561,1594 ----
format_type_be(elem_typeid))));
}
}
+ /* Get the element type based on the range type, if we have one */
+ else if (OidIsValid(range_typeid))
+ {
+ range_typelem = get_range_subtype(range_typeid);
+ if (!OidIsValid(range_typelem))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("argument declared \"anyrange\" is not a range but type %s",
+ format_type_be(range_typeid))));
+
+ if (!OidIsValid(elem_typeid))
+ {
+ /*
+ * if we don't have an element type yet, use the one we just got
+ */
+ elem_typeid = range_typelem;
+ }
+ else if (range_typelem != elem_typeid)
+ {
+ /* otherwise, they better match */
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("argument declared \"anyrange\" is not consistent with argument declared \"anyelement\""),
+ errdetail("%s versus %s",
+ format_type_be(range_typeid),
+ format_type_be(elem_typeid))));
+ }
+ }
else if (!OidIsValid(elem_typeid))
{
if (allow_poly)
***************
*** 1574,1579 **** enforce_generic_type_consistency(Oid *actual_arg_types,
--- 1655,1673 ----
}
declared_arg_types[j] = array_typeid;
}
+ else if (decl_type == ANYRANGEOID)
+ {
+ if (!OidIsValid(range_typeid))
+ {
+ range_typeid = get_range_subtype(elem_typeid);
+ if (!OidIsValid(range_typeid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find range type for data type %s",
+ format_type_be(elem_typeid))));
+ }
+ declared_arg_types[j] = range_typeid;
+ }
}
}
***************
*** 1592,1597 **** enforce_generic_type_consistency(Oid *actual_arg_types,
--- 1686,1706 ----
return array_typeid;
}
+ /* if we return ANYRANGE use the appropriate argument type */
+ if (rettype == ANYRANGEOID)
+ {
+ if (!OidIsValid(range_typeid))
+ {
+ range_typeid = get_range_from_subtype(elem_typeid);
+ if (!OidIsValid(range_typeid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find range type for data type %s",
+ format_type_be(elem_typeid))));
+ }
+ return range_typeid;
+ }
+
/* if we return ANYELEMENT use the appropriate argument type */
if (rettype == ANYELEMENTOID ||
rettype == ANYNONARRAYOID ||
***************
*** 1636,1642 **** resolve_generic_type(Oid declared_type,
}
else if (context_declared_type == ANYELEMENTOID ||
context_declared_type == ANYNONARRAYOID ||
! context_declared_type == ANYENUMOID)
{
/* Use the array type corresponding to actual type */
Oid array_typeid = get_array_type(context_actual_type);
--- 1745,1752 ----
}
else if (context_declared_type == ANYELEMENTOID ||
context_declared_type == ANYNONARRAYOID ||
! context_declared_type == ANYENUMOID ||
! context_declared_type == ANYRANGEOID)
{
/* Use the array type corresponding to actual type */
Oid array_typeid = get_array_type(context_actual_type);
***************
*** 1651,1657 **** resolve_generic_type(Oid declared_type,
}
else if (declared_type == ANYELEMENTOID ||
declared_type == ANYNONARRAYOID ||
! declared_type == ANYENUMOID)
{
if (context_declared_type == ANYARRAYOID)
{
--- 1761,1768 ----
}
else if (declared_type == ANYELEMENTOID ||
declared_type == ANYNONARRAYOID ||
! declared_type == ANYENUMOID ||
! declared_type == ANYRANGEOID)
{
if (context_declared_type == ANYARRAYOID)
{
***************
*** 1665,1670 **** resolve_generic_type(Oid declared_type,
--- 1776,1793 ----
format_type_be(context_actual_type))));
return array_typelem;
}
+ else if (context_declared_type == ANYRANGEOID)
+ {
+ /* Use the element type corresponding to actual type */
+ Oid range_typelem = get_range_subtype(context_actual_type);
+
+ if (!OidIsValid(range_typelem))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("argument declared \"anyrange\" is not an range but type %s",
+ format_type_be(context_actual_type))));
+ return range_typelem;
+ }
else if (context_declared_type == ANYELEMENTOID ||
context_declared_type == ANYNONARRAYOID ||
context_declared_type == ANYENUMOID)
***************
*** 1778,1783 **** IsBinaryCoercible(Oid srctype, Oid targettype)
--- 1901,1911 ----
if (type_is_enum(srctype))
return true;
+ /* Also accept any enum type as coercible to ANYRANGE */
+ if (targettype == ANYRANGEOID)
+ if (type_is_range(srctype))
+ return true;
+
/* Also accept any composite type as coercible to RECORD */
if (targettype == RECORDOID)
if (ISCOMPLEX(srctype))
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 190,195 **** check_xact_readonly(Node *parsetree)
--- 190,196 ----
case T_CreateTrigStmt:
case T_CompositeTypeStmt:
case T_CreateEnumStmt:
+ case T_CreateRangeStmt:
case T_AlterEnumStmt:
case T_ViewStmt:
case T_DropCastStmt:
***************
*** 880,885 **** standard_ProcessUtility(Node *parsetree,
--- 881,890 ----
DefineEnum((CreateEnumStmt *) parsetree);
break;
+ case T_CreateRangeStmt:
+ DefineRange((CreateRangeStmt *) parsetree);
+ break;
+
case T_AlterEnumStmt: /* ALTER TYPE (enum) */
/*
* We disallow this in transaction blocks, because we can't cope
***************
*** 1937,1942 **** CreateCommandTag(Node *parsetree)
--- 1942,1951 ----
tag = "CREATE TYPE";
break;
+ case T_CreateRangeStmt:
+ tag = "CREATE TYPE";
+ break;
+
case T_AlterEnumStmt:
tag = "ALTER TYPE";
break;
***************
*** 2484,2489 **** GetCommandLogLevel(Node *parsetree)
--- 2493,2502 ----
lev = LOGSTMT_DDL;
break;
+ case T_CreateRangeStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_AlterEnumStmt:
lev = LOGSTMT_DDL;
break;
*** a/src/backend/utils/adt/Makefile
--- b/src/backend/utils/adt/Makefile
***************
*** 20,27 **** OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
enum.o float.o format_type.o \
geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o \
misc.o nabstime.o name.o numeric.o numutils.o \
! oid.o oracle_compat.o pseudotypes.o rowtypes.o \
! regexp.o regproc.o ruleutils.o selfuncs.o \
tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \
network.o mac.o inet_cidr_ntop.o inet_net_pton.o \
ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
--- 20,27 ----
enum.o float.o format_type.o \
geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o \
misc.o nabstime.o name.o numeric.o numutils.o \
! oid.o oracle_compat.o pseudotypes.o rangetypes.o rangetypes_gist.o \
! rowtypes.o regexp.o regproc.o ruleutils.o selfuncs.o \
tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \
network.o mac.o inet_cidr_ntop.o inet_net_pton.o \
ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
*** a/src/backend/utils/adt/date.c
--- b/src/backend/utils/adt/date.c
***************
*** 888,893 **** date_timestamp(PG_FUNCTION_ARGS)
--- 888,900 ----
PG_RETURN_TIMESTAMP(result);
}
+ Datum
+ date_float8(PG_FUNCTION_ARGS)
+ {
+ DateADT dateVal = PG_GETARG_DATEADT(0);
+
+ PG_RETURN_FLOAT8((float8) dateVal);
+ }
/* timestamp_date()
* Convert timestamp to date data type.
*** a/src/backend/utils/adt/pseudotypes.c
--- b/src/backend/utils/adt/pseudotypes.c
***************
*** 25,30 ****
--- 25,31 ----
#include "libpq/pqformat.h"
#include "utils/array.h"
#include "utils/builtins.h"
+ #include "utils/rangetypes.h"
/*
***************
*** 187,192 **** anyenum_out(PG_FUNCTION_ARGS)
--- 188,216 ----
return enum_out(fcinfo);
}
+ /*
+ * anyrange_in - input routine for pseudo-type ANYRANGE.
+ */
+ Datum
+ anyrange_in(PG_FUNCTION_ARGS)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot accept a value of type anyrange")));
+
+ PG_RETURN_VOID(); /* keep compiler quiet */
+ }
+
+ /*
+ * anyrange_out - output routine for pseudo-type ANYRANGE.
+ *
+ * We may as well allow this, since range_out will in fact work.
+ */
+ Datum
+ anyrange_out(PG_FUNCTION_ARGS)
+ {
+ return range_out(fcinfo);
+ }
/*
* void_in - input routine for pseudo-type VOID.
*** /dev/null
--- b/src/backend/utils/adt/rangetypes.c
***************
*** 0 ****
--- 1,1703 ----
+ /*-------------------------------------------------------------------------
+ *
+ * rangetypes.c
+ * I/O functions, operators, and support functions for range types
+ *
+ * Copyright (c) 2006-2011, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/utils/adt/rangetypes.c
+ *
+ *-------------------------------------------------------------------------
+ */
+ #include "postgres.h"
+
+ #include "access/hash.h"
+ #include "catalog/pg_range.h"
+ #include "catalog/pg_type.h"
+ #include "fmgr.h"
+ #include "lib/stringinfo.h"
+ #include "utils/builtins.h"
+ #include "utils/date.h"
+ #include "utils/fmgroids.h"
+ #include "utils/lsyscache.h"
+ #include "utils/rangetypes.h"
+ #include "utils/typcache.h"
+
+ /* flags */
+ #define RANGE_EMPTY 0x01
+ #define RANGE_LB_INC 0x02
+ #define RANGE_LB_NULL 0x04
+ #define RANGE_LB_INF 0x08
+ #define RANGE_UB_INC 0x10
+ #define RANGE_UB_NULL 0x20
+ #define RANGE_UB_INF 0x40
+
+ #define RANGE_HAS_LBOUND(flags) (!(flags & (RANGE_EMPTY | \
+ RANGE_LB_NULL | \
+ RANGE_LB_INF)))
+
+ #define RANGE_HAS_UBOUND(flags) (!(flags & (RANGE_EMPTY | \
+ RANGE_UB_NULL | \
+ RANGE_UB_INF)))
+ typedef enum
+ {
+ RANGE_PSTATE_INIT,
+ RANGE_PSTATE_PRE_LB,
+ RANGE_PSTATE_LB,
+ RANGE_PSTATE_SEP,
+ RANGE_PSTATE_PRE_UB,
+ RANGE_PSTATE_UB,
+ RANGE_PSTATE_UB_INC,
+ RANGE_PSTATE_DONE
+ } RangePState;
+
+ static void range_parse(const char *input_str, char *flags,
+ char **lbound_str, char **ubound_str);
+ static char *range_deparse(char flags, char *lbound_str, char *ubound_str);
+ static Datum range_make2(PG_FUNCTION_ARGS);
+ static bool range_contains_internal(RangeType *r1, RangeType *r2);
+
+ /*
+ *----------------------------------------------------------
+ * I/O FUNCTIONS
+ *----------------------------------------------------------
+ */
+
+ Datum
+ range_in(PG_FUNCTION_ARGS)
+ {
+ char *input_str = PG_GETARG_CSTRING(0);
+ Oid rngtypoid = PG_GETARG_OID(1);
+ Oid typmod = PG_GETARG_INT32(2);
+
+ char flags;
+ Datum range;
+ char *lbound_str;
+ char *ubound_str;
+
+ Oid subtype;
+ regproc subInput;
+ FmgrInfo subInputFn;
+ Oid ioParam;
+
+ RangeBound lower;
+ RangeBound upper;
+
+ if (rngtypoid == ANYRANGEOID)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot accept a value of type anyrange")));
+
+ subtype = get_range_subtype(rngtypoid);
+
+ /* parse */
+ range_parse(input_str, &flags, &lbound_str, &ubound_str);
+
+ /* input */
+ getTypeInputInfo(subtype, &subInput, &ioParam);
+ fmgr_info(subInput, &subInputFn);
+
+ lower.rngtypid = rngtypoid;
+ lower.infinite = flags & RANGE_LB_INF;
+ lower.inclusive = flags & RANGE_LB_INC;
+ lower.lower = true;
+ upper.rngtypid = rngtypoid;
+ upper.infinite = flags & RANGE_UB_INF;
+ upper.inclusive = flags & RANGE_UB_INC;
+ upper.lower = false;
+
+ if (RANGE_HAS_LBOUND(flags))
+ lower.val = InputFunctionCall(&subInputFn, lbound_str,
+ ioParam, typmod);
+ if (RANGE_HAS_UBOUND(flags))
+ upper.val = InputFunctionCall(&subInputFn, ubound_str,
+ ioParam, typmod);
+
+ /* serialize and canonicalize */
+ range = make_range(&lower, &upper, flags & RANGE_EMPTY);
+
+ PG_RETURN_RANGE(range);
+ }
+
+ Datum
+ range_out(PG_FUNCTION_ARGS)
+ {
+ RangeType *range = PG_GETARG_RANGE(0);
+
+ Oid subtype;
+
+ regproc subOutput;
+ FmgrInfo subOutputFn;
+ bool isVarlena;
+
+ char flags = 0;
+ char *lbound_str = NULL;
+ char *ubound_str = NULL;
+ char *output_str;
+
+ bool empty;
+ RangeBound lower;
+ RangeBound upper;
+
+ /* deserialize */
+ range_deserialize(range, &lower, &upper, &empty);
+
+ if (lower.rngtypid != upper.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ subtype = get_range_subtype(lower.rngtypid);
+
+ if (empty)
+ flags |= RANGE_EMPTY;
+
+ flags |= (lower.inclusive) ? RANGE_LB_INC : 0;
+ flags |= (lower.infinite) ? RANGE_LB_INF : 0;
+ flags |= (upper.inclusive) ? RANGE_UB_INC : 0;
+ flags |= (upper.infinite) ? RANGE_UB_INF : 0;
+
+ /* output */
+ getTypeOutputInfo(subtype, &subOutput, &isVarlena);
+ fmgr_info(subOutput, &subOutputFn);
+
+ if (RANGE_HAS_LBOUND(flags))
+ lbound_str = OutputFunctionCall(&subOutputFn, lower.val);
+ if (RANGE_HAS_UBOUND(flags))
+ ubound_str = OutputFunctionCall(&subOutputFn, upper.val);
+
+ /* deparse */
+ output_str = range_deparse(flags, lbound_str, ubound_str);
+
+ PG_RETURN_CSTRING(output_str);
+ }
+
+ Datum
+ range_recv(PG_FUNCTION_ARGS)
+ {
+ PG_RETURN_VOID();
+ }
+
+ Datum
+ range_send(PG_FUNCTION_ARGS)
+ {
+ PG_RETURN_VOID();
+ }
+
+
+ /*
+ *----------------------------------------------------------
+ * GENERIC FUNCTIONS
+ *----------------------------------------------------------
+ */
+
+
+ /* constructors */
+
+ Datum
+ range_make1(PG_FUNCTION_ARGS)
+ {
+ Datum arg = PG_GETARG_DATUM(0);
+ Oid subtype = get_fn_expr_argtype(fcinfo->flinfo,0);
+ Oid rngtypid = get_range_from_subtype(subtype);
+ RangeType *range;
+ RangeBound lower;
+ RangeBound upper;
+
+ if (PG_ARGISNULL(0))
+ elog(ERROR, "NULL range boundaries are not supported");
+
+ if (!OidIsValid(subtype) || !OidIsValid(rngtypid))
+ elog(ERROR, "cannot determine argument types");
+
+ lower.rngtypid = rngtypid;
+ lower.inclusive = true;
+ lower.val = arg;
+ lower.lower = true;
+ lower.infinite = false;
+ upper.rngtypid = rngtypid;
+ upper.inclusive = true;
+ upper.val = arg;
+ upper.lower = false;
+ upper.infinite = false;
+
+ range = DatumGetRangeType(make_range(&lower, &upper, false));
+
+ PG_RETURN_RANGE(range);
+ }
+
+ Datum
+ range_linf_(PG_FUNCTION_ARGS)
+ {
+ Datum arg = PG_GETARG_DATUM(0);
+ Oid subtype = get_fn_expr_argtype(fcinfo->flinfo,0);
+ Oid rngtypid = get_range_from_subtype(subtype);
+ RangeType *range;
+ RangeBound lower;
+ RangeBound upper;
+
+ if (PG_ARGISNULL(0))
+ elog(ERROR, "NULL range boundaries are not supported");
+
+ lower.rngtypid = rngtypid;
+ lower.inclusive = false;
+ lower.infinite = true;
+ lower.lower = true;
+ lower.val = (Datum) 0;
+
+ upper.rngtypid = rngtypid;
+ upper.inclusive = false;
+ upper.infinite = false;
+ upper.lower = false;
+ upper.val = arg;
+
+ range = DatumGetRangeType(make_range(&lower, &upper, false));
+
+ PG_RETURN_RANGE(range);
+ }
+
+ Datum
+ range_uinf_(PG_FUNCTION_ARGS)
+ {
+ Datum arg = PG_GETARG_DATUM(0);
+ Oid subtype = get_fn_expr_argtype(fcinfo->flinfo,0);
+ Oid rngtypid = get_range_from_subtype(subtype);
+ RangeType *range;
+ RangeBound lower;
+ RangeBound upper;
+
+ if (PG_ARGISNULL(0))
+ elog(ERROR, "NULL range boundaries are not supported");
+
+ lower.rngtypid = rngtypid;
+ lower.inclusive = false;
+ lower.infinite = false;
+ lower.lower = true;
+ lower.val = arg;
+
+ upper.rngtypid = rngtypid;
+ upper.inclusive = false;
+ upper.infinite = true;
+ upper.lower = false;
+ upper.val = (Datum) 0;
+
+ range = DatumGetRangeType(make_range(&lower, &upper, false));
+
+ PG_RETURN_RANGE(range);
+ }
+
+ Datum
+ range_linfi(PG_FUNCTION_ARGS)
+ {
+ Datum arg = PG_GETARG_DATUM(0);
+ Oid subtype = get_fn_expr_argtype(fcinfo->flinfo,0);
+ Oid rngtypid = get_range_from_subtype(subtype);
+ RangeType *range;
+ RangeBound lower;
+ RangeBound upper;
+
+ if (PG_ARGISNULL(0))
+ elog(ERROR, "NULL range boundaries are not supported");
+
+ lower.rngtypid = rngtypid;
+ lower.inclusive = false;
+ lower.infinite = true;
+ lower.lower = true;
+ lower.val = (Datum) 0;
+
+ upper.rngtypid = rngtypid;
+ upper.inclusive = true;
+ upper.infinite = false;
+ upper.lower = false;
+ upper.val = arg;
+
+ range = DatumGetRangeType(make_range(&lower, &upper, false));
+
+ PG_RETURN_RANGE(range);
+ }
+
+ Datum
+ range_uinfi(PG_FUNCTION_ARGS)
+ {
+ Datum arg = PG_GETARG_DATUM(0);
+ Oid subtype = get_fn_expr_argtype(fcinfo->flinfo,0);
+ Oid rngtypid = get_range_from_subtype(subtype);
+ RangeType *range;
+ RangeBound lower;
+ RangeBound upper;
+
+ if (PG_ARGISNULL(0))
+ elog(ERROR, "NULL range boundaries are not supported");
+
+ lower.rngtypid = rngtypid;
+ lower.inclusive = true;
+ lower.infinite = false;
+ lower.lower = true;
+ lower.val = arg;
+
+ upper.rngtypid = rngtypid;
+ upper.inclusive = false;
+ upper.infinite = true;
+ upper.lower = false;
+ upper.val = (Datum) 0;
+
+ range = DatumGetRangeType(make_range(&lower, &upper, false));
+
+ PG_RETURN_RANGE(range);
+ }
+
+ Datum
+ range(PG_FUNCTION_ARGS)
+ {
+ return range_make2(fcinfo);
+ }
+
+ Datum
+ range__(PG_FUNCTION_ARGS)
+ {
+ return range_make2(fcinfo);
+ }
+
+ Datum
+ range_i(PG_FUNCTION_ARGS)
+ {
+ return range_make2(fcinfo);
+ }
+
+ Datum
+ rangei_(PG_FUNCTION_ARGS)
+ {
+ return range_make2(fcinfo);
+ }
+
+ Datum
+ rangeii(PG_FUNCTION_ARGS)
+ {
+ return range_make2(fcinfo);
+ }
+
+ /* range -> subtype */
+ Datum
+ range_lower(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+
+ range_deserialize(r1, &lower, &upper, &empty);
+
+ if (empty)
+ elog(ERROR, "range is empty");
+ if (lower.infinite)
+ elog(ERROR, "range lower bound is infinite");
+
+ PG_RETURN_DATUM(lower.val);
+ }
+
+ Datum
+ range_upper(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+
+ range_deserialize(r1, &lower, &upper, &empty);
+
+ if (empty)
+ elog(ERROR, "range is empty");
+ if (upper.infinite)
+ elog(ERROR, "range lower bound is infinite");
+
+ PG_RETURN_DATUM(upper.val);
+ }
+
+
+ /* range -> bool */
+ Datum
+ range_empty(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+
+ range_deserialize(r1, &lower, &upper, &empty);
+
+ PG_RETURN_BOOL(empty);
+ }
+
+ Datum
+ range_non_empty(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+
+ range_deserialize(r1, &lower, &upper, &empty);
+
+ PG_RETURN_BOOL(!empty);
+ }
+
+ Datum
+ range_lower_inc(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+
+ range_deserialize(r1, &lower, &upper, &empty);
+
+ PG_RETURN_BOOL(lower.inclusive);
+ }
+
+ Datum
+ range_upper_inc(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+
+ range_deserialize(r1, &lower, &upper, &empty);
+
+ PG_RETURN_BOOL(upper.inclusive);
+ }
+
+ Datum
+ range_lower_inf(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+
+ range_deserialize(r1, &lower, &upper, &empty);
+
+ PG_RETURN_BOOL(lower.infinite);
+ }
+
+ Datum
+ range_upper_inf(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+
+ range_deserialize(r1, &lower, &upper, &empty);
+
+ PG_RETURN_BOOL(upper.infinite);
+ }
+
+
+ /* range, range -> bool */
+ Datum
+ range_eq(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (lower1.rngtypid != upper1.rngtypid ||
+ lower1.rngtypid != lower2.rngtypid ||
+ lower1.rngtypid != upper2.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty1 && empty2)
+ PG_RETURN_BOOL(true);
+ if (empty1 != empty2)
+ PG_RETURN_BOOL(false);
+
+ if (range_cmp_bounds(&lower1, &lower2) != 0)
+ PG_RETURN_BOOL(false);
+
+ if (range_cmp_bounds(&upper1, &upper2) != 0)
+ PG_RETURN_BOOL(false);
+
+ PG_RETURN_BOOL(true);
+ }
+
+ Datum
+ range_ne(PG_FUNCTION_ARGS)
+ {
+ bool eq = DatumGetBool(range_eq(fcinfo));
+
+ PG_RETURN_BOOL(!eq);
+ }
+
+ Datum
+ range_contains_elem(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2;
+ Datum val = PG_GETARG_DATUM(1);
+ Oid rngtypid = get_fn_expr_argtype(fcinfo->flinfo,0);
+ RangeBound lower;
+ RangeBound upper;
+
+ lower.rngtypid = rngtypid;
+ lower.inclusive = true;
+ lower.infinite = false;
+ lower.lower = true;
+ lower.val = val;
+
+ upper.rngtypid = rngtypid;
+ upper.inclusive = true;
+ upper.infinite = false;
+ upper.lower = false;
+ upper.val = val;
+
+ r2 = DatumGetRangeType(make_range(&lower, &upper, false));
+
+ PG_RETURN_BOOL(range_contains_internal(r1, r2));
+ }
+
+ Datum
+ range_contains(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ PG_RETURN_BOOL(range_contains_internal(r1, r2));
+ }
+
+ Datum
+ elem_contained_by_range(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(1);
+ RangeType *r2;
+ Datum val = PG_GETARG_DATUM(0);
+ Oid rngtypid = get_fn_expr_argtype(fcinfo->flinfo,1);
+ RangeBound lower;
+ RangeBound upper;
+
+ lower.rngtypid = rngtypid;
+ lower.inclusive = true;
+ lower.infinite = false;
+ lower.lower = true;
+ lower.val = val;
+
+ upper.rngtypid = rngtypid;
+ upper.inclusive = true;
+ upper.infinite = false;
+ upper.lower = false;
+ upper.val = val;
+
+ r2 = DatumGetRangeType(make_range(&lower, &upper, false));
+
+ PG_RETURN_BOOL(range_contains_internal(r1, r2));
+ }
+
+ Datum
+ range_contained_by(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ PG_RETURN_BOOL(range_contains_internal(r2, r1));
+ }
+
+ Datum
+ range_before(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (lower1.rngtypid != upper1.rngtypid ||
+ lower1.rngtypid != lower2.rngtypid ||
+ lower1.rngtypid != upper2.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty1 || empty2)
+ elog(ERROR, "empty range");
+
+ if (range_cmp_bounds(&upper1, &lower2) < 0)
+ PG_RETURN_BOOL(true);
+ else
+ PG_RETURN_BOOL(false);
+ }
+
+ Datum
+ range_after(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (lower1.rngtypid != upper1.rngtypid ||
+ lower1.rngtypid != lower2.rngtypid ||
+ lower1.rngtypid != upper2.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty1 || empty2)
+ elog(ERROR, "empty range");
+
+ if (range_cmp_bounds(&lower1, &upper2) > 0)
+ PG_RETURN_BOOL(true);
+ else
+ PG_RETURN_BOOL(false);
+ }
+
+ Datum range_adjacent(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ Oid cmpFn;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (lower1.rngtypid != upper1.rngtypid ||
+ lower1.rngtypid != lower2.rngtypid ||
+ lower1.rngtypid != upper2.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty1 || empty2)
+ elog(ERROR, "empty range");
+
+ /*
+ * For two ranges to be adjacent, the lower boundary of one range
+ * has to match the upper boundary of the other. However, the
+ * inclusivity of those two boundaries must also be different.
+ *
+ * The semantics for range_cmp_bounds aren't quite what we need
+ * here, so we do the comparison more directly.
+ */
+
+ cmpFn = get_range_subtype_cmp(lower1.rngtypid);
+
+ if (lower1.inclusive != upper2.inclusive)
+ {
+ if (DatumGetInt32(OidFunctionCall2(cmpFn, lower1.val, upper2.val)) == 0)
+ PG_RETURN_BOOL(true);
+ }
+
+ if (upper1.inclusive != lower2.inclusive)
+ {
+ if (DatumGetInt32(OidFunctionCall2(cmpFn, upper1.val, lower2.val)) == 0)
+ PG_RETURN_BOOL(true);
+ }
+
+ PG_RETURN_BOOL(false);
+ }
+
+ Datum
+ range_overlaps(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (lower1.rngtypid != upper1.rngtypid ||
+ lower1.rngtypid != lower2.rngtypid ||
+ lower1.rngtypid != upper2.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty1 || empty2)
+ PG_RETURN_BOOL(false);
+
+ if (range_cmp_bounds(&lower1, &lower2) >= 0 &&
+ range_cmp_bounds(&lower1, &upper2) <= 0)
+ PG_RETURN_BOOL(true);
+
+ if (range_cmp_bounds(&lower2, &lower1) >= 0 &&
+ range_cmp_bounds(&lower2, &upper1) <= 0)
+ PG_RETURN_BOOL(true);
+
+ PG_RETURN_BOOL(false);
+ }
+
+ Datum
+ range_overleft(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (lower1.rngtypid != upper1.rngtypid ||
+ lower1.rngtypid != lower2.rngtypid ||
+ lower1.rngtypid != upper2.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty1 || empty2)
+ PG_RETURN_BOOL(false);
+
+ if (range_cmp_bounds(&upper1, &upper2) <= 0)
+ PG_RETURN_BOOL(true);
+
+ PG_RETURN_BOOL(false);
+ }
+
+ Datum
+ range_overright(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (lower1.rngtypid != upper1.rngtypid ||
+ lower1.rngtypid != lower2.rngtypid ||
+ lower1.rngtypid != upper2.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty1 || empty2)
+ PG_RETURN_BOOL(false);
+
+ if (range_cmp_bounds(&lower1, &lower2) >= 0)
+ PG_RETURN_BOOL(true);
+
+ PG_RETURN_BOOL(false);
+ }
+
+
+ /* range, range -> range */
+ Datum
+ range_minus(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ int cmp_l1l2, cmp_l1u2, cmp_u1l2, cmp_u1u2;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (lower1.rngtypid != upper1.rngtypid ||
+ lower1.rngtypid != lower2.rngtypid ||
+ lower1.rngtypid != upper2.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty1 || empty2)
+ PG_RETURN_RANGE(r1);
+
+ cmp_l1l2 = range_cmp_bounds(&lower1, &lower2);
+ cmp_l1u2 = range_cmp_bounds(&lower1, &upper2);
+ cmp_u1l2 = range_cmp_bounds(&upper1, &lower2);
+ cmp_u1u2 = range_cmp_bounds(&upper1, &upper2);
+
+ if (cmp_l1l2 < 0 && cmp_u1u2 > 0)
+ elog(ERROR, "range_minus resulted in two ranges");
+
+ if (cmp_l1u2 > 0 || cmp_u1l2 < 0)
+ PG_RETURN_RANGE(r1);
+
+ if (cmp_l1l2 >= 0 && cmp_u1u2 <= 0)
+ PG_RETURN_RANGE(make_empty_range(lower1.rngtypid));
+
+ if (cmp_l1l2 <= 0 && cmp_u1l2 >= 0 && cmp_u1u2 <= 0)
+ {
+ lower2.inclusive = !lower2.inclusive;
+ lower2.lower = false; /* it will become the upper bound */
+ PG_RETURN_RANGE(make_range(&lower1, &lower2, false));
+ }
+
+ if (cmp_l1l2 >= 0 && cmp_u1u2 >= 0 && cmp_l1u2 <= 0)
+ {
+ upper2.inclusive = !upper2.inclusive;
+ upper2.lower = true; /* it will become the lower bound */
+ PG_RETURN_RANGE(make_range(&upper2, &upper1, false));
+ }
+
+ elog(ERROR, "unexpected error in range_minus");
+ PG_RETURN_VOID();
+ }
+
+ Datum
+ range_union(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+ RangeBound *result_lower;
+ RangeBound *result_upper;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (empty1)
+ PG_RETURN_RANGE(r2);
+ if (empty2)
+ PG_RETURN_RANGE(r1);
+
+ if (!DatumGetBool(range_overlaps(fcinfo)) &&
+ !DatumGetBool(range_adjacent(fcinfo)))
+ elog(ERROR, "range union resulted in two ranges");
+
+ if (range_cmp_bounds(&lower1, &lower2) < 0)
+ result_lower = &lower1;
+ else
+ result_lower = &lower2;
+
+ if (range_cmp_bounds(&upper1, &upper2) > 0)
+ result_upper = &upper1;
+ else
+ result_upper = &upper2;
+
+ PG_RETURN_RANGE(make_range(result_lower, result_upper, false));
+ }
+
+ Datum
+ range_intersect(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+ RangeBound *result_lower;
+ RangeBound *result_upper;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (empty1 || empty2 || !DatumGetBool(range_overlaps(fcinfo)))
+ PG_RETURN_RANGE(make_empty_range(lower1.rngtypid));
+
+ if (range_cmp_bounds(&lower1, &lower2) >= 0)
+ result_lower = &lower1;
+ else
+ result_lower = &lower2;
+
+ if (range_cmp_bounds(&upper1, &upper2) <= 0)
+ result_upper = &upper1;
+ else
+ result_upper = &upper2;
+
+ PG_RETURN_RANGE(make_range(result_lower, result_upper, false));
+ }
+
+ /* Btree support */
+
+ Datum
+ range_cmp(PG_FUNCTION_ARGS)
+ {
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ int cmp;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (lower1.rngtypid != upper1.rngtypid ||
+ lower1.rngtypid != lower2.rngtypid ||
+ lower1.rngtypid != upper2.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty1 && empty2)
+ PG_RETURN_INT32(0);
+ else if (empty1)
+ PG_RETURN_INT32(-1);
+ else if (empty2)
+ PG_RETURN_INT32(1);
+
+ if ((cmp = range_cmp_bounds(&lower1, &lower2)) != 0)
+ PG_RETURN_INT32(cmp);
+
+ PG_RETURN_INT32(range_cmp_bounds(&upper1, &upper2));
+ }
+
+ Datum
+ range_lt(PG_FUNCTION_ARGS)
+ {
+ int cmp = range_cmp(fcinfo);
+ PG_RETURN_BOOL(cmp < 0);
+ }
+
+ Datum
+ range_le(PG_FUNCTION_ARGS)
+ {
+ int cmp = range_cmp(fcinfo);
+ PG_RETURN_BOOL(cmp <= 0);
+ }
+
+ Datum
+ range_ge(PG_FUNCTION_ARGS)
+ {
+ int cmp = range_cmp(fcinfo);
+ PG_RETURN_BOOL(cmp >= 0);
+ }
+
+ Datum
+ range_gt(PG_FUNCTION_ARGS)
+ {
+ int cmp = range_cmp(fcinfo);
+ PG_RETURN_BOOL(cmp > 0);
+ }
+
+ /* Hash support */
+ Datum
+ hash_range(PG_FUNCTION_ARGS)
+ {
+ RangeType *r = PG_GETARG_RANGE(0);
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+ char flags = 0;
+ uint32 lower_hash = 0;
+ uint32 upper_hash = 0;
+ uint32 result = 0;
+
+ TypeCacheEntry *typentry;
+ Oid subtype;
+ FunctionCallInfoData locfcinfo;
+
+
+ range_deserialize(r, &lower, &upper, &empty);
+
+ if (lower.rngtypid != upper.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty)
+ flags |= RANGE_EMPTY;
+
+ flags |= (lower.inclusive) ? RANGE_LB_INC : 0;
+ flags |= (lower.infinite) ? RANGE_LB_INF : 0;
+ flags |= (upper.inclusive) ? RANGE_UB_INC : 0;
+ flags |= (upper.infinite) ? RANGE_UB_INF : 0;
+
+ subtype = get_range_subtype(lower.rngtypid);
+
+ /*
+ * We arrange to look up the hash function only once per series of
+ * calls, assuming the subtype doesn't change underneath us. The
+ * typcache is used so that we have no memory leakage when being
+ * used as an index support function.
+ */
+ typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
+ if (typentry == NULL || typentry->type_id != subtype)
+ {
+ typentry = lookup_type_cache(subtype, TYPECACHE_HASH_PROC_FINFO);
+ if (!OidIsValid(typentry->hash_proc_finfo.fn_oid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("could not identify a hash function for type %s",
+ format_type_be(subtype))));
+ fcinfo->flinfo->fn_extra = (void *) typentry;
+ }
+
+ /*
+ * apply the hash function to each array element.
+ */
+ InitFunctionCallInfoData(locfcinfo, &typentry->hash_proc_finfo, 1,
+ NULL, NULL);
+
+ if (RANGE_HAS_LBOUND(flags))
+ {
+ locfcinfo.arg[0] = lower.val;
+ locfcinfo.argnull[0] = false;
+ locfcinfo.isnull = false;
+ lower_hash = DatumGetUInt32(FunctionCallInvoke(&locfcinfo));
+ }
+ if (RANGE_HAS_UBOUND(flags))
+ {
+ locfcinfo.arg[0] = upper.val;
+ locfcinfo.argnull[0] = false;
+ locfcinfo.isnull = false;
+ upper_hash = DatumGetUInt32(FunctionCallInvoke(&locfcinfo));
+ }
+
+ result = hash_uint32((uint32) flags);
+ result = (result << 1) | (result >> 31);
+ result ^= lower_hash;
+ result = (result << 1) | (result >> 31);
+ result ^= upper_hash;
+
+ PG_RETURN_INT32(result);
+ }
+
+ /*
+ *----------------------------------------------------------
+ * CANONICAL FUNCTIONS
+ *----------------------------------------------------------
+ */
+
+ Datum
+ int4range_canonical(PG_FUNCTION_ARGS)
+ {
+ RangeType *r = PG_GETARG_RANGE(0);
+
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+
+ range_deserialize(r, &lower, &upper, &empty);
+
+ if (empty)
+ PG_RETURN_RANGE(r);
+
+ if (!lower.infinite && !lower.inclusive)
+ {
+ lower.val = DirectFunctionCall2(int4pl, lower.val, Int32GetDatum(1));
+ lower.inclusive = true;
+ }
+
+ if (!upper.infinite && upper.inclusive)
+ {
+ upper.val = DirectFunctionCall2(int4pl, upper.val, Int32GetDatum(1));
+ upper.inclusive = false;
+ }
+
+ PG_RETURN_RANGE(range_serialize(&lower, &upper, false));
+ }
+
+ Datum
+ int8range_canonical(PG_FUNCTION_ARGS)
+ {
+ RangeType *r = PG_GETARG_RANGE(0);
+
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+
+ range_deserialize(r, &lower, &upper, &empty);
+
+ if (empty)
+ PG_RETURN_RANGE(r);
+
+ if (!lower.infinite && !lower.inclusive)
+ {
+ lower.val = DirectFunctionCall2(int8pl, lower.val, Int64GetDatum(1));
+ lower.inclusive = true;
+ }
+
+ if (!upper.infinite && upper.inclusive)
+ {
+ upper.val = DirectFunctionCall2(int8pl, upper.val, Int64GetDatum(1));
+ upper.inclusive = false;
+ }
+
+ PG_RETURN_RANGE(range_serialize(&lower, &upper, false));
+ }
+
+ Datum
+ daterange_canonical(PG_FUNCTION_ARGS)
+ {
+ RangeType *r = PG_GETARG_RANGE(0);
+
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+
+ range_deserialize(r, &lower, &upper, &empty);
+
+ if (empty)
+ PG_RETURN_RANGE(r);
+
+ if (!lower.infinite && !lower.inclusive)
+ {
+ lower.val = DirectFunctionCall2(date_pli, lower.val, Int32GetDatum(1));
+ lower.inclusive = true;
+ }
+
+ if (!upper.infinite && upper.inclusive)
+ {
+ upper.val = DirectFunctionCall2(date_pli, upper.val, Int32GetDatum(1));
+ upper.inclusive = false;
+ }
+
+ PG_RETURN_RANGE(range_serialize(&lower, &upper, false));
+ }
+
+ /*
+ *----------------------------------------------------------
+ * SUPPORT FUNCTIONS
+ *----------------------------------------------------------
+ */
+
+ /*
+ * This serializes a range, but does not canonicalize it. This should
+ * only be called by a canonicalization function.
+ */
+ Datum
+ range_serialize(RangeBound *lower, RangeBound *upper, bool empty)
+ {
+ Datum range;
+ size_t msize;
+ char *ptr;
+ Oid subtype = get_range_subtype(lower->rngtypid);
+ int16 typlen = get_typlen(subtype);
+ char typalign = get_typalign(subtype);
+ char typbyval = get_typbyval(subtype);
+ size_t llen = 0;
+ size_t ulen = 0;
+ char flags = 0;
+
+ if (lower->rngtypid != upper->rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty)
+ flags |= RANGE_EMPTY;
+ else if (range_cmp_bounds(lower, upper) > 0)
+ elog(ERROR, "range lower bound must be less than or equal to range upper bound");
+
+ flags |= (lower->inclusive) ? RANGE_LB_INC : 0;
+ flags |= (lower->infinite) ? RANGE_LB_INF : 0;
+ flags |= (upper->inclusive) ? RANGE_UB_INC : 0;
+ flags |= (upper->infinite) ? RANGE_UB_INF : 0;
+
+ msize = VARHDRSZ;
+ msize += sizeof(Oid);
+ msize += sizeof(char);
+
+ if (RANGE_HAS_LBOUND(flags))
+ {
+ llen = att_addlength_datum(0, typlen, lower->val);
+ msize = att_align_nominal(msize, typalign);
+ msize += llen;
+ }
+
+ if (RANGE_HAS_UBOUND(flags))
+ {
+ ulen = att_addlength_datum(0, typlen, upper->val);
+ msize = att_align_nominal(msize, typalign);
+ msize += ulen;
+ }
+
+ ptr = palloc(msize);
+ range = (Datum) ptr;
+
+ ptr += VARHDRSZ;
+
+ memcpy(ptr, &lower->rngtypid, sizeof(Oid));
+ ptr += sizeof(Oid);
+ memcpy(ptr, &flags, sizeof(char));
+ ptr += sizeof(char);
+
+ if (RANGE_HAS_LBOUND(flags))
+ {
+ Assert(lower->lower);
+ ptr = (char *) att_align_nominal(ptr, typalign);
+ if (typbyval)
+ store_att_byval(ptr, lower->val, typlen);
+ else
+ memcpy(ptr, (void *) lower->val, llen);
+ ptr += llen;
+ }
+
+ if (RANGE_HAS_UBOUND(flags))
+ {
+ Assert(!upper->lower);
+ ptr = (char *) att_align_nominal(ptr, typalign);
+ if (typbyval)
+ store_att_byval(ptr, upper->val, typlen);
+ else
+ memcpy(ptr, (void *) upper->val, ulen);
+ ptr += ulen;
+ }
+
+ SET_VARSIZE(range, msize);
+ PG_RETURN_RANGE(range);
+ }
+
+ void
+ range_deserialize(RangeType *range, RangeBound *lower, RangeBound *upper,
+ bool *empty)
+ {
+ char *ptr = VARDATA(range);
+ int llen;
+ int ulen;
+ char typalign;
+ int16 typlen;
+ int16 typbyval;
+ char flags;
+ Oid rngtypid;
+ Oid subtype;
+ Datum lbound;
+ Datum ubound;
+
+ memset(lower, 0, sizeof(RangeBound));
+ memset(upper, 0, sizeof(RangeBound));
+
+ memcpy(&rngtypid, ptr, sizeof(Oid));
+ ptr += sizeof(Oid);
+ memcpy(&flags, ptr, sizeof(char));
+ ptr += sizeof(char);
+
+ if (rngtypid == ANYRANGEOID)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot output a value of type anyrange")));
+
+ subtype = get_range_subtype(rngtypid);
+ typalign = get_typalign(subtype);
+ typlen = get_typlen(subtype);
+ typbyval = get_typbyval(subtype);
+
+ if (RANGE_HAS_LBOUND(flags))
+ {
+ ptr = (char *) att_align_nominal(ptr, typalign);
+ llen = att_addlength_datum(0, typlen, (Datum) ptr);
+ lbound = fetch_att(ptr, typbyval, typlen);
+ ptr += llen;
+ }
+ else
+ lbound = (Datum) 0;
+
+ if (RANGE_HAS_UBOUND(flags))
+ {
+ ptr = (char *) att_align_nominal(ptr, typalign);
+ ulen = att_addlength_datum(0, typlen, (Datum) ptr);
+ ubound = fetch_att(ptr, typbyval, typlen);
+ ptr += ulen;
+ }
+ else
+ ubound = (Datum) 0;
+
+ *empty = flags & RANGE_EMPTY;
+
+ lower->rngtypid = rngtypid;
+ lower->val = lbound;
+ lower->inclusive = flags & RANGE_LB_INC;
+ lower->infinite = flags & RANGE_LB_INF;
+ lower->lower = true;
+
+ upper->rngtypid = rngtypid;
+ upper->val = ubound;;
+ upper->inclusive = flags & RANGE_UB_INC;
+ upper->infinite = flags & RANGE_UB_INF;
+ upper->lower = false;
+ }
+
+ /*
+ * This both serializes and caonicalizes (if applicable) the
+ * range. This should be used by most callers.
+ */
+ Datum
+ make_range(RangeBound *lower, RangeBound *upper, bool empty)
+ {
+ Datum range;
+ Oid canonical = get_range_canonical(lower->rngtypid);
+
+ if (lower->rngtypid != upper->rngtypid)
+ elog(ERROR, "range types do not match");
+
+ range = range_serialize(lower, upper, empty);
+
+ if (OidIsValid(canonical))
+ range = OidFunctionCall1(canonical, range);
+
+ PG_RETURN_RANGE(range);
+ }
+
+ int
+ range_cmp_bounds(RangeBound *b1, RangeBound *b2)
+ {
+ regproc cmpFn;
+ int result;
+
+ if (b1->infinite && b2->infinite)
+ {
+ if (b1->lower == b2->lower)
+ return 0;
+ else
+ return (b1->lower) ? -1 : 1;
+ }
+ else if (b1->infinite && !b2->infinite)
+ return (b1->lower) ? -1 : 1;
+ else if (!b1->infinite && b2->infinite)
+ return (b2->lower) ? 1 : -1;
+
+ cmpFn = get_range_subtype_cmp(b1->rngtypid);
+ result = DatumGetInt32(OidFunctionCall2(cmpFn, b1->val, b2->val));
+
+ if (result == 0)
+ {
+ if (b1->inclusive && !b2->inclusive)
+ return (b2->lower) ? -1 : 1;
+ else if (!b1->inclusive && b2->inclusive)
+ return (b1->lower) ? 1 : -1;
+ }
+
+ return result;
+ }
+
+ RangeType *
+ make_empty_range(Oid rngtypid)
+ {
+ RangeBound lower;
+ RangeBound upper;
+
+ memset(&lower, 0, sizeof(RangeBound));
+ memset(&upper, 0, sizeof(RangeBound));
+
+ lower.rngtypid = rngtypid;
+ lower.lower = true;
+ upper.rngtypid = rngtypid;
+ upper.lower = false;
+
+ return DatumGetRangeType(make_range(&lower, &upper, true));
+ }
+
+ /*
+ *----------------------------------------------------------
+ * STATIC FUNCTIONS
+ *----------------------------------------------------------
+ */
+
+ /*
+ * Parse input of the form:
+ *
+ * where
+ * is either "[" or "("
+ * and are either plain strings or quoted strings
+ * is ","
+ * is either "]" or ")"
+ *
+ * Quoted strings preserve whitespace, and allow using special
+ * characters like "," and special values like "INF" ("\" is the
+ * escape character if you need to include a double quote or backslash
+ * character). Unquoted strings preserve internal whitespace, but not
+ * leading or trailing whitespace.
+ */
+ static void
+ range_parse(const char *input_str, char *flags, char **lbound_str,
+ char **ubound_str)
+ {
+ int ilen = strlen(input_str);
+ char *lb = palloc0(ilen + 1);
+ char *ub = palloc0(ilen + 1);
+ int lidx = 0;
+ int lb_last = 1;
+ int uidx = 0;
+ int ub_last = 1;
+ bool inside_quotes = false;
+ bool lb_quoted = false;
+ bool ub_quoted = false;
+ bool escape = false;
+ char fl = 0;
+ RangePState pstate = RANGE_PSTATE_INIT;
+ int i;
+
+
+ for (i = 0; i < ilen; i++)
+ {
+ char ch = input_str[i];
+ switch(pstate)
+ {
+ case RANGE_PSTATE_INIT:
+ if (isspace(ch))
+ continue;
+ if(ch == '-')
+ {
+ fl = RANGE_EMPTY;
+ pstate = RANGE_PSTATE_DONE;
+ /* read the rest to make sure it's whitespace */
+ continue;
+ }
+
+ if (ch == '[' || ch == '(')
+ {
+ if (ch == '[')
+ fl |= RANGE_LB_INC;
+ pstate = RANGE_PSTATE_PRE_LB;
+ continue;
+ }
+ break;
+ case RANGE_PSTATE_PRE_LB:
+ /* remove leading whitespace */
+ if (isspace(ch))
+ continue;
+ pstate = RANGE_PSTATE_LB;
+ /* fall through */
+ case RANGE_PSTATE_LB:
+ if (ch == '"' && !escape)
+ {
+ if (inside_quotes)
+ {
+ inside_quotes = false;
+ pstate = RANGE_PSTATE_SEP;
+ }
+ else
+ {
+ inside_quotes = true;
+ lb_quoted = true;
+ }
+ continue;
+ }
+ if (ch == '\\' && !escape && inside_quotes)
+ {
+ escape = true;
+ continue;
+ }
+ escape = false;
+
+ if (ch != ',')
+ {
+ lb[lidx++] = ch;
+ /* track last significant character */
+ if (inside_quotes || !isspace(ch))
+ lb_last = lidx;
+ continue;
+ }
+
+ pstate = RANGE_PSTATE_SEP;
+ /* fall through */
+ case RANGE_PSTATE_SEP:
+ if (isspace(ch))
+ continue;
+ if (ch == ',')
+ {
+ pstate = RANGE_PSTATE_PRE_UB;
+ continue;
+ }
+ case RANGE_PSTATE_PRE_UB:
+ /* remove leading whitespace */
+ if (isspace(ch))
+ continue;
+ pstate = RANGE_PSTATE_UB;
+ /* fall through */
+ case RANGE_PSTATE_UB:
+ if (ch == '"' && !escape)
+ {
+ if (inside_quotes)
+ {
+ inside_quotes = false;
+ pstate = RANGE_PSTATE_UB_INC;
+ }
+ else
+ {
+ inside_quotes = true;
+ lb_quoted = true;
+ }
+ continue;
+ }
+ if (ch == '\\' && !escape && inside_quotes)
+ {
+ escape = true;
+ continue;
+ }
+ escape = false;
+
+ if (ch != ']' && ch != ')')
+ {
+ ub[uidx++] = ch;
+ /* track last significant character */
+ if (inside_quotes || !isspace(ch))
+ ub_last = uidx;
+ continue;
+ }
+
+ pstate = RANGE_PSTATE_UB_INC;
+ /* fall through */
+ case RANGE_PSTATE_UB_INC:
+ if (isspace(ch))
+ continue;
+ if (ch == ']' || ch == ')')
+ {
+ if (ch == ']')
+ fl |= RANGE_UB_INC;
+ pstate = RANGE_PSTATE_DONE;
+ continue;
+ }
+ break;
+ case RANGE_PSTATE_DONE:
+ if (isspace(ch))
+ continue;
+ break;
+ }
+ elog(ERROR, "syntax error on range input \"%s\", character %d",
+ input_str, i);
+ }
+
+ /* remove trailing whitespace */
+ lb[lb_last] = '\0';
+ ub[ub_last] = '\0';
+
+ if (pstate != RANGE_PSTATE_DONE)
+ elog(ERROR, "syntax error on range input: unexpected end of input");
+
+ if (fl & RANGE_EMPTY)
+ fl = RANGE_EMPTY;
+
+ if (!lb_quoted && strncmp(lb, "NULL", ilen) == 0)
+ elog(ERROR, "NULL range boundaries are not supported");
+ if (!ub_quoted && strncmp(ub, "NULL", ilen) == 0)
+ elog(ERROR, "NULL range boundaries are not supported");
+ if (!lb_quoted && strncmp(lb, "-INF", ilen) == 0)
+ fl |= RANGE_LB_INF;
+ if (!ub_quoted && strncmp(ub, "INF", ilen) == 0)
+ fl |= RANGE_UB_INF;
+
+ if (!RANGE_HAS_LBOUND(fl))
+ {
+ lb = NULL;
+ fl &= ~RANGE_LB_INC;
+ }
+
+ if (!RANGE_HAS_UBOUND(fl))
+ {
+ ub = NULL;
+ fl &= ~RANGE_UB_INC;
+ }
+
+ *lbound_str = lb;
+ *ubound_str = ub;
+ *flags = fl;
+
+ return;
+ }
+
+ static char *
+ range_deparse(char flags, char *lbound_str, char *ubound_str)
+ {
+ StringInfo str = makeStringInfo();
+ char lb_c;
+ char ub_c;
+ char *lb_str;
+ char *ub_str;
+
+ if (flags & RANGE_EMPTY)
+ return pstrdup("-");
+
+ lb_c = (flags & RANGE_LB_INC) ? '[' : '(';
+ ub_c = (flags & RANGE_UB_INC) ? ']' : ')';
+
+ lb_str = lbound_str;
+ ub_str = ubound_str;
+
+ if (!RANGE_HAS_LBOUND(flags))
+ lb_str = (flags & RANGE_LB_NULL) ? "NULL" : "-INF";
+ if (!RANGE_HAS_UBOUND(flags))
+ ub_str = (flags & RANGE_UB_NULL) ? "NULL" : "INF";
+
+ appendStringInfo(str, "%c %s, %s %c", lb_c, lb_str, ub_str, ub_c);
+
+ return str->data;
+ }
+
+ static Datum
+ range_make2(PG_FUNCTION_ARGS)
+ {
+ Datum arg1 = PG_GETARG_DATUM(0);
+ Datum arg2 = PG_GETARG_DATUM(1);
+ Oid subtype = get_fn_expr_argtype(fcinfo->flinfo,0);
+ Oid rngtypid = get_range_from_subtype(subtype);
+ RangeType *range;
+ RangeBound lower;
+ RangeBound upper;
+
+ memset(&lower, 0, sizeof(RangeBound));
+ memset(&upper, 0, sizeof(RangeBound));
+
+ switch(fcinfo->flinfo->fn_oid)
+ {
+ case F_RANGE__:
+ break;
+ case F_RANGE_I:
+ upper.inclusive = true;
+ break;
+ case F_RANGE:
+ case F_RANGEI_:
+ lower.inclusive = true;
+ break;
+ case F_RANGEII:
+ lower.inclusive = true;
+ upper.inclusive = true;
+ break;
+ }
+
+ if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+ elog(ERROR, "NULL range boundaries are not supported");
+
+ lower.rngtypid = rngtypid;
+ lower.lower = true;
+ lower.val = arg1;
+
+ upper.rngtypid = rngtypid;
+ upper.lower = false;
+ upper.val = arg2;
+
+ range = DatumGetRangeType(make_range(&lower, &upper, false));
+
+ PG_RETURN_RANGE(range);
+ }
+
+ static bool
+ range_contains_internal(RangeType *r1, RangeType *r2)
+ {
+ RangeBound lower1;
+ RangeBound upper1;
+ bool empty1;
+ RangeBound lower2;
+ RangeBound upper2;
+ bool empty2;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (lower1.rngtypid != upper1.rngtypid ||
+ lower1.rngtypid != lower2.rngtypid ||
+ lower1.rngtypid != upper2.rngtypid)
+ elog(ERROR, "range types do not match");
+
+ if (empty2)
+ return true;
+ else if (empty1)
+ return false;
+
+ if (range_cmp_bounds(&lower1, &lower2) > 0)
+ return false;
+ if (range_cmp_bounds(&upper1, &upper2) < 0)
+ return false;
+
+ return true;
+ }
*** /dev/null
--- b/src/backend/utils/adt/rangetypes_gist.c
***************
*** 0 ****
--- 1,537 ----
+ /*-------------------------------------------------------------------------
+ *
+ * rangetypes_gist.c
+ * GiST support for range types.
+ *
+ * Copyright (c) 2006-2011, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/utils/adt/rangetypes_gist.c
+ *
+ *-------------------------------------------------------------------------
+ */
+ #include "postgres.h"
+
+ #include "access/gist.h"
+ #include "access/skey.h"
+ #include "utils/lsyscache.h"
+ #include "utils/rangetypes.h"
+
+ #define RANGESTRAT_EQ 1
+ #define RANGESTRAT_NE 2
+ #define RANGESTRAT_OVERLAPS 3
+ #define RANGESTRAT_CONTAINS_ELEM 4
+ #define RANGESTRAT_ELEM_CONTAINED_BY 5
+ #define RANGESTRAT_CONTAINS 6
+ #define RANGESTRAT_CONTAINED_BY 7
+ #define RANGESTRAT_BEFORE 8
+ #define RANGESTRAT_AFTER 9
+ #define RANGESTRAT_OVERLEFT 10
+ #define RANGESTRAT_OVERRIGHT 11
+ #define RANGESTRAT_ADJACENT 12
+
+ static RangeType *range_super_union(RangeType *r1, RangeType *r2);
+ static bool range_gist_consistent_int(StrategyNumber strategy, RangeType *key,
+ RangeType *query);
+ static bool range_gist_consistent_leaf(StrategyNumber strategy, RangeType *key,
+ RangeType *query);
+ static int sort_item_cmp(const void *a, const void *b);
+
+ /*
+ * Auxiliary structure for picksplit method.
+ */
+ typedef struct
+ {
+ int index;
+ RangeType *data;
+ } PickSplitSortItem;
+
+
+ /* GiST support */
+ Datum
+ range_gist_consistent(PG_FUNCTION_ARGS)
+ {
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ Datum dquery = PG_GETARG_DATUM(1);
+ StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+ /* Oid subtype = PG_GETARG_OID(3); */
+ bool *recheck = (bool *) PG_GETARG_POINTER(4);
+ RangeType *key = DatumGetRangeType(entry->key);
+ RangeType *query;
+
+ RangeBound lower;
+ RangeBound upper;
+ bool empty;
+ Oid rngtypid;
+
+ *recheck = false;
+ range_deserialize(key, &lower, &upper, &empty);
+ rngtypid = lower.rngtypid;
+
+ switch(strategy)
+ {
+ RangeBound lower;
+ RangeBound upper;
+
+ case RANGESTRAT_CONTAINS_ELEM:
+ case RANGESTRAT_ELEM_CONTAINED_BY:
+ lower.rngtypid = rngtypid;
+ lower.inclusive = true;
+ lower.val = dquery;
+ lower.lower = true;
+ lower.infinite = false;
+ upper.rngtypid = rngtypid;
+ upper.inclusive = true;
+ upper.val = dquery;
+ upper.lower = false;
+ upper.infinite = false;
+ query = DatumGetRangeType(
+ make_range(&lower, &upper, false));
+ break;
+ default:
+ query = DatumGetRangeType(dquery);
+ break;
+ }
+
+ if(GIST_LEAF(entry))
+ PG_RETURN_BOOL(range_gist_consistent_leaf(strategy, key, query));
+ else
+ PG_RETURN_BOOL(range_gist_consistent_int(strategy, key, query));
+ }
+
+ Datum
+ range_gist_union(PG_FUNCTION_ARGS)
+ {
+ GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+ GISTENTRY *ent = entryvec->vector;
+ RangeType *result_range;
+ int i;
+
+ result_range = DatumGetRangeType(ent[0].key);
+
+ for (i = 1; i < entryvec->n; i++)
+ {
+ result_range = range_super_union(result_range,
+ DatumGetRangeType(ent[i].key));
+ }
+
+ PG_RETURN_RANGE(result_range);
+ }
+
+ Datum
+ range_gist_compress(PG_FUNCTION_ARGS)
+ {
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ PG_RETURN_POINTER(entry);
+ }
+
+ Datum
+ range_gist_decompress(PG_FUNCTION_ARGS)
+ {
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ PG_RETURN_POINTER(entry);
+ }
+
+ Datum
+ range_gist_penalty(PG_FUNCTION_ARGS)
+ {
+ GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
+ float *penalty = (float *) PG_GETARG_POINTER(2);
+ RangeType *orig = DatumGetRangeType(origentry->key);
+ RangeType *new = DatumGetRangeType(newentry->key);
+ RangeType *s_union = range_super_union(orig, new);
+
+ regproc subtype_float;
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+ float length1, length2;
+
+ range_deserialize(orig, &lower1, &upper1, &empty1);
+ range_deserialize(s_union, &lower2, &upper2, &empty2);
+
+ subtype_float = get_range_subtype_float(lower1.rngtypid);
+
+ if (empty1)
+ length1 = 0.0;
+ else if (lower1.infinite || upper1.infinite)
+ length1 = 1.0/0.0;
+ else if (OidIsValid(subtype_float))
+ {
+ double l = DatumGetFloat8(OidFunctionCall1(subtype_float, lower1.val));
+ double u = DatumGetFloat8(OidFunctionCall1(subtype_float, upper1.val));
+ length1 = u - l;
+ }
+ else
+ length1 = 1.0;
+
+ if (empty2)
+ length2 = 0.0;
+ else if (lower2.infinite || upper2.infinite)
+ length2 = 1.0/0.0;
+ else if (OidIsValid(subtype_float))
+ {
+ double l = DatumGetFloat8(OidFunctionCall1(subtype_float, lower2.val));
+ double u = DatumGetFloat8(OidFunctionCall1(subtype_float, upper2.val));
+ length2 = u - l;
+ }
+ else
+ length2 = 1.0;
+
+ *penalty = (float) (length2 - length1);
+ PG_RETURN_POINTER(penalty);
+ }
+
+ /*
+ * The GiST PickSplit method for ranges
+ * Algorithm based on sorting. Incoming array of periods is sorting using
+ * period_compare function. After that first half of periods goes to the left
+ * datum, and the second half of periods goes to the right datum.
+ */
+ Datum
+ range_gist_picksplit(PG_FUNCTION_ARGS)
+ {
+ GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+ GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+ OffsetNumber i;
+ RangeType *pred_left;
+ RangeType *pred_right;
+ PickSplitSortItem *sortItems;
+ int nbytes;
+ OffsetNumber split_idx;
+ OffsetNumber *left;
+ OffsetNumber *right;
+ OffsetNumber maxoff;
+
+ maxoff = entryvec->n - 1;
+ nbytes = (maxoff + 1) * sizeof(OffsetNumber);
+ sortItems = (PickSplitSortItem *)palloc(maxoff * sizeof(PickSplitSortItem));
+ v->spl_left = (OffsetNumber *) palloc(nbytes);
+ v->spl_right = (OffsetNumber *) palloc(nbytes);
+
+ /*
+ * Preparing auxiliary array and sorting.
+ */
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ sortItems[i - 1].index = i;
+ sortItems[i - 1].data = DatumGetRangeType(entryvec->vector[i].key);
+ }
+ qsort(sortItems, maxoff, sizeof(PickSplitSortItem), sort_item_cmp);
+ split_idx = maxoff / 2;
+
+ left = v->spl_left;
+ v->spl_nleft = 0;
+ right = v->spl_right;
+ v->spl_nright = 0;
+
+ /*
+ * First half of segs goes to the left datum.
+ */
+ pred_left = DatumGetRangeType(sortItems[0].data);
+ *left++ = sortItems[0].index;
+ v->spl_nleft++;
+ for (i = 1; i < split_idx; i++)
+ {
+ pred_left = range_super_union(pred_left,
+ DatumGetRangeType(sortItems[i].data));
+ *left++ = sortItems[i].index;
+ v->spl_nleft++;
+ }
+
+ /*
+ * Second half of segs goes to the right datum.
+ */
+ pred_right = DatumGetRangeType(sortItems[split_idx].data);
+ *right++ = sortItems[split_idx].index;
+ v->spl_nright++;
+ for (i = split_idx + 1; i < maxoff; i++)
+ {
+ pred_right = range_super_union(pred_right,
+ DatumGetRangeType(sortItems[i].data));
+ *right++ = sortItems[i].index;
+ v->spl_nright++;
+ }
+
+ *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
+
+ v->spl_ldatum = RangeTypeGetDatum(pred_left);
+ v->spl_rdatum = RangeTypeGetDatum(pred_right);
+
+ PG_RETURN_POINTER(v);
+ }
+
+ Datum
+ range_gist_same(PG_FUNCTION_ARGS)
+ {
+ Datum r1 = PG_GETARG_DATUM(0);
+ Datum r2 = PG_GETARG_DATUM(1);
+ bool *result = (bool *) PG_GETARG_POINTER(2);
+
+ *result = DatumGetBool(DirectFunctionCall2(range_eq, r1, r2));
+ PG_RETURN_POINTER(result);
+ }
+
+ /*
+ *----------------------------------------------------------
+ * STATIC FUNCTIONS
+ *----------------------------------------------------------
+ */
+
+ /* return the smallest range that contains r1 and r2 */
+ static RangeType *
+ range_super_union(RangeType *r1, RangeType *r2)
+ {
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+ RangeBound *result_lower;
+ RangeBound *result_upper;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (empty1)
+ return r2;
+ if (empty2)
+ return r1;
+
+ if (range_cmp_bounds(&lower1, &lower2) <= 0)
+ result_lower = &lower1;
+ else
+ result_lower = &lower2;
+
+ if (range_cmp_bounds(&upper1, &upper2) >= 0)
+ result_upper = &upper1;
+ else
+ result_upper = &upper2;
+
+ /* optimization to avoid constructing a new range */
+ if (result_lower == &lower1 && result_upper == &upper1)
+ return r1;
+ if (result_lower == &lower2 && result_upper == &upper2)
+ return r2;
+
+ return DatumGetRangeType(make_range(result_lower, result_upper, false));
+ }
+
+ static bool
+ range_gist_consistent_int(StrategyNumber strategy, RangeType *key,
+ RangeType *query)
+ {
+ Datum (*proc)(PG_FUNCTION_ARGS);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ bool retval;
+ bool negate = false;
+
+ range_deserialize(key, &lower1, &upper1, &empty1);
+ range_deserialize(query, &lower2, &upper2, &empty2);
+
+ switch (strategy)
+ {
+ case RANGESTRAT_EQ:
+ proc = range_contains;
+ break;
+ case RANGESTRAT_NE:
+ return true;
+ break;
+ case RANGESTRAT_OVERLAPS:
+ proc = range_overlaps;
+ break;
+ case RANGESTRAT_CONTAINS_ELEM:
+ case RANGESTRAT_CONTAINS:
+ proc = range_contains;
+ break;
+ case RANGESTRAT_ELEM_CONTAINED_BY:
+ case RANGESTRAT_CONTAINED_BY:
+ return true;
+ break;
+ case RANGESTRAT_BEFORE:
+ if (empty1)
+ return false;
+ proc = range_overright;
+ negate = true;
+ break;
+ case RANGESTRAT_AFTER:
+ if (empty1)
+ return false;
+ proc = range_overleft;
+ negate = true;
+ break;
+ case RANGESTRAT_OVERLEFT:
+ if (empty1)
+ return false;
+ proc = range_after;
+ negate = true;
+ break;
+ case RANGESTRAT_OVERRIGHT:
+ if (empty1)
+ return false;
+ proc = range_before;
+ negate = true;
+ break;
+ case RANGESTRAT_ADJACENT:
+ if (empty1 || empty2)
+ return false;
+ if (DatumGetBool(
+ DirectFunctionCall2(range_adjacent,
+ RangeTypeGetDatum(key),
+ RangeTypeGetDatum(query))))
+ return true;
+ proc = range_overlaps;
+ break;
+ }
+
+ retval = DatumGetBool(DirectFunctionCall2(proc, RangeTypeGetDatum(key),
+ RangeTypeGetDatum(query)));
+
+ if (negate)
+ retval = !retval;
+
+ PG_RETURN_BOOL(retval);
+ }
+
+ static bool
+ range_gist_consistent_leaf(StrategyNumber strategy, RangeType *key,
+ RangeType *query)
+ {
+ Datum (*proc)(PG_FUNCTION_ARGS);
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ range_deserialize(key, &lower1, &upper1, &empty1);
+ range_deserialize(query, &lower2, &upper2, &empty2);
+
+ switch (strategy)
+ {
+ case RANGESTRAT_EQ:
+ proc = range_eq;
+ break;
+ case RANGESTRAT_NE:
+ proc = range_ne;
+ break;
+ case RANGESTRAT_OVERLAPS:
+ proc = range_overlaps;
+ break;
+ case RANGESTRAT_CONTAINS_ELEM:
+ case RANGESTRAT_CONTAINS:
+ proc = range_contains;
+ break;
+ case RANGESTRAT_ELEM_CONTAINED_BY:
+ case RANGESTRAT_CONTAINED_BY:
+ proc = range_contained_by;
+ break;
+ case RANGESTRAT_BEFORE:
+ if (empty1 || empty2)
+ return false;
+ proc = range_before;
+ break;
+ case RANGESTRAT_AFTER:
+ if (empty1 || empty2)
+ return false;
+ proc = range_after;
+ break;
+ case RANGESTRAT_OVERLEFT:
+ if (empty1 || empty2)
+ return false;
+ proc = range_overleft;
+ break;
+ case RANGESTRAT_OVERRIGHT:
+ if (empty1 || empty2)
+ return false;
+ proc = range_overright;
+ break;
+ case RANGESTRAT_ADJACENT:
+ if (empty1 || empty2)
+ return false;
+ proc = range_adjacent;
+ break;
+ }
+
+ return DatumGetBool(DirectFunctionCall2(proc, RangeTypeGetDatum(key),
+ RangeTypeGetDatum(query)));
+ }
+
+ /*
+ * Compare function for PickSplitSortItem. This is actually the
+ * interesting part of the picksplit algorithm.
+ *
+ * We want to separate out empty ranges, bounded ranges, and unbounded
+ * ranges. We assume that "contains" and "overlaps" are the most
+ * important queries, so empty ranges will rarely match and unbounded
+ * ranges frequently will. Bounded ranges should be in the middle.
+ *
+ * Empty ranges we push all the way to the left, then bounded ranges
+ * (sorted on lower bound, then upper), then ranges with no lower
+ * bound, then ranges with no upper bound; and finally, ranges with no
+ * upper or lower bound all the way to the right.
+ */
+ static int
+ sort_item_cmp(const void *a, const void *b)
+ {
+ PickSplitSortItem *i1 = (PickSplitSortItem *)a;
+ PickSplitSortItem *i2 = (PickSplitSortItem *)b;
+ RangeType *r1 = i1->data;
+ RangeType *r2 = i2->data;
+
+ RangeBound lower1, lower2;
+ RangeBound upper1, upper2;
+ bool empty1, empty2;
+
+ int cmp;
+
+ range_deserialize(r1, &lower1, &upper1, &empty1);
+ range_deserialize(r2, &lower2, &upper2, &empty2);
+
+ if (empty1 || empty2)
+ {
+ if (empty1 && empty2)
+ return 0;
+ else if (empty1)
+ return -1;
+ else if (empty2)
+ return 1;
+ else
+ Assert(false);
+ }
+
+ /*
+ * If both lower or both upper bounds are infinite, we sort by
+ * ascending range size. That means that if both upper bounds are
+ * infinite, we sort by the lower bound _descending_. That creates
+ * a slightly odd total order, but keeps the pages with very
+ * unselective predicates grouped more closely together on the
+ * right.
+ */
+ if (lower1.infinite || upper1.infinite ||
+ lower2.infinite || upper2.infinite)
+ {
+ if (lower1.infinite && lower2.infinite)
+ return range_cmp_bounds(&upper1, &upper2);
+ else if (lower1.infinite)
+ return -1;
+ else if (lower2.infinite)
+ return 1;
+ else if (upper1.infinite && upper2.infinite)
+ return -1 * range_cmp_bounds(&lower1, &lower2);
+ else if (upper1.infinite)
+ return 1;
+ else if (upper2.infinite)
+ return -1;
+ else
+ Assert(false);
+ }
+
+ if ((cmp = range_cmp_bounds(&lower1, &lower2)) != 0)
+ return cmp;
+
+ return range_cmp_bounds(&upper1, &upper2);
+ }
*** a/src/backend/utils/adt/timestamp.c
--- b/src/backend/utils/adt/timestamp.c
***************
*** 4630,4635 **** timestamptz_zone(PG_FUNCTION_ARGS)
--- 4630,4650 ----
PG_RETURN_TIMESTAMP(result);
}
+ Datum
+ timestamp_float8(PG_FUNCTION_ARGS)
+ {
+ Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
+ float8 result;
+
+ #ifdef HAVE_INT64_TIMESTAMP
+ result = ((float8) timestamp) / USECS_PER_SEC;
+ #else
+ result = timestamp;
+ #endif
+
+ PG_RETURN_FLOAT8(result);
+ }
+
/* timestamptz_izone()
* Encode timestamp with time zone type with specified time interval as time zone.
* Returns a timestamp without time zone.
*** a/src/backend/utils/cache/lsyscache.c
--- b/src/backend/utils/cache/lsyscache.c
***************
*** 25,30 ****
--- 25,31 ----
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
+ #include "catalog/pg_range.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
***************
*** 1927,1933 **** get_type_io_data(Oid typid,
ReleaseSysCache(typeTuple);
}
- #ifdef NOT_USED
char
get_typalign(Oid typid)
{
--- 1928,1933 ----
***************
*** 1946,1952 **** get_typalign(Oid typid)
else
return 'i';
}
- #endif
char
get_typstorage(Oid typid)
--- 1946,1951 ----
***************
*** 2199,2204 **** type_is_enum(Oid typid)
--- 2198,2213 ----
}
/*
+ * type_is_range
+ * Returns true if the given type is an range type.
+ */
+ bool
+ type_is_range(Oid typid)
+ {
+ return (get_typtype(typid) == TYPTYPE_RANGE);
+ }
+
+ /*
* get_type_category_preferred
*
* Given the type OID, fetch its category and preferred-type status.
***************
*** 2767,2769 **** get_namespace_name(Oid nspid)
--- 2776,2873 ----
else
return NULL;
}
+
+ Oid
+ get_range_subtype(Oid rangeOid)
+ {
+ HeapTuple tp;
+
+ tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
+ Oid result;
+
+ result = rngtup->rngsubtype;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+ }
+
+ Oid
+ get_range_from_subtype(Oid subtypeOid)
+ {
+ HeapTuple tp;
+
+ tp = SearchSysCache1(RANGESUBTYPE, ObjectIdGetDatum(subtypeOid));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
+ Oid result;
+
+ result = rngtup->rngtypid;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+ }
+
+ Oid
+ get_range_subtype_cmp(Oid rangeOid)
+ {
+ HeapTuple tp;
+
+ tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
+ Oid result;
+
+ result = rngtup->rngsubcmp;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+ }
+
+ Oid
+ get_range_subtype_float(Oid rangeOid)
+ {
+ HeapTuple tp;
+
+ tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
+ Oid result;
+
+ result = rngtup->rngsubfloat;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+ }
+
+ Oid
+ get_range_canonical(Oid rangeOid)
+ {
+ HeapTuple tp;
+
+ tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
+ Oid result;
+
+ result = rngtup->rngcanonical;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+ }
*** a/src/backend/utils/cache/syscache.c
--- b/src/backend/utils/cache/syscache.c
***************
*** 42,47 ****
--- 42,48 ----
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
+ #include "catalog/pg_range.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_tablespace.h"
***************
*** 531,536 **** static const struct cachedesc cacheinfo[] = {
--- 532,559 ----
},
2048
},
+ {RangeRelationId, /* RANGETYPE */
+ RangeTypidIndexId,
+ 1,
+ {
+ Anum_pg_range_rngtypid,
+ 0,
+ 0,
+ 0
+ },
+ 1024
+ },
+ {RangeRelationId, /* RANGESUBTYPE */
+ RangeSubtypeIndexId,
+ 1,
+ {
+ Anum_pg_range_rngsubtype,
+ 0,
+ 0,
+ 0
+ },
+ 1024
+ },
{RelationRelationId, /* RELNAMENSP */
ClassNameNspIndexId,
2,
*** a/src/backend/utils/fmgr/funcapi.c
--- b/src/backend/utils/fmgr/funcapi.c
***************
*** 407,416 **** resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
--- 407,418 ----
int nargs = declared_args->dim1;
bool have_anyelement_result = false;
bool have_anyarray_result = false;
+ bool have_anyrange_result = false;
bool have_anynonarray = false;
bool have_anyenum = false;
Oid anyelement_type = InvalidOid;
Oid anyarray_type = InvalidOid;
+ Oid anyrange_type = InvalidOid;
int i;
/* See if there are any polymorphic outputs; quick out if not */
***************
*** 432,437 **** resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
--- 434,441 ----
have_anyelement_result = true;
have_anyenum = true;
break;
+ case ANYRANGEOID:
+ have_anyrange_result = true;
default:
break;
}
***************
*** 460,465 **** resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
--- 464,473 ----
if (!OidIsValid(anyarray_type))
anyarray_type = get_call_expr_argtype(call_expr, i);
break;
+ case ANYRANGEOID:
+ if (!OidIsValid(anyrange_type))
+ anyrange_type = get_call_expr_argtype(call_expr, i);
+ break;
default:
break;
}
***************
*** 479,484 **** resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
--- 487,501 ----
anyelement_type,
ANYELEMENTOID);
+ if (have_anyelement_result && !OidIsValid(anyelement_type))
+ anyelement_type = resolve_generic_type(ANYELEMENTOID,
+ anyrange_type,
+ ANYRANGEOID);
+ if (have_anyrange_result && !OidIsValid(anyrange_type))
+ anyrange_type = resolve_generic_type(ANYRANGEOID,
+ anyelement_type,
+ ANYELEMENTOID);
+
/* Enforce ANYNONARRAY if needed */
if (have_anynonarray && type_is_array(anyelement_type))
return false;
***************
*** 508,513 **** resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
--- 525,537 ----
-1,
0);
break;
+ case ANYRANGEOID:
+ TupleDescInitEntry(tupdesc, i + 1,
+ NameStr(tupdesc->attrs[i]->attname),
+ anyrange_type,
+ -1,
+ 0);
+ break;
default:
break;
}
***************
*** 547,552 **** resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
--- 571,577 ----
case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID:
+ case ANYRANGEOID:
if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
have_anyelement_result = true;
else
***************
*** 611,616 **** resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
--- 636,642 ----
case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID:
+ case ANYRANGEOID:
argtypes[i] = anyelement_type;
break;
case ANYARRAYOID:
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 163,168 **** static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
--- 163,169 ----
static void dumpType(Archive *fout, TypeInfo *tyinfo);
static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
+ static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
***************
*** 6725,6730 **** dumpType(Archive *fout, TypeInfo *tyinfo)
--- 6726,6733 ----
dumpCompositeType(fout, tyinfo);
else if (tyinfo->typtype == TYPTYPE_ENUM)
dumpEnumType(fout, tyinfo);
+ else if (tyinfo->typtype == TYPTYPE_RANGE)
+ dumpRangeType(fout, tyinfo);
}
/*
***************
*** 6845,6850 **** dumpEnumType(Archive *fout, TypeInfo *tyinfo)
--- 6848,6936 ----
}
/*
+ * dumpEnumType
+ * writes out to fout the queries to recreate a user-defined enum type
+ */
+ static void
+ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
+ {
+ PQExpBuffer q = createPQExpBuffer();
+ PQExpBuffer delq = createPQExpBuffer();
+ PQExpBuffer query = createPQExpBuffer();
+ PGresult *res;
+ int num;
+
+ char *canonical;
+ Oid canonicalOid;
+
+ /* Set proper schema search path */
+ selectSourceSchema("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT rngtypid, "
+ "format_type(rngsubtype, NULL) as rngsubtype, "
+ "rngsubcmp, rngcanonical "
+ "FROM pg_catalog.pg_range "
+ "WHERE rngtypid = '%u'",
+ tyinfo->dobj.catId.oid);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ num = PQntuples(res);
+
+ /*
+ * DROP must be fully qualified in case same name appears in pg_catalog.
+ * CASCADE shouldn't be required here as for normal types since the I/O
+ * functions are generic and do not get dropped.
+ */
+ appendPQExpBuffer(delq, "DROP TYPE %s.",
+ fmtId(tyinfo->dobj.namespace->dobj.name));
+ appendPQExpBuffer(delq, "%s;\n",
+ fmtId(tyinfo->dobj.name));
+
+ appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
+ fmtId(tyinfo->dobj.name));
+
+ appendPQExpBuffer(q, "\n SUBTYPE = %s",
+ PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
+ appendPQExpBuffer(q, ",\n SUBTYPE_CMP = %s",
+ PQgetvalue(res, 0, PQfnumber(res, "rngsubcmp")));
+
+ canonical = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
+ canonicalOid = atooid(canonical);
+ if (OidIsValid(canonicalOid))
+ appendPQExpBuffer(q, ",\n CANONICAL = %s", canonical);
+
+ appendPQExpBuffer(q, "\n);\n");
+
+ ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
+ tyinfo->dobj.name,
+ tyinfo->dobj.namespace->dobj.name,
+ NULL,
+ tyinfo->rolname, false,
+ "TYPE", SECTION_PRE_DATA,
+ q->data, delq->data, NULL,
+ tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Dump Type Comments and Security Labels */
+ resetPQExpBuffer(q);
+
+ appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
+ dumpComment(fout, q->data,
+ tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+ tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ dumpSecLabel(fout, q->data,
+ tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+ tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+
+ PQclear(res);
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(query);
+ }
+
+ /*
* dumpBaseType
* writes out to fout the queries to recreate a user-defined base type
*/
*** a/src/include/catalog/catversion.h
--- b/src/include/catalog/catversion.h
***************
*** 53,58 ****
*/
/* yyyymmddN */
! #define CATALOG_VERSION_NO 201102011
#endif
--- 53,59 ----
*/
/* yyyymmddN */
! /* COMMITTER: please set appropriately */
! #define CATALOG_VERSION_NO 201111111
#endif
*** a/src/include/catalog/indexing.h
--- b/src/include/catalog/indexing.h
***************
*** 289,294 **** DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_rol
--- 289,299 ----
DECLARE_UNIQUE_INDEX(pg_seclabel_object_index, 3597, on pg_seclabel using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops, provider text_ops));
#define SecLabelObjectIndexId 3597
+ DECLARE_UNIQUE_INDEX(pg_range_rgntypid_index, 3542, on pg_range using btree(rngtypid oid_ops));
+ #define RangeTypidIndexId 3542
+ DECLARE_UNIQUE_INDEX(pg_range_rgnsubtype_index, 3543, on pg_range using btree(rngsubtype oid_ops));
+ #define RangeSubtypeIndexId 3543
+
/* last step of initialization script: build the indexes declared above */
BUILD_INDICES
*** a/src/include/catalog/pg_amop.h
--- b/src/include/catalog/pg_amop.h
***************
*** 709,712 **** DATA(insert ( 3683 3615 3615 5 s 3679 403 0 ));
--- 709,742 ----
DATA(insert ( 3702 3615 3615 7 s 3693 783 0 ));
DATA(insert ( 3702 3615 3615 8 s 3694 783 0 ));
+ /*
+ * btree range_ops
+ */
+ DATA(insert ( 3901 3831 3831 1 s 3884 403 0 ));
+ DATA(insert ( 3901 3831 3831 2 s 3885 403 0 ));
+ DATA(insert ( 3901 3831 3831 3 s 3882 403 0 ));
+ DATA(insert ( 3901 3831 3831 4 s 3886 403 0 ));
+ DATA(insert ( 3901 3831 3831 5 s 3887 403 0 ));
+
+ /*
+ * hash range_ops
+ */
+ DATA(insert ( 3903 3831 3831 1 s 3882 405 0 ));
+
+ /*
+ * GiST range_ops
+ */
+ DATA(insert ( 3919 3831 3831 1 s 3882 783 0 ));
+ DATA(insert ( 3919 3831 3831 2 s 3883 783 0 ));
+ DATA(insert ( 3919 3831 3831 3 s 3888 783 0 ));
+ DATA(insert ( 3919 3831 2776 4 s 3889 783 0 ));
+ DATA(insert ( 3919 2776 3831 5 s 3891 783 0 ));
+ DATA(insert ( 3919 3831 3831 6 s 3890 783 0 ));
+ DATA(insert ( 3919 3831 3831 7 s 3892 783 0 ));
+ DATA(insert ( 3919 3831 3831 8 s 3893 783 0 ));
+ DATA(insert ( 3919 3831 3831 9 s 3894 783 0 ));
+ DATA(insert ( 3919 3831 3831 10 s 3895 783 0 ));
+ DATA(insert ( 3919 3831 3831 11 s 3896 783 0 ));
+ DATA(insert ( 3919 3831 3831 12 s 3897 783 0 ));
+
#endif /* PG_AMOP_H */
*** a/src/include/catalog/pg_amproc.h
--- b/src/include/catalog/pg_amproc.h
***************
*** 336,340 **** DATA(insert ( 3659 3614 3614 4 3658 ));
--- 336,349 ----
DATA(insert ( 3659 3614 3614 5 2700 ));
DATA(insert ( 3626 3614 3614 1 3622 ));
DATA(insert ( 3683 3615 3615 1 3668 ));
+ DATA(insert ( 3901 3831 3831 1 3870 ));
+ DATA(insert ( 3903 3831 3831 1 3902 ));
+ DATA(insert ( 3919 3831 3831 1 3875 ));
+ DATA(insert ( 3919 3831 3831 2 3876 ));
+ DATA(insert ( 3919 3831 3831 3 3877 ));
+ DATA(insert ( 3919 3831 3831 4 3878 ));
+ DATA(insert ( 3919 3831 3831 5 3879 ));
+ DATA(insert ( 3919 3831 3831 6 3880 ));
+ DATA(insert ( 3919 3831 3831 7 3881 ));
#endif /* PG_AMPROC_H */
*** a/src/include/catalog/pg_opclass.h
--- b/src/include/catalog/pg_opclass.h
***************
*** 213,217 **** DATA(insert ( 783 tsvector_ops PGNSP PGUID 3655 3614 t 3642 ));
--- 213,220 ----
DATA(insert ( 2742 tsvector_ops PGNSP PGUID 3659 3614 t 25 ));
DATA(insert ( 403 tsquery_ops PGNSP PGUID 3683 3615 t 0 ));
DATA(insert ( 783 tsquery_ops PGNSP PGUID 3702 3615 t 20 ));
+ DATA(insert ( 403 range_ops PGNSP PGUID 3901 3831 t 0 ));
+ DATA(insert ( 405 range_ops PGNSP PGUID 3903 3831 t 0 ));
+ DATA(insert ( 783 range_ops PGNSP PGUID 3919 3831 t 0 ));
#endif /* PG_OPCLASS_H */
*** a/src/include/catalog/pg_operator.h
--- b/src/include/catalog/pg_operator.h
***************
*** 944,949 **** DATA(insert OID = 2991 ( ">" PGNSP PGUID b f f 2249 2249 16 2990 2992 record
--- 944,971 ----
DATA(insert OID = 2992 ( "<=" PGNSP PGUID b f f 2249 2249 16 2993 2991 record_le scalarltsel scalarltjoinsel ));
DATA(insert OID = 2993 ( ">=" PGNSP PGUID b f f 2249 2249 16 2992 2990 record_ge scalargtsel scalargtjoinsel ));
+ /* generic range type operators */
+ DATA(insert OID = 3882 ( "=" PGNSP PGUID b t t 3831 3831 16 3882 3883 range_eq eqsel eqjoinsel ));
+ DATA(insert OID = 3883 ( "<>" PGNSP PGUID b f f 3831 3831 16 3883 3882 range_ne neqsel neqjoinsel ));
+ DATA(insert OID = 3884 ( "<" PGNSP PGUID b f f 3831 3831 16 3887 3886 range_lt eqsel eqjoinsel ));
+ DATA(insert OID = 3885 ( "<=" PGNSP PGUID b f f 3831 3831 16 3886 3887 range_le eqsel eqjoinsel ));
+ DATA(insert OID = 3886 ( ">=" PGNSP PGUID b f f 3831 3831 16 3885 3884 range_ge eqsel eqjoinsel ));
+ DATA(insert OID = 3887 ( ">" PGNSP PGUID b f f 3831 3831 16 3884 3885 range_gt eqsel eqjoinsel ));
+ DATA(insert OID = 3888 ( "&&" PGNSP PGUID b f f 3831 3831 16 3888 0 3857 scalarltsel scalarltjoinsel ));
+ DATA(insert OID = 3889 ( "@>" PGNSP PGUID b f f 3831 2776 16 3891 0 3858 scalargtsel scalargtjoinsel ));
+ DATA(insert OID = 3890 ( "@>" PGNSP PGUID b f f 3831 3831 16 3892 0 3859 scalargtsel scalargtjoinsel ));
+ DATA(insert OID = 3891 ( "<@" PGNSP PGUID b f f 2776 3831 16 3889 0 3860 scalargtsel scalargtjoinsel ));
+ DATA(insert OID = 3892 ( "<@" PGNSP PGUID b f f 3831 3831 16 3890 0 3861 scalargtsel scalargtjoinsel ));
+ DATA(insert OID = 3893 ( "<<" PGNSP PGUID b f f 3831 3831 16 0 0 before scalargtsel scalargtjoinsel ));
+ DATA(insert OID = 3894 ( ">>" PGNSP PGUID b f f 3831 3831 16 0 0 after scalargtsel scalargtjoinsel ));
+ DATA(insert OID = 3895 ( "&<" PGNSP PGUID b f f 3831 3831 16 0 0 overleft scalarltsel scalarltjoinsel ));
+ DATA(insert OID = 3896 ( "&>" PGNSP PGUID b f f 3831 3831 16 0 0 overright scalargtsel scalargtjoinsel ));
+ DATA(insert OID = 3897 ( "-|-" PGNSP PGUID b f f 3831 3831 16 3897 0 adjacent scalargtsel scalargtjoinsel ));
+ DATA(insert OID = 3898 ( "+" PGNSP PGUID b f f 3831 3831 3831 3898 0 range_union - - ));
+ DATA(insert OID = 3899 ( "-" PGNSP PGUID b f f 3831 3831 3831 0 0 minus - - ));
+ DATA(insert OID = 3900 ( "*" PGNSP PGUID b f f 3831 3831 3831 3900 0 range_intersect - - ));
+ DATA(insert OID = 3920 ( "!?" PGNSP PGUID r f f 3831 0 16 0 3921 3850 - - ));
+ DATA(insert OID = 3921 ( "?" PGNSP PGUID r f f 3831 0 16 0 3920 3829 - - ));
/*
* function prototypes
*** a/src/include/catalog/pg_opfamily.h
--- b/src/include/catalog/pg_opfamily.h
***************
*** 139,143 **** DATA(insert OID = 3655 ( 783 tsvector_ops PGNSP PGUID ));
--- 139,146 ----
DATA(insert OID = 3659 ( 2742 tsvector_ops PGNSP PGUID ));
DATA(insert OID = 3683 ( 403 tsquery_ops PGNSP PGUID ));
DATA(insert OID = 3702 ( 783 tsquery_ops PGNSP PGUID ));
+ DATA(insert OID = 3901 ( 403 range_ops PGNSP PGUID ));
+ DATA(insert OID = 3903 ( 405 range_ops PGNSP PGUID ));
+ DATA(insert OID = 3919 ( 783 range_ops PGNSP PGUID ));
#endif /* PG_OPFAMILY_H */
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 1528,1533 **** DATA(insert OID = 1180 ( abstime PGNSP PGUID 12 1 0 0 f f f t f i 1 0 702 "
--- 1528,1539 ----
DESCR("convert timestamp with time zone to abstime");
DATA(insert OID = 1181 ( age PGNSP PGUID 12 1 0 0 f f f t f s 1 0 23 "28" _null_ _null_ _null_ _null_ xid_age _null_ _null_ _null_ ));
DESCR("age of a transaction ID, in transactions before current transaction");
+ DATA(insert OID = 3916 ( float8 PGNSP PGUID 12 1 0 0 f f f t f i 1 0 701 "1114" _null_ _null_ _null_ _null_ timestamp_float8 _null_ _null_ _null_ ));
+ DESCR("convert timestamp to float8");
+ DATA(insert OID = 3917 ( float8 PGNSP PGUID 12 1 0 0 f f f t f i 1 0 701 "1184" _null_ _null_ _null_ _null_ timestamp_float8 _null_ _null_ _null_ ));
+ DESCR("convert timestamp with time zone to float8");
+ DATA(insert OID = 3918 ( float8 PGNSP PGUID 12 1 0 0 f f f t f i 1 0 701 "1082" _null_ _null_ _null_ _null_ date_float8 _null_ _null_ _null_ ));
+ DESCR("convert date to float8");
DATA(insert OID = 1188 ( timestamptz_mi PGNSP PGUID 12 1 0 0 f f f t f i 2 0 1186 "1184 1184" _null_ _null_ _null_ _null_ timestamp_mi _null_ _null_ _null_ ));
DESCR("subtract");
***************
*** 4895,4900 **** DESCR("fetch the last row value");
--- 4901,5021 ----
DATA(insert OID = 3114 ( nth_value PGNSP PGUID 12 1 0 0 f t f t f i 2 0 2283 "2283 23" _null_ _null_ _null_ _null_ window_nth_value _null_ _null_ _null_ ));
DESCR("fetch the Nth row value");
+ /* procs for range types */
+ DATA(insert OID = 3832 ( anyrange_in PGNSP PGUID 12 1 0 0 f f f t f s 3 0 3831 "2275 26 23" _null_ _null_ _null_ _null_ anyrange_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3833 ( anyrange_out PGNSP PGUID 12 1 0 0 f f f t f s 1 0 2275 "3831" _null_ _null_ _null_ _null_ anyrange_out _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3834 ( range_in PGNSP PGUID 12 1 0 0 f f f t f s 3 0 3831 "2275 26 23" _null_ _null_ _null_ _null_ range_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3835 ( range_out PGNSP PGUID 12 1 0 0 f f f t f s 1 0 2275 "3831" _null_ _null_ _null_ _null_ range_out _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3836 ( range_recv PGNSP PGUID 12 1 0 0 f f f t f s 3 0 3831 "2281 26 23" _null_ _null_ _null_ _null_ range_recv _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3837 ( range_send PGNSP PGUID 12 1 0 0 f f f t f s 1 0 17 "3831" _null_ _null_ _null_ _null_ range_send _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3838 ( range PGNSP PGUID 12 1 0 0 f f f t f i 1 0 3831 "2283" _null_ _null_ _null_ _null_ range_make1 _null_ _null_ _null_ ));
+ DESCR("construct a range from a single point");
+ DATA(insert OID = 3839 ( range PGNSP PGUID 12 1 0 0 f f f t f i 2 0 3831 "2283 2283" _null_ _null_ _null_ _null_ range _null_ _null_ _null_ ));
+ DESCR("construct a left-inclusive range from two points");
+ DATA(insert OID = 3840 ( range__ PGNSP PGUID 12 1 0 0 f f f t f i 2 0 3831 "2283 2283" _null_ _null_ _null_ _null_ range__ _null_ _null_ _null_ ));
+ DESCR("construct an exclusive range from two points");
+ DATA(insert OID = 3841 ( range_i PGNSP PGUID 12 1 0 0 f f f t f i 2 0 3831 "2283 2283" _null_ _null_ _null_ _null_ range_i _null_ _null_ _null_ ));
+ DESCR("construct a right-inclusive range from two points");
+ DATA(insert OID = 3842 ( rangei_ PGNSP PGUID 12 1 0 0 f f f t f i 2 0 3831 "2283 2283" _null_ _null_ _null_ _null_ rangei_ _null_ _null_ _null_ ));
+ DESCR("construct a left-inclusive range from two points");
+ DATA(insert OID = 3843 ( rangeii PGNSP PGUID 12 1 0 0 f f f t f i 2 0 3831 "2283 2283" _null_ _null_ _null_ _null_ rangeii _null_ _null_ _null_ ));
+ DESCR("construct an inclusive range from two points");
+ DATA(insert OID = 3844 ( range_linf_ PGNSP PGUID 12 1 0 0 f f f t f i 1 0 3831 "2283" _null_ _null_ _null_ _null_ range_linf_ _null_ _null_ _null_ ));
+ DESCR("construct a range with an infinite lower bound and exclusive upper bound");
+ DATA(insert OID = 3845 ( range_uinf_ PGNSP PGUID 12 1 0 0 f f f t f i 1 0 3831 "2283" _null_ _null_ _null_ _null_ range_uinf_ _null_ _null_ _null_ ));
+ DESCR("construct a range with an infinite upper bound and exclusive lower bound");
+ DATA(insert OID = 3846 ( range_linfi PGNSP PGUID 12 1 0 0 f f f t f i 1 0 3831 "2283" _null_ _null_ _null_ _null_ range_linfi _null_ _null_ _null_ ));
+ DESCR("construct a range with an infinite lower bound and inclusive upper bound");
+ DATA(insert OID = 3847 ( range_uinfi PGNSP PGUID 12 1 0 0 f f f t f i 1 0 3831 "2283" _null_ _null_ _null_ _null_ range_uinfi _null_ _null_ _null_ ));
+ DESCR("construct a range with an infinite upper bound and inclusive lower bound");
+ DATA(insert OID = 3848 ( lower PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2283 "3831" _null_ _null_ _null_ _null_ range_lower _null_ _null_ _null_ ));
+ DESCR("return the range's lower bound");
+ DATA(insert OID = 3849 ( upper PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2283 "3831" _null_ _null_ _null_ _null_ range_upper _null_ _null_ _null_ ));
+ DESCR("return the range's upper bound");
+ DATA(insert OID = 3850 ( empty PGNSP PGUID 12 1 0 0 f f f t f i 1 0 16 "3831" _null_ _null_ _null_ _null_ range_empty _null_ _null_ _null_ ));
+ DESCR("is the range empty?");
+ DATA(insert OID = 3829 ( non_empty PGNSP PGUID 12 1 0 0 f f f t f i 1 0 16 "3831" _null_ _null_ _null_ _null_ range_non_empty _null_ _null_ _null_ ));
+ DESCR("is the range non-empty?");
+ DATA(insert OID = 3851 ( lower_inc PGNSP PGUID 12 1 0 0 f f f t f i 1 0 16 "3831" _null_ _null_ _null_ _null_ range_lower_inc _null_ _null_ _null_ ));
+ DESCR("is the range's lower bound inclusive?");
+ DATA(insert OID = 3852 ( upper_inc PGNSP PGUID 12 1 0 0 f f f t f i 1 0 16 "3831" _null_ _null_ _null_ _null_ range_upper_inc _null_ _null_ _null_ ));
+ DESCR("is the range's upper bound inclusive?");
+ DATA(insert OID = 3853 ( lower_inf PGNSP PGUID 12 1 0 0 f f f t f i 1 0 16 "3831" _null_ _null_ _null_ _null_ range_lower_inf _null_ _null_ _null_ ));
+ DESCR("is the range's lower bound infinite?");
+ DATA(insert OID = 3854 ( upper_inf PGNSP PGUID 12 1 0 0 f f f t f i 1 0 16 "3831" _null_ _null_ _null_ _null_ range_upper_inf _null_ _null_ _null_ ));
+ DESCR("is the range's upper bound infinite?");
+ DATA(insert OID = 3855 ( range_eq PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_eq _null_ _null_ _null_ ));
+ DESCR("are the two ranges equal?");
+ DATA(insert OID = 3856 ( range_ne PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_ne _null_ _null_ _null_ ));
+ DESCR("are the two ranges not equal?");
+ DATA(insert OID = 3857 ( overlaps PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_overlaps _null_ _null_ _null_ ));
+ DESCR("do the two ranges overlap?");
+ DATA(insert OID = 3858 ( contains PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 2776" _null_ _null_ _null_ _null_ range_contains_elem _null_ _null_ _null_ ));
+ DESCR("does the range contain the point?");
+ DATA(insert OID = 3859 ( contains PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_contains _null_ _null_ _null_ ));
+ DESCR("does the range contain the other range?");
+ DATA(insert OID = 3860 ( contained_by PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "2776 3831" _null_ _null_ _null_ _null_ elem_contained_by_range _null_ _null_ _null_ ));
+ DESCR("is the point contained by the range?");
+ DATA(insert OID = 3861 ( contained_by PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_contained_by _null_ _null_ _null_ ));
+ DESCR("is the range contained by the other range?");
+ DATA(insert OID = 3862 ( adjacent PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_adjacent _null_ _null_ _null_ ));
+ DESCR("are the two ranges adjacent?");
+ DATA(insert OID = 3863 ( before PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_before _null_ _null_ _null_ ));
+ DESCR("is the range before the other range?");
+ DATA(insert OID = 3864 ( after PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_after _null_ _null_ _null_ ));
+ DESCR("is the range after the other range?");
+ DATA(insert OID = 3865 ( overleft PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_overleft _null_ _null_ _null_ ));
+ DESCR("is the range after the other range?");
+ DATA(insert OID = 3866 ( overright PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_overright _null_ _null_ _null_ ));
+ DESCR("is the range after the other range?");
+ DATA(insert OID = 3867 ( range_union PGNSP PGUID 12 1 0 0 f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ range_union _null_ _null_ _null_ ));
+ DESCR("the union of the two ranges");
+ DATA(insert OID = 3868 ( range_intersect PGNSP PGUID 12 1 0 0 f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ range_intersect _null_ _null_ _null_ ));
+ DESCR("the intersection of the two ranges");
+ DATA(insert OID = 3869 ( minus PGNSP PGUID 12 1 0 0 f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ range_minus _null_ _null_ _null_ ));
+ DESCR("the set difference of the two ranges");
+ DATA(insert OID = 3870 ( range_cmp PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 "3831 3831" _null_ _null_ _null_ _null_ range_cmp _null_ _null_ _null_ ));
+ DATA(insert OID = 3871 ( range_lt PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_lt _null_ _null_ _null_ ));
+ DATA(insert OID = 3872 ( range_le PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_le _null_ _null_ _null_ ));
+ DATA(insert OID = 3873 ( range_ge PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_ge _null_ _null_ _null_ ));
+ DATA(insert OID = 3874 ( range_gt PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "3831 3831" _null_ _null_ _null_ _null_ range_gt _null_ _null_ _null_ ));
+ DATA(insert OID = 3875 ( range_gist_consistent PGNSP PGUID 12 1 0 0 f f f t f i 5 0 16 "2281 3831 21 26 2281" _null_ _null_ _null_ _null_ range_gist_consistent _null_ _null_ _null_ ));
+ DESCR("the set difference of the two ranges");
+ DATA(insert OID = 3876 ( range_gist_union PGNSP PGUID 12 1 0 0 f f f t f i 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ range_gist_union _null_ _null_ _null_ ));
+ DESCR("the set difference of the two ranges");
+ DATA(insert OID = 3877 ( range_gist_compress PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ range_gist_compress _null_ _null_ _null_ ));
+ DESCR("the set difference of the two ranges");
+ DATA(insert OID = 3878 ( range_gist_decompress PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ range_gist_decompress _null_ _null_ _null_ ));
+ DESCR("the set difference of the two ranges");
+ DATA(insert OID = 3879 ( range_gist_penalty PGNSP PGUID 12 1 0 0 f f f t f i 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ range_gist_penalty _null_ _null_ _null_ ));
+ DESCR("the set difference of the two ranges");
+ DATA(insert OID = 3880 ( range_gist_picksplit PGNSP PGUID 12 1 0 0 f f f t f i 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ range_gist_picksplit _null_ _null_ _null_ ));
+ DESCR("the set difference of the two ranges");
+ DATA(insert OID = 3881 ( range_gist_same PGNSP PGUID 12 1 0 0 f f f t f i 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ range_gist_same _null_ _null_ _null_ ));
+ DESCR("the set difference of the two ranges");
+ DATA(insert OID = 3902 ( hash_range PGNSP PGUID 12 1 0 0 f f f t f i 1 0 23 "3831" _null_ _null_ _null_ _null_ hash_range _null_ _null_ _null_ ));
+ DESCR("hash a range");
+ DATA(insert OID = 3914 ( int4range_canonical PGNSP PGUID 12 1 0 0 f f f t f i 1 0 3904 "3904" _null_ _null_ _null_ _null_ int4range_canonical _null_ _null_ _null_ ));
+ DESCR("convert an int4 range to canonical form");
+ DATA(insert OID = 3928 ( int8range_canonical PGNSP PGUID 12 1 0 0 f f f t f i 1 0 3926 "3926" _null_ _null_ _null_ _null_ int8range_canonical _null_ _null_ _null_ ));
+ DESCR("convert an int8 range to canonical form");
+ DATA(insert OID = 3915 ( daterange_canonical PGNSP PGUID 12 1 0 0 f f f t f i 1 0 3906 "3906" _null_ _null_ _null_ _null_ daterange_canonical _null_ _null_ _null_ ));
+ DESCR("convert a date range to canonical form");
+ DATA(insert OID = 3922 ( length PGNSP PGUID 14 100 0 0 f f f t f i 1 0 2283 "3831" _null_ _null_ _null_ _null_ "select pg_catalog.upper($1) - pg_catalog.lower($1);" _null_ _null_ _null_ ));
+ DESCR("range upper bound minus range lower bound");
+ DATA(insert OID = 3923 ( length PGNSP PGUID 14 100 0 0 f f f t f i 1 0 1186 "3908" _null_ _null_ _null_ _null_ "select pg_catalog.upper($1) - pg_catalog.lower($1);" _null_ _null_ _null_ ));
+ DESCR("range upper bound minus range lower bound");
+ DATA(insert OID = 3924 ( length PGNSP PGUID 14 100 0 0 f f f t f i 1 0 1186 "3910" _null_ _null_ _null_ _null_ "select pg_catalog.upper($1) - pg_catalog.lower($1);" _null_ _null_ _null_ ));
+ DESCR("range upper bound minus range lower bound");
+ DATA(insert OID = 3925 ( length PGNSP PGUID 14 100 0 0 f f f t f i 1 0 23 "3912" _null_ _null_ _null_ _null_ "select pg_catalog.upper($1) - pg_catalog.lower($1);" _null_ _null_ _null_ ));
+ DESCR("range upper bound minus range lower bound");
+
/*
* Symbolic values for provolatile column: these indicate whether the result
*** /dev/null
--- b/src/include/catalog/pg_range.h
***************
*** 0 ****
--- 1,80 ----
+ /*-------------------------------------------------------------------------
+ *
+ * pg_range.h
+ * definition of the system "range" relation (pg_range)
+ * along with the relation's initial contents.
+ *
+ *
+ * Copyright (c) 2006-2010, PostgreSQL Global Development Group
+ *
+ * src/include/catalog/pg_range.h
+ *
+ * NOTES
+ * the genbki.pl script reads this file and generates .bki
+ * information from the DATA() statements.
+ *
+ * XXX do NOT break up DATA() statements into multiple lines!
+ * the scripts are not as smart as you might think...
+ *
+ *-------------------------------------------------------------------------
+ */
+ #ifndef PG_RANGE_H
+ #define PG_RANGE_H
+
+ #include "catalog/genbki.h"
+
+ /* ----------------
+ * pg_range definition. cpp turns this into
+ * typedef struct FormData_pg_range
+ * ----------------
+ */
+ #define RangeRelationId 3541
+
+ CATALOG(pg_range,3541) BKI_WITHOUT_OIDS
+ {
+ Oid rngtypid; /* OID of owning range type */
+ Oid rngsubtype; /* OID of range's subtype */
+ regproc rngsubcmp; /* compare values of type 'subtype' */
+ regproc rngcanonical; /* canonicalize range, or 0 */
+ regproc rngsubfloat; /* represent subtype as a float8 (for GiST) */
+ } FormData_pg_range;
+
+ /* ----------------
+ * Form_pg_range corresponds to a pointer to a tuple with
+ * the format of pg_range relation.
+ * ----------------
+ */
+ typedef FormData_pg_range *Form_pg_range;
+
+ /* ----------------
+ * compiler constants for pg_range
+ * ----------------
+ */
+ #define Natts_pg_range 5
+ #define Anum_pg_range_rngtypid 1
+ #define Anum_pg_range_rngsubtype 2
+ #define Anum_pg_range_rngsubcmp 3
+ #define Anum_pg_range_rngcanonical 4
+ #define Anum_pg_range_rngsubfloat 5
+
+ /*
+ * prototypes for functions in pg_range.c
+ */
+
+ void RangeCreate(Oid rangeTypeOid, Oid rangeSubType,
+ regproc rangeSubtypeCmp, regproc rangeCanonical,
+ regproc rangeSubFloat);
+ void RangeDelete(Oid rangeTypeOid);
+
+ /* ----------------
+ * initial contents of pg_range
+ * ----------------
+ */
+ DATA(insert ( 3904 23 btint4cmp int4range_canonical 316 ));
+ DATA(insert ( 3906 1700 numeric_cmp - 1746 ));
+ DATA(insert ( 3908 1114 timestamp_cmp - 3916 ));
+ DATA(insert ( 3910 1184 timestamp_cmp - 3917 ));
+ DATA(insert ( 3912 1082 date_cmp daterange_canonical 3918 ));
+ DATA(insert ( 3926 20 btint8cmp int8range_canonical 482 ));
+
+ #endif /* PG_RANGE_H */
*** a/src/include/catalog/pg_type.h
--- b/src/include/catalog/pg_type.h
***************
*** 623,629 **** DATA(insert OID = 2776 ( anynonarray PGNSP PGUID 4 t p P f t \054 0 0 0 anynona
#define ANYNONARRAYOID 2776
DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in anyenum_out - - - - - i p f 0 -1 0 _null_ _null_ ));
#define ANYENUMOID 3500
!
/*
* macros
--- 623,658 ----
#define ANYNONARRAYOID 2776
DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in anyenum_out - - - - - i p f 0 -1 0 _null_ _null_ ));
#define ANYENUMOID 3500
! DATA(insert OID = 3831 ( anyrange PGNSP PGUID 4 t p P f t \054 0 0 0 anyrange_in anyrange_out - - - - - i p f 0 -1 0 _null_ _null_ ));
! #define ANYRANGEOID 3831
!
!
!
!
! DATA(insert OID = 3904 ( int4range PGNSP PGUID -1 f r R f t \054 0 0 3905 range_in range_out range_recv range_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define INT4RANGEOID 3904
! DATA(insert OID = 3905 ( _int4range PGNSP PGUID -1 f b A f t \054 0 3904 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define INT4RANGEARRAYOID 3905
! DATA(insert OID = 3906 ( numrange PGNSP PGUID -1 f r R f t \054 0 0 3907 range_in range_out range_recv range_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define NUMRANGEOID 3906
! DATA(insert OID = 3907 ( _numrange PGNSP PGUID -1 f b A f t \054 0 3906 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define NUMRANGEARRAYOID 3907
! DATA(insert OID = 3908 ( tsrange PGNSP PGUID -1 f r R f t \054 0 0 3909 range_in range_out range_recv range_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define TSRANGEOID 3908
! DATA(insert OID = 3909 ( _tsrange PGNSP PGUID -1 f b A f t \054 0 3908 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define TSRANGEARRAYOID 3909
! DATA(insert OID = 3910 ( tstzrange PGNSP PGUID -1 f r R f t \054 0 0 3911 range_in range_out range_recv range_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define TSTZRANGEOID 3910
! DATA(insert OID = 3911 ( _tstzrange PGNSP PGUID -1 f b A f t \054 0 3910 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define TSTZRANGEARRAYOID 3911
! DATA(insert OID = 3912 ( daterange PGNSP PGUID -1 f r R f t \054 0 0 3913 range_in range_out range_recv range_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define DATERANGEOID 3912
! DATA(insert OID = 3913 ( _daterange PGNSP PGUID -1 f b A f t \054 0 3912 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define DATERANGEARRAYOID 3913
! DATA(insert OID = 3926 ( int8range PGNSP PGUID -1 f r R f t \054 0 0 3927 range_in range_out range_recv range_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define INT8RANGEOID 3926
! DATA(insert OID = 3927 ( _int8range PGNSP PGUID -1 f b A f t \054 0 3926 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
! #define INT8RANGEARRAYOID 3927
/*
* macros
***************
*** 633,638 **** DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in
--- 662,668 ----
#define TYPTYPE_DOMAIN 'd' /* domain over another type */
#define TYPTYPE_ENUM 'e' /* enumerated type */
#define TYPTYPE_PSEUDO 'p' /* pseudo-type */
+ #define TYPTYPE_RANGE 'r' /* range type */
#define TYPCATEGORY_INVALID '\0' /* not an allowed category */
#define TYPCATEGORY_ARRAY 'A'
***************
*** 644,649 **** DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in
--- 674,680 ----
#define TYPCATEGORY_NETWORK 'I' /* think INET */
#define TYPCATEGORY_NUMERIC 'N'
#define TYPCATEGORY_PSEUDOTYPE 'P'
+ #define TYPCATEGORY_RANGE 'R'
#define TYPCATEGORY_STRING 'S'
#define TYPCATEGORY_TIMESPAN 'T'
#define TYPCATEGORY_USER 'U'
***************
*** 655,660 **** DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in
((typid) == ANYELEMENTOID || \
(typid) == ANYARRAYOID || \
(typid) == ANYNONARRAYOID || \
! (typid) == ANYENUMOID)
#endif /* PG_TYPE_H */
--- 686,692 ----
((typid) == ANYELEMENTOID || \
(typid) == ANYARRAYOID || \
(typid) == ANYNONARRAYOID || \
! (typid) == ANYENUMOID || \
! (typid) == ANYRANGEOID)
#endif /* PG_TYPE_H */
*** a/src/include/commands/typecmds.h
--- b/src/include/commands/typecmds.h
***************
*** 24,29 **** extern void RemoveTypes(DropStmt *drop);
--- 24,30 ----
extern void RemoveTypeById(Oid typeOid);
extern void DefineDomain(CreateDomainStmt *stmt);
extern void DefineEnum(CreateEnumStmt *stmt);
+ extern void DefineRange(CreateRangeStmt *stmt);
extern void AlterEnum(AlterEnumStmt *stmt);
extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist);
extern Oid AssignTypeArrayOid(void);
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
***************
*** 339,344 **** typedef enum NodeTag
--- 339,345 ----
T_ReassignOwnedStmt,
T_CompositeTypeStmt,
T_CreateEnumStmt,
+ T_CreateRangeStmt,
T_AlterEnumStmt,
T_AlterTSDictionaryStmt,
T_AlterTSConfigurationStmt,
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 2242,2247 **** typedef struct AlterEnumStmt
--- 2242,2258 ----
} AlterEnumStmt;
/* ----------------------
+ * Create Type Statement, enum types
+ * ----------------------
+ */
+ typedef struct CreateRangeStmt
+ {
+ NodeTag type;
+ List *typeName; /* qualified name (list of Value strings) */
+ List *params; /* range parameters (list of DefElem) */
+ } CreateRangeStmt;
+
+ /* ----------------------
* Create View Statement
* ----------------------
*/
*** a/src/include/utils/date.h
--- b/src/include/utils/date.h
***************
*** 146,151 **** extern Datum date_timestamptz(PG_FUNCTION_ARGS);
--- 146,152 ----
extern Datum timestamptz_date(PG_FUNCTION_ARGS);
extern Datum datetime_timestamp(PG_FUNCTION_ARGS);
extern Datum abstime_date(PG_FUNCTION_ARGS);
+ extern Datum date_float8(PG_FUNCTION_ARGS);
extern Datum time_in(PG_FUNCTION_ARGS);
extern Datum time_out(PG_FUNCTION_ARGS);
*** a/src/include/utils/lsyscache.h
--- b/src/include/utils/lsyscache.h
***************
*** 92,97 **** extern Oid get_rel_namespace(Oid relid);
--- 92,98 ----
extern Oid get_rel_type_id(Oid relid);
extern char get_rel_relkind(Oid relid);
extern Oid get_rel_tablespace(Oid relid);
+ extern char get_typalign(Oid typid);
extern bool get_typisdefined(Oid typid);
extern int16 get_typlen(Oid typid);
extern bool get_typbyval(Oid typid);
***************
*** 112,117 **** extern Node *get_typdefault(Oid typid);
--- 113,119 ----
extern char get_typtype(Oid typid);
extern bool type_is_rowtype(Oid typid);
extern bool type_is_enum(Oid typid);
+ extern bool type_is_range(Oid typid);
extern void get_type_category_preferred(Oid typid,
char *typcategory,
bool *typispreferred);
***************
*** 138,143 **** extern void free_attstatsslot(Oid atttype,
--- 140,150 ----
Datum *values, int nvalues,
float4 *numbers, int nnumbers);
extern char *get_namespace_name(Oid nspid);
+ extern Oid get_range_subtype(Oid rangeOid);
+ extern Oid get_range_from_subtype(Oid subtypeOid);
+ extern Oid get_range_subtype_cmp(Oid rangeOid);
+ extern Oid get_range_subtype_float(Oid rangeOid);
+ extern Oid get_range_canonical(Oid rangeOid);
#define type_is_array(typid) (get_element_type(typid) != InvalidOid)
/* type_is_array_domain accepts both plain arrays and domains over arrays */
*** /dev/null
--- b/src/include/utils/rangetypes.h
***************
*** 0 ****
--- 1,126 ----
+ /*-------------------------------------------------------------------------
+ *
+ * rangetypes.h
+ * Declarations for Postgres range types.
+ *
+ */
+
+ #ifndef RANGETYPES_H
+ #define RANGETYPES_H
+
+ #include "fmgr.h"
+
+ typedef struct varlena RangeType;
+
+ typedef struct
+ {
+ Datum val;
+ Oid rngtypid;
+ bool infinite;
+ bool lower;
+ bool inclusive;
+ } RangeBound;
+
+ /*
+ * fmgr macros for range type objects
+ */
+ #define DatumGetRangeType(X) ((RangeType *) PG_DETOAST_DATUM(X))
+ #define DatumGetRangeTypeCopy(X) ((RangeType *) PG_DETOAST_DATUM_COPY(X))
+ #define RangeTypeGetDatum(X) PointerGetDatum(X)
+ #define PG_GETARG_RANGE(n) DatumGetRangeType(PG_GETARG_DATUM(n))
+ #define PG_GETARG_RANGE_COPY(n) DatumGetRangeTypeCopy(PG_GETARG_DATUM(n))
+ #define PG_RETURN_RANGE(x) return RangeTypeGetDatum(x)
+
+ /*
+ * prototypes for functions defined in rangetypes.c
+ */
+
+ /* IO */
+ extern Datum anyrange_in(PG_FUNCTION_ARGS);
+ extern Datum anyrange_out(PG_FUNCTION_ARGS);
+ extern Datum range_in(PG_FUNCTION_ARGS);
+ extern Datum range_out(PG_FUNCTION_ARGS);
+ extern Datum range_recv(PG_FUNCTION_ARGS);
+ extern Datum range_send(PG_FUNCTION_ARGS);
+
+ /* constructors */
+ extern Datum range_make1(PG_FUNCTION_ARGS);
+ extern Datum range_linf_(PG_FUNCTION_ARGS);
+ extern Datum range_uinf_(PG_FUNCTION_ARGS);
+ extern Datum range_linfi(PG_FUNCTION_ARGS);
+ extern Datum range_uinfi(PG_FUNCTION_ARGS);
+ extern Datum range(PG_FUNCTION_ARGS);
+ extern Datum range__(PG_FUNCTION_ARGS);
+ extern Datum range_i(PG_FUNCTION_ARGS);
+ extern Datum rangei_(PG_FUNCTION_ARGS);
+ extern Datum rangeii(PG_FUNCTION_ARGS);
+
+ /* range -> subtype */
+ extern Datum range_lower(PG_FUNCTION_ARGS);
+ extern Datum range_upper(PG_FUNCTION_ARGS);
+
+ /* range -> bool */
+ extern Datum range_empty(PG_FUNCTION_ARGS);
+ extern Datum range_non_empty(PG_FUNCTION_ARGS);
+ extern Datum range_lower_inc(PG_FUNCTION_ARGS);
+ extern Datum range_upper_inc(PG_FUNCTION_ARGS);
+ extern Datum range_lower_inf(PG_FUNCTION_ARGS);
+ extern Datum range_upper_inf(PG_FUNCTION_ARGS);
+
+ /* range, point -> bool */
+ extern Datum range_contains_elem(PG_FUNCTION_ARGS);
+ extern Datum elem_contained_by_range(PG_FUNCTION_ARGS);
+
+ /* range, range -> bool */
+ extern Datum range_eq(PG_FUNCTION_ARGS);
+ extern Datum range_ne(PG_FUNCTION_ARGS);
+ extern Datum range_contains(PG_FUNCTION_ARGS);
+ extern Datum range_contained_by(PG_FUNCTION_ARGS);
+ extern Datum range_before(PG_FUNCTION_ARGS);
+ extern Datum range_after(PG_FUNCTION_ARGS);
+ extern Datum range_adjacent(PG_FUNCTION_ARGS);
+ extern Datum range_overlaps(PG_FUNCTION_ARGS);
+ extern Datum range_overleft(PG_FUNCTION_ARGS);
+ extern Datum range_overright(PG_FUNCTION_ARGS);
+
+ /* range, range -> range */
+ extern Datum range_minus(PG_FUNCTION_ARGS);
+ extern Datum range_union(PG_FUNCTION_ARGS);
+ extern Datum range_intersect(PG_FUNCTION_ARGS);
+
+ /* BTree support */
+ extern Datum range_cmp(PG_FUNCTION_ARGS);
+ extern Datum range_lt(PG_FUNCTION_ARGS);
+ extern Datum range_le(PG_FUNCTION_ARGS);
+ extern Datum range_ge(PG_FUNCTION_ARGS);
+ extern Datum range_gt(PG_FUNCTION_ARGS);
+
+ /* Hash support */
+ extern Datum hash_range(PG_FUNCTION_ARGS);
+
+ /* GiST support (rangetypes_gist.c) */
+ extern Datum range_gist_consistent(PG_FUNCTION_ARGS);
+ extern Datum range_gist_compress(PG_FUNCTION_ARGS);
+ extern Datum range_gist_decompress(PG_FUNCTION_ARGS);
+ extern Datum range_gist_union(PG_FUNCTION_ARGS);
+ extern Datum range_gist_penalty(PG_FUNCTION_ARGS);
+ extern Datum range_gist_picksplit(PG_FUNCTION_ARGS);
+ extern Datum range_gist_same(PG_FUNCTION_ARGS);
+
+ /* Canonical functions */
+ Datum int4range_canonical(PG_FUNCTION_ARGS);
+ Datum int8range_canonical(PG_FUNCTION_ARGS);
+ Datum daterange_canonical(PG_FUNCTION_ARGS);
+
+
+ /* for defining more generic functions */
+ extern Datum make_range(RangeBound *lower, RangeBound *upper, bool empty);
+ extern void range_deserialize(RangeType *range, RangeBound *lower,
+ RangeBound *upper, bool *empty);
+ extern int range_cmp_bounds(RangeBound *b1, RangeBound *b2);
+ extern RangeType *make_empty_range(Oid rngtypid);
+
+ /* for defining a range "canonicalize" function */
+ extern Datum range_serialize(RangeBound *lower, RangeBound *upper, bool empty);
+
+ #endif /* RANGETYPES_H */
*** a/src/include/utils/syscache.h
--- b/src/include/utils/syscache.h
***************
*** 68,73 **** enum SysCacheIdentifier
--- 68,75 ----
OPFAMILYOID,
PROCNAMEARGSNSP,
PROCOID,
+ RANGETYPE,
+ RANGESUBTYPE,
RELNAMENSP,
RELOID,
RULERELNAME,
*** a/src/include/utils/timestamp.h
--- b/src/include/utils/timestamp.h
***************
*** 266,271 **** extern Datum interval_part(PG_FUNCTION_ARGS);
--- 266,272 ----
extern Datum timestamp_zone(PG_FUNCTION_ARGS);
extern Datum timestamp_izone(PG_FUNCTION_ARGS);
extern Datum timestamp_timestamptz(PG_FUNCTION_ARGS);
+ extern Datum timestamp_float8(PG_FUNCTION_ARGS);
extern Datum timestamptz_in(PG_FUNCTION_ARGS);
extern Datum timestamptz_out(PG_FUNCTION_ARGS);
*** a/src/pl/plpgsql/src/pl_comp.c
--- b/src/pl/plpgsql/src/pl_comp.c
***************
*** 489,494 **** do_compile(FunctionCallInfo fcinfo,
--- 489,496 ----
{
if (rettypeid == ANYARRAYOID)
rettypeid = INT4ARRAYOID;
+ else if (rettypeid == ANYRANGEOID)
+ rettypeid = INT4RANGEOID;
else /* ANYELEMENT or ANYNONARRAY */
rettypeid = INT4OID;
/* XXX what could we use for ANYENUM? */
***************
*** 2055,2060 **** build_datatype(HeapTuple typeTup, int32 typmod)
--- 2057,2063 ----
case TYPTYPE_BASE:
case TYPTYPE_DOMAIN:
case TYPTYPE_ENUM:
+ case TYPTYPE_RANGE:
typ->ttype = PLPGSQL_TTYPE_SCALAR;
break;
case TYPTYPE_COMPOSITE:
***************
*** 2303,2310 **** compute_function_hashkey(FunctionCallInfo fcinfo,
/*
* This is the same as the standard resolve_polymorphic_argtypes() function,
* but with a special case for validation: assume that polymorphic arguments
! * are integer or integer-array. Also, we go ahead and report the error
! * if we can't resolve the types.
*/
static void
plpgsql_resolve_polymorphic_argtypes(int numargs,
--- 2306,2313 ----
/*
* This is the same as the standard resolve_polymorphic_argtypes() function,
* but with a special case for validation: assume that polymorphic arguments
! * are integer, integer-range or integer-array. Also, we go ahead and report
! * the error if we can't resolve the types.
*/
static void
plpgsql_resolve_polymorphic_argtypes(int numargs,
***************
*** 2337,2342 **** plpgsql_resolve_polymorphic_argtypes(int numargs,
--- 2340,2348 ----
case ANYENUMOID: /* XXX dubious */
argtypes[i] = INT4OID;
break;
+ case ANYRANGEOID:
+ argtypes[i] = INT4RANGEOID;
+ break;
case ANYARRAYOID:
argtypes[i] = INT4ARRAYOID;
break;
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
***************
*** 975,993 **** ORDER BY 1, 2, 3;
--- 975,1004 ----
403 | 5 | ~>~
405 | 1 | =
783 | 1 | <<
+ 783 | 1 | =
783 | 1 | @@
783 | 2 | &<
+ 783 | 2 | <>
783 | 3 | &&
783 | 4 | &>
+ 783 | 4 | @>
+ 783 | 5 | <@
783 | 5 | >>
+ 783 | 6 | @>
783 | 6 | ~=
+ 783 | 7 | <@
783 | 7 | @>
+ 783 | 8 | <<
783 | 8 | <@
783 | 9 | &<|
+ 783 | 9 | >>
+ 783 | 10 | &<
783 | 10 | <<|
783 | 10 | <^
+ 783 | 11 | &>
783 | 11 | >^
783 | 11 | |>>
+ 783 | 12 | -|-
783 | 12 | |&>
783 | 13 | ~
783 | 14 | @
***************
*** 1004,1010 **** ORDER BY 1, 2, 3;
2742 | 2 | @@@
2742 | 3 | <@
2742 | 4 | =
! (40 rows)
-- Check that all opclass search operators have selectivity estimators.
-- This is not absolutely required, but it seems a reasonable thing
--- 1015,1021 ----
2742 | 2 | @@@
2742 | 3 | <@
2742 | 4 | =
! (51 rows)
-- Check that all opclass search operators have selectivity estimators.
-- This is not absolutely required, but it seems a reasonable thing
*** /dev/null
--- b/src/test/regress/expected/rangetypes.out
***************
*** 0 ****
--- 1,699 ----
+ CREATE TABLE numrange_test (nr NUMRANGE);
+ create index numrange_test_btree on numrange_test(nr);
+ SET enable_seqscan = f;
+ -- negative test; should fail
+ INSERT INTO numrange_test VALUES('-[1.1, 2.2)');
+ ERROR: syntax error on range input "-[1.1, 2.2)", character 1
+ LINE 1: INSERT INTO numrange_test VALUES('-[1.1, 2.2)');
+ ^
+ INSERT INTO numrange_test VALUES('[1.1, NULL)');
+ ERROR: NULL range boundaries are not supported
+ LINE 1: INSERT INTO numrange_test VALUES('[1.1, NULL)');
+ ^
+ INSERT INTO numrange_test VALUES('[NULL, 2.2)');
+ ERROR: NULL range boundaries are not supported
+ LINE 1: INSERT INTO numrange_test VALUES('[NULL, 2.2)');
+ ^
+ INSERT INTO numrange_test VALUES('[NULL, NULL)');
+ ERROR: NULL range boundaries are not supported
+ LINE 1: INSERT INTO numrange_test VALUES('[NULL, NULL)');
+ ^
+ -- should succeed
+ INSERT INTO numrange_test VALUES('[-INF, INF)');
+ INSERT INTO numrange_test VALUES('[3, INF]');
+ INSERT INTO numrange_test VALUES('[-INF, 5)');
+ INSERT INTO numrange_test VALUES(range(1.1, 2.2));
+ INSERT INTO numrange_test VALUES('-');
+ INSERT INTO numrange_test VALUES(range(1.7));
+ SELECT empty(nr) FROM numrange_test;
+ empty
+ -------
+ f
+ f
+ f
+ f
+ t
+ f
+ (6 rows)
+
+ SELECT lower_inc(nr), lower(nr), upper(nr), upper_inc(nr) FROM numrange_test
+ WHERE NOT empty(nr) AND NOT lower_inf(nr) AND NOT upper_inf(nr);
+ lower_inc | lower | upper | upper_inc
+ -----------+-------+-------+-----------
+ t | 1.1 | 2.2 | f
+ t | 1.7 | 1.7 | t
+ (2 rows)
+
+ SELECT * FROM numrange_test WHERE contains(nr, range(1.9,1.91));
+ nr
+ ---------------
+ ( -INF, INF )
+ ( -INF, 5 )
+ [ 1.1, 2.2 )
+ (3 rows)
+
+ SELECT * FROM numrange_test WHERE nr @> range(1.0,10000.1);
+ nr
+ ---------------
+ ( -INF, INF )
+ (1 row)
+
+ SELECT * FROM numrange_test WHERE contained_by(range(-1e7,-10000.1), nr);
+ nr
+ ---------------
+ ( -INF, INF )
+ ( -INF, 5 )
+ (2 rows)
+
+ SELECT * FROM numrange_test WHERE 1.9 <@ nr;
+ nr
+ ---------------
+ ( -INF, INF )
+ ( -INF, 5 )
+ [ 1.1, 2.2 )
+ (3 rows)
+
+ SELECT * FROM numrange_test WHERE nr = '-';
+ nr
+ ----
+ -
+ (1 row)
+
+ SELECT * FROM numrange_test WHERE range_eq(nr, '(1.1, 2.2)');
+ nr
+ ----
+ (0 rows)
+
+ SELECT * FROM numrange_test WHERE nr = '[1.1, 2.2)';
+ nr
+ --------------
+ [ 1.1, 2.2 )
+ (1 row)
+
+ select range(2.0, 1.0);
+ ERROR: range lower bound must be less than or equal to range upper bound
+ select range(2.0, 3.0) -|- range(3.0, 4.0);
+ ?column?
+ ----------
+ t
+ (1 row)
+
+ select adjacent(range(2.0, 3.0), range(3.1, 4.0));
+ adjacent
+ ----------
+ f
+ (1 row)
+
+ select rangeii(2.0, 3.0) -|- range__(3.0, 4.0);
+ ?column?
+ ----------
+ t
+ (1 row)
+
+ select range(1.0, 2.0) -|- rangeii(2.0, 3.0);
+ ?column?
+ ----------
+ t
+ (1 row)
+
+ select adjacent(range_i(2.0, 3.0), range_i(1.0, 2.0));
+ adjacent
+ ----------
+ t
+ (1 row)
+
+ select range(1.1, 3.3) <@ range(0.1,10.1);
+ ?column?
+ ----------
+ t
+ (1 row)
+
+ select range(0.1, 10.1) <@ range(1.1,3.3);
+ ?column?
+ ----------
+ f
+ (1 row)
+
+ select range(1.1, 2.2) - range(2.0, 3.0);
+ ?column?
+ --------------
+ [ 1.1, 2.0 )
+ (1 row)
+
+ select range(1.1, 2.2) - range(2.2, 3.0);
+ ?column?
+ --------------
+ [ 1.1, 2.2 )
+ (1 row)
+
+ select rangeii(1.1, 2.2) - range(2.0, 3.0);
+ ?column?
+ --------------
+ [ 1.1, 2.0 )
+ (1 row)
+
+ select minus(rangeii(10.1, 12.2), range_i(110.0,120.2));
+ minus
+ ----------------
+ [ 10.1, 12.2 ]
+ (1 row)
+
+ select minus(rangeii(10.1, 12.2), range_i(0.0,120.2));
+ minus
+ -------
+ -
+ (1 row)
+
+ select rangeii(4.5, 5.5) && range(5.5, 6.5);
+ ?column?
+ ----------
+ t
+ (1 row)
+
+ select range(1.0, 2.0) << range(3.0, 4.0);
+ ?column?
+ ----------
+ t
+ (1 row)
+
+ select range(1.0, 2.0) >> range(3.0, 4.0);
+ ?column?
+ ----------
+ f
+ (1 row)
+
+ select range(3.0, 70.0) &< range(6.6, 100.0);
+ ?column?
+ ----------
+ t
+ (1 row)
+
+ select range(1.1, 2.2) < range(1.0, 200.2);
+ ?column?
+ ----------
+ f
+ (1 row)
+
+ select range(1.1, 2.2) < range__(1.1, 1.2);
+ ?column?
+ ----------
+ t
+ (1 row)
+
+ select range(1.0, 2.0) + range(2.0, 3.0);
+ ?column?
+ --------------
+ [ 1.0, 3.0 )
+ (1 row)
+
+ select range(1.0, 2.0) + range(1.5, 3.0);
+ ?column?
+ --------------
+ [ 1.0, 3.0 )
+ (1 row)
+
+ select range(1.0, 2.0) + range(2.5, 3.0);
+ ERROR: range union resulted in two ranges
+ select range(1.0, 2.0) * range(2.0, 3.0);
+ ?column?
+ ----------
+ -
+ (1 row)
+
+ select range(1.0, 2.0) * range(1.5, 3.0);
+ ?column?
+ --------------
+ [ 1.5, 2.0 )
+ (1 row)
+
+ select range(1.0, 2.0) * range(2.5, 3.0);
+ ?column?
+ ----------
+ -
+ (1 row)
+
+ select * from numrange_test where nr < rangeii(-1000.0, -1000.0);
+ nr
+ ---------------
+ ( -INF, INF )
+ ( -INF, 5 )
+ -
+ (3 rows)
+
+ select * from numrange_test where nr < rangeii(0.0, 1.0);
+ nr
+ ---------------
+ ( -INF, INF )
+ ( -INF, 5 )
+ -
+ (3 rows)
+
+ select * from numrange_test where nr < rangeii(1000.0, 1001.0);
+ nr
+ ---------------
+ ( -INF, INF )
+ [ 3, INF )
+ ( -INF, 5 )
+ [ 1.1, 2.2 )
+ -
+ [ 1.7, 1.7 ]
+ (6 rows)
+
+ select * from numrange_test where nr > rangeii(-1001.0, -1000.0);
+ nr
+ --------------
+ [ 3, INF )
+ [ 1.1, 2.2 )
+ [ 1.7, 1.7 ]
+ (3 rows)
+
+ select * from numrange_test where nr > rangeii(0.0, 1.0);
+ nr
+ --------------
+ [ 3, INF )
+ [ 1.1, 2.2 )
+ [ 1.7, 1.7 ]
+ (3 rows)
+
+ select * from numrange_test where nr > rangeii(1000.0, 1000.0);
+ nr
+ ----
+ (0 rows)
+
+ create table numrange_test2(nr numrange);
+ create index numrange_test2_hash_idx on numrange_test2 (nr);
+ INSERT INTO numrange_test2 VALUES('[-INF, 5)');
+ INSERT INTO numrange_test2 VALUES(range(1.1, 2.2));
+ INSERT INTO numrange_test2 VALUES(range(1.1, 2.2));
+ INSERT INTO numrange_test2 VALUES(range__(1.1, 2.2));
+ INSERT INTO numrange_test2 VALUES('-');
+ select * from numrange_test2 where nr = '-'::numrange;
+ nr
+ ----
+ -
+ (1 row)
+
+ select * from numrange_test2 where nr = range(1.1, 2.2);
+ nr
+ --------------
+ [ 1.1, 2.2 )
+ [ 1.1, 2.2 )
+ (2 rows)
+
+ select * from numrange_test2 where nr = range(1.1, 2.3);
+ nr
+ ----
+ (0 rows)
+
+ set enable_nestloop=t;
+ set enable_hashjoin=f;
+ set enable_mergejoin=f;
+ select * from numrange_test natural join numrange_test2 order by nr;
+ nr
+ --------------
+ -
+ ( -INF, 5 )
+ [ 1.1, 2.2 )
+ [ 1.1, 2.2 )
+ (4 rows)
+
+ set enable_nestloop=f;
+ set enable_hashjoin=t;
+ set enable_mergejoin=f;
+ select * from numrange_test natural join numrange_test2 order by nr;
+ nr
+ --------------
+ -
+ ( -INF, 5 )
+ [ 1.1, 2.2 )
+ [ 1.1, 2.2 )
+ (4 rows)
+
+ set enable_nestloop=f;
+ set enable_hashjoin=f;
+ set enable_mergejoin=t;
+ select * from numrange_test natural join numrange_test2 order by nr;
+ nr
+ --------------
+ -
+ ( -INF, 5 )
+ [ 1.1, 2.2 )
+ [ 1.1, 2.2 )
+ (4 rows)
+
+ set enable_nestloop to default;
+ set enable_hashjoin to default;
+ set enable_mergejoin to default;
+ SET enable_seqscan TO DEFAULT;
+ DROP TABLE numrange_test;
+ DROP TABLE numrange_test2;
+ -- test canonical form for int4range
+ select range__(1,10);
+ range__
+ -----------
+ [ 2, 10 )
+ (1 row)
+
+ select rangei_(1,10);
+ rangei_
+ -----------
+ [ 1, 10 )
+ (1 row)
+
+ select range_i(1,10);
+ range_i
+ -----------
+ [ 2, 11 )
+ (1 row)
+
+ select rangeii(1,10);
+ rangeii
+ -----------
+ [ 1, 11 )
+ (1 row)
+
+ -- test canonical form for daterange
+ select range__('2000-01-10'::date, '2000-01-20'::date);
+ range__
+ ----------------------------
+ [ 01-11-2000, 01-20-2000 )
+ (1 row)
+
+ select rangei_('2000-01-10'::date, '2000-01-20'::date);
+ rangei_
+ ----------------------------
+ [ 01-10-2000, 01-20-2000 )
+ (1 row)
+
+ select range_i('2000-01-10'::date, '2000-01-20'::date);
+ range_i
+ ----------------------------
+ [ 01-11-2000, 01-21-2000 )
+ (1 row)
+
+ select rangeii('2000-01-10'::date, '2000-01-20'::date);
+ rangeii
+ ----------------------------
+ [ 01-10-2000, 01-21-2000 )
+ (1 row)
+
+ -- test length()
+ select length(range(10.1,100.1));
+ length
+ --------
+ 90.0
+ (1 row)
+
+ select length('[2000-01-01 01:00:00, 2000-01-05 03:00:00)'::tsrange);
+ length
+ ------------------
+ @ 4 days 2 hours
+ (1 row)
+
+ select length('[2000-01-01 01:00:00, 2000-01-01 03:00:00)'::tstzrange);
+ length
+ -----------
+ @ 2 hours
+ (1 row)
+
+ select length('[2000-01-01, 2000-01-05)'::daterange);
+ length
+ --------
+ 4
+ (1 row)
+
+ create table test_range_gist(ir int4range);
+ create index test_range_gist_idx on test_range_gist using gist (ir);
+ insert into test_range_gist select range(g, g+10) from generate_series(1,2000) g;
+ insert into test_range_gist select '-'::int4range from generate_series(1,500) g;
+ insert into test_range_gist select range(g, g+10000) from generate_series(1,1000) g;
+ insert into test_range_gist select '-'::int4range from generate_series(1,500) g;
+ insert into test_range_gist select range_linfi(g*10) from generate_series(1,100) g;
+ insert into test_range_gist select range_uinf_(g*10) from generate_series(1,100) g;
+ insert into test_range_gist select range(g, g+10) from generate_series(1,2000) g;
+ BEGIN;
+ SET LOCAL enable_seqscan = t;
+ SET LOCAL enable_bitmapscan = f;
+ SET LOCAL enable_indexscan = f;
+ select count(*) from test_range_gist where ir @> '-'::int4range;
+ count
+ -------
+ 6200
+ (1 row)
+
+ select count(*) from test_range_gist where ir = range(10,20);
+ count
+ -------
+ 2
+ (1 row)
+
+ select count(*) from test_range_gist where ir @> 10;
+ count
+ -------
+ 130
+ (1 row)
+
+ select count(*) from test_range_gist where ir @> range(10,20);
+ count
+ -------
+ 111
+ (1 row)
+
+ select count(*) from test_range_gist where ir && range(10,20);
+ count
+ -------
+ 158
+ (1 row)
+
+ select count(*) from test_range_gist where ir <@ range(10,50);
+ count
+ -------
+ 1062
+ (1 row)
+
+ select count(*) from (select * from test_range_gist where ir?) s where ir << range(100,500);
+ count
+ -------
+ 189
+ (1 row)
+
+ select count(*) from (select * from test_range_gist where ir?) s where ir >> range(100,500);
+ count
+ -------
+ 3554
+ (1 row)
+
+ select count(*) from (select * from test_range_gist where ir?) s where ir &< range(100,500);
+ count
+ -------
+ 1029
+ (1 row)
+
+ select count(*) from (select * from test_range_gist where ir?) s where ir &> range(100,500);
+ count
+ -------
+ 4794
+ (1 row)
+
+ select count(*) from (select * from test_range_gist where ir?) s where ir -|- range(100,500);
+ count
+ -------
+ 5
+ (1 row)
+
+ COMMIT;
+ BEGIN;
+ SET LOCAL enable_seqscan = f;
+ SET LOCAL enable_bitmapscan = f;
+ SET LOCAL enable_indexscan = t;
+ select count(*) from test_range_gist where ir @> '-'::int4range;
+ count
+ -------
+ 6200
+ (1 row)
+
+ select count(*) from test_range_gist where ir = range(10,20);
+ count
+ -------
+ 2
+ (1 row)
+
+ select count(*) from test_range_gist where ir @> 10;
+ count
+ -------
+ 130
+ (1 row)
+
+ select count(*) from test_range_gist where ir @> range(10,20);
+ count
+ -------
+ 111
+ (1 row)
+
+ select count(*) from test_range_gist where ir && range(10,20);
+ count
+ -------
+ 158
+ (1 row)
+
+ select count(*) from test_range_gist where ir <@ range(10,50);
+ count
+ -------
+ 1062
+ (1 row)
+
+ select count(*) from test_range_gist where ir << range(100,500);
+ count
+ -------
+ 189
+ (1 row)
+
+ select count(*) from test_range_gist where ir >> range(100,500);
+ count
+ -------
+ 3554
+ (1 row)
+
+ select count(*) from test_range_gist where ir &< range(100,500);
+ count
+ -------
+ 1029
+ (1 row)
+
+ select count(*) from test_range_gist where ir &> range(100,500);
+ count
+ -------
+ 4794
+ (1 row)
+
+ select count(*) from test_range_gist where ir -|- range(100,500);
+ count
+ -------
+ 5
+ (1 row)
+
+ COMMIT;
+ drop index test_range_gist_idx;
+ create index test_range_gist_idx on test_range_gist using gist (ir);
+ BEGIN;
+ SET LOCAL enable_seqscan = f;
+ SET LOCAL enable_bitmapscan = f;
+ SET LOCAL enable_indexscan = t;
+ select count(*) from test_range_gist where ir @> '-'::int4range;
+ count
+ -------
+ 6200
+ (1 row)
+
+ select count(*) from test_range_gist where ir = range(10,20);
+ count
+ -------
+ 2
+ (1 row)
+
+ select count(*) from test_range_gist where ir @> 10;
+ count
+ -------
+ 130
+ (1 row)
+
+ select count(*) from test_range_gist where ir @> range(10,20);
+ count
+ -------
+ 111
+ (1 row)
+
+ select count(*) from test_range_gist where ir && range(10,20);
+ count
+ -------
+ 158
+ (1 row)
+
+ select count(*) from test_range_gist where ir <@ range(10,50);
+ count
+ -------
+ 1062
+ (1 row)
+
+ select count(*) from test_range_gist where ir << range(100,500);
+ count
+ -------
+ 189
+ (1 row)
+
+ select count(*) from test_range_gist where ir >> range(100,500);
+ count
+ -------
+ 3554
+ (1 row)
+
+ select count(*) from test_range_gist where ir &< range(100,500);
+ count
+ -------
+ 1029
+ (1 row)
+
+ select count(*) from test_range_gist where ir &> range(100,500);
+ count
+ -------
+ 4794
+ (1 row)
+
+ select count(*) from test_range_gist where ir -|- range(100,500);
+ count
+ -------
+ 5
+ (1 row)
+
+ COMMIT;
+ drop table test_range_gist;
+ --
+ -- Btree_gist is not included by default, so to test exclusion
+ -- constraints with range types, use singleton int ranges for the "="
+ -- portion of the constraint.
+ --
+ create table test_range_excl(
+ room int4range,
+ speaker int4range,
+ during tsrange,
+ exclude using gist (room with =, during with &&),
+ exclude using gist (speaker with =, during with &&)
+ );
+ NOTICE: CREATE TABLE / EXCLUDE will create implicit index "test_range_excl_room_during_excl" for table "test_range_excl"
+ NOTICE: CREATE TABLE / EXCLUDE will create implicit index "test_range_excl_speaker_during_excl" for table "test_range_excl"
+ insert into test_range_excl
+ values(range(123), range(1), '[2010-01-02 10:00, 2010-01-02 11:00)');
+ insert into test_range_excl
+ values(range(123), range(2), '[2010-01-02 11:00, 2010-01-02 12:00)');
+ insert into test_range_excl
+ values(range(123), range(3), '[2010-01-02 10:10, 2010-01-02 11:10)');
+ ERROR: conflicting key value violates exclusion constraint "test_range_excl_room_during_excl"
+ DETAIL: Key (room, during)=([ 123, 124 ), [ Sat Jan 02 10:10:00 2010, Sat Jan 02 11:10:00 2010 )) conflicts with existing key (room, during)=([ 123, 124 ), [ Sat Jan 02 10:00:00 2010, Sat Jan 02 11:00:00 2010 )).
+ insert into test_range_excl
+ values(range(124), range(3), '[2010-01-02 10:10, 2010-01-02 11:10)');
+ insert into test_range_excl
+ values(range(125), range(1), '[2010-01-02 10:10, 2010-01-02 11:10)');
+ ERROR: conflicting key value violates exclusion constraint "test_range_excl_speaker_during_excl"
+ DETAIL: Key (speaker, during)=([ 1, 2 ), [ Sat Jan 02 10:10:00 2010, Sat Jan 02 11:10:00 2010 )) conflicts with existing key (speaker, during)=([ 1, 2 ), [ Sat Jan 02 10:00:00 2010, Sat Jan 02 11:00:00 2010 )).
+ drop table test_range_excl;
+ -- test bigint ranges
+ select range_i(10000000000::int8, 20000000000::int8);
+ range_i
+ ------------------------------
+ [ 10000000001, 20000000001 )
+ (1 row)
+
+ -- test tstz ranges
+ set timezone to '-08';
+ select '[2010-01-01 01:00:00 -05, 2010-01-01 02:00:00 -08)'::tstzrange;
+ tstzrange
+ ----------------------------------------------------------------
+ [ Thu Dec 31 22:00:00 2009 -08, Fri Jan 01 02:00:00 2010 -08 )
+ (1 row)
+
+ -- should fail
+ select '[2010-01-01 01:00:00 -08, 2010-01-01 02:00:00 -05)'::tstzrange;
+ ERROR: range lower bound must be less than or equal to range upper bound
+ LINE 1: select '[2010-01-01 01:00:00 -08, 2010-01-01 02:00:00 -05)':...
+ ^
+ set timezone to default;
*** a/src/test/regress/expected/sanity_check.out
--- b/src/test/regress/expected/sanity_check.out
***************
*** 114,119 **** SELECT relname, relhasindex
--- 114,120 ----
pg_opfamily | t
pg_pltemplate | t
pg_proc | t
+ pg_range | t
pg_rewrite | t
pg_seclabel | t
pg_shdepend | t
***************
*** 155,161 **** SELECT relname, relhasindex
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (144 rows)
--
-- another sanity check: every system catalog that has OIDs should have
--- 156,162 ----
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (145 rows)
--
-- another sanity check: every system catalog that has OIDs should have
*** a/src/test/regress/expected/type_sanity.out
--- b/src/test/regress/expected/type_sanity.out
***************
*** 17,23 **** SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typnamespace = 0 OR
(p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
! (p1.typtype not in ('b', 'c', 'd', 'e', 'p')) OR
NOT p1.typisdefined OR
(p1.typalign not in ('c', 's', 'i', 'd')) OR
(p1.typstorage not in ('p', 'x', 'e', 'm'));
--- 17,23 ----
FROM pg_type as p1
WHERE p1.typnamespace = 0 OR
(p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
! (p1.typtype not in ('b', 'c', 'd', 'e', 'p', 'r')) OR
NOT p1.typisdefined OR
(p1.typalign not in ('c', 's', 'i', 'd')) OR
(p1.typstorage not in ('p', 'x', 'e', 'm'));
*** a/src/test/regress/parallel_schedule
--- b/src/test/regress/parallel_schedule
***************
*** 13,19 **** test: tablespace
# ----------
# The first group of parallel tests
# ----------
! test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum money
# Depends on things setup during char, varchar and text
test: strings
--- 13,19 ----
# ----------
# The first group of parallel tests
# ----------
! test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric txid uuid enum money rangetypes
# Depends on things setup during char, varchar and text
test: strings
*** /dev/null
--- b/src/test/regress/sql/rangetypes.sql
***************
*** 0 ****
--- 1,226 ----
+
+ CREATE TABLE numrange_test (nr NUMRANGE);
+ create index numrange_test_btree on numrange_test(nr);
+ SET enable_seqscan = f;
+
+ -- negative test; should fail
+ INSERT INTO numrange_test VALUES('-[1.1, 2.2)');
+ INSERT INTO numrange_test VALUES('[1.1, NULL)');
+ INSERT INTO numrange_test VALUES('[NULL, 2.2)');
+ INSERT INTO numrange_test VALUES('[NULL, NULL)');
+
+ -- should succeed
+ INSERT INTO numrange_test VALUES('[-INF, INF)');
+ INSERT INTO numrange_test VALUES('[3, INF]');
+ INSERT INTO numrange_test VALUES('[-INF, 5)');
+ INSERT INTO numrange_test VALUES(range(1.1, 2.2));
+ INSERT INTO numrange_test VALUES('-');
+ INSERT INTO numrange_test VALUES(range(1.7));
+
+ SELECT empty(nr) FROM numrange_test;
+ SELECT lower_inc(nr), lower(nr), upper(nr), upper_inc(nr) FROM numrange_test
+ WHERE NOT empty(nr) AND NOT lower_inf(nr) AND NOT upper_inf(nr);
+
+ SELECT * FROM numrange_test WHERE contains(nr, range(1.9,1.91));
+ SELECT * FROM numrange_test WHERE nr @> range(1.0,10000.1);
+ SELECT * FROM numrange_test WHERE contained_by(range(-1e7,-10000.1), nr);
+ SELECT * FROM numrange_test WHERE 1.9 <@ nr;
+ SELECT * FROM numrange_test WHERE nr = '-';
+ SELECT * FROM numrange_test WHERE range_eq(nr, '(1.1, 2.2)');
+ SELECT * FROM numrange_test WHERE nr = '[1.1, 2.2)';
+
+ select range(2.0, 1.0);
+
+ select range(2.0, 3.0) -|- range(3.0, 4.0);
+ select adjacent(range(2.0, 3.0), range(3.1, 4.0));
+ select rangeii(2.0, 3.0) -|- range__(3.0, 4.0);
+ select range(1.0, 2.0) -|- rangeii(2.0, 3.0);
+ select adjacent(range_i(2.0, 3.0), range_i(1.0, 2.0));
+
+ select range(1.1, 3.3) <@ range(0.1,10.1);
+ select range(0.1, 10.1) <@ range(1.1,3.3);
+
+ select range(1.1, 2.2) - range(2.0, 3.0);
+ select range(1.1, 2.2) - range(2.2, 3.0);
+ select rangeii(1.1, 2.2) - range(2.0, 3.0);
+ select minus(rangeii(10.1, 12.2), range_i(110.0,120.2));
+ select minus(rangeii(10.1, 12.2), range_i(0.0,120.2));
+
+ select rangeii(4.5, 5.5) && range(5.5, 6.5);
+ select range(1.0, 2.0) << range(3.0, 4.0);
+ select range(1.0, 2.0) >> range(3.0, 4.0);
+ select range(3.0, 70.0) &< range(6.6, 100.0);
+
+ select range(1.1, 2.2) < range(1.0, 200.2);
+ select range(1.1, 2.2) < range__(1.1, 1.2);
+
+ select range(1.0, 2.0) + range(2.0, 3.0);
+ select range(1.0, 2.0) + range(1.5, 3.0);
+ select range(1.0, 2.0) + range(2.5, 3.0);
+
+ select range(1.0, 2.0) * range(2.0, 3.0);
+ select range(1.0, 2.0) * range(1.5, 3.0);
+ select range(1.0, 2.0) * range(2.5, 3.0);
+
+ select * from numrange_test where nr < rangeii(-1000.0, -1000.0);
+ select * from numrange_test where nr < rangeii(0.0, 1.0);
+ select * from numrange_test where nr < rangeii(1000.0, 1001.0);
+ select * from numrange_test where nr > rangeii(-1001.0, -1000.0);
+ select * from numrange_test where nr > rangeii(0.0, 1.0);
+ select * from numrange_test where nr > rangeii(1000.0, 1000.0);
+
+ create table numrange_test2(nr numrange);
+ create index numrange_test2_hash_idx on numrange_test2 (nr);
+ INSERT INTO numrange_test2 VALUES('[-INF, 5)');
+ INSERT INTO numrange_test2 VALUES(range(1.1, 2.2));
+ INSERT INTO numrange_test2 VALUES(range(1.1, 2.2));
+ INSERT INTO numrange_test2 VALUES(range__(1.1, 2.2));
+ INSERT INTO numrange_test2 VALUES('-');
+
+ select * from numrange_test2 where nr = '-'::numrange;
+ select * from numrange_test2 where nr = range(1.1, 2.2);
+ select * from numrange_test2 where nr = range(1.1, 2.3);
+
+ set enable_nestloop=t;
+ set enable_hashjoin=f;
+ set enable_mergejoin=f;
+ select * from numrange_test natural join numrange_test2 order by nr;
+ set enable_nestloop=f;
+ set enable_hashjoin=t;
+ set enable_mergejoin=f;
+ select * from numrange_test natural join numrange_test2 order by nr;
+ set enable_nestloop=f;
+ set enable_hashjoin=f;
+ set enable_mergejoin=t;
+ select * from numrange_test natural join numrange_test2 order by nr;
+
+ set enable_nestloop to default;
+ set enable_hashjoin to default;
+ set enable_mergejoin to default;
+ SET enable_seqscan TO DEFAULT;
+ DROP TABLE numrange_test;
+ DROP TABLE numrange_test2;
+
+ -- test canonical form for int4range
+ select range__(1,10);
+ select rangei_(1,10);
+ select range_i(1,10);
+ select rangeii(1,10);
+
+ -- test canonical form for daterange
+ select range__('2000-01-10'::date, '2000-01-20'::date);
+ select rangei_('2000-01-10'::date, '2000-01-20'::date);
+ select range_i('2000-01-10'::date, '2000-01-20'::date);
+ select rangeii('2000-01-10'::date, '2000-01-20'::date);
+
+ -- test length()
+ select length(range(10.1,100.1));
+ select length('[2000-01-01 01:00:00, 2000-01-05 03:00:00)'::tsrange);
+ select length('[2000-01-01 01:00:00, 2000-01-01 03:00:00)'::tstzrange);
+ select length('[2000-01-01, 2000-01-05)'::daterange);
+
+ create table test_range_gist(ir int4range);
+ create index test_range_gist_idx on test_range_gist using gist (ir);
+
+ insert into test_range_gist select range(g, g+10) from generate_series(1,2000) g;
+ insert into test_range_gist select '-'::int4range from generate_series(1,500) g;
+ insert into test_range_gist select range(g, g+10000) from generate_series(1,1000) g;
+ insert into test_range_gist select '-'::int4range from generate_series(1,500) g;
+ insert into test_range_gist select range_linfi(g*10) from generate_series(1,100) g;
+ insert into test_range_gist select range_uinf_(g*10) from generate_series(1,100) g;
+ insert into test_range_gist select range(g, g+10) from generate_series(1,2000) g;
+
+ BEGIN;
+ SET LOCAL enable_seqscan = t;
+ SET LOCAL enable_bitmapscan = f;
+ SET LOCAL enable_indexscan = f;
+
+ select count(*) from test_range_gist where ir @> '-'::int4range;
+ select count(*) from test_range_gist where ir = range(10,20);
+ select count(*) from test_range_gist where ir @> 10;
+ select count(*) from test_range_gist where ir @> range(10,20);
+ select count(*) from test_range_gist where ir && range(10,20);
+ select count(*) from test_range_gist where ir <@ range(10,50);
+ select count(*) from (select * from test_range_gist where ir?) s where ir << range(100,500);
+ select count(*) from (select * from test_range_gist where ir?) s where ir >> range(100,500);
+ select count(*) from (select * from test_range_gist where ir?) s where ir &< range(100,500);
+ select count(*) from (select * from test_range_gist where ir?) s where ir &> range(100,500);
+ select count(*) from (select * from test_range_gist where ir?) s where ir -|- range(100,500);
+ COMMIT;
+
+ BEGIN;
+ SET LOCAL enable_seqscan = f;
+ SET LOCAL enable_bitmapscan = f;
+ SET LOCAL enable_indexscan = t;
+
+ select count(*) from test_range_gist where ir @> '-'::int4range;
+ select count(*) from test_range_gist where ir = range(10,20);
+ select count(*) from test_range_gist where ir @> 10;
+ select count(*) from test_range_gist where ir @> range(10,20);
+ select count(*) from test_range_gist where ir && range(10,20);
+ select count(*) from test_range_gist where ir <@ range(10,50);
+ select count(*) from test_range_gist where ir << range(100,500);
+ select count(*) from test_range_gist where ir >> range(100,500);
+ select count(*) from test_range_gist where ir &< range(100,500);
+ select count(*) from test_range_gist where ir &> range(100,500);
+ select count(*) from test_range_gist where ir -|- range(100,500);
+ COMMIT;
+
+ drop index test_range_gist_idx;
+ create index test_range_gist_idx on test_range_gist using gist (ir);
+
+ BEGIN;
+ SET LOCAL enable_seqscan = f;
+ SET LOCAL enable_bitmapscan = f;
+ SET LOCAL enable_indexscan = t;
+
+ select count(*) from test_range_gist where ir @> '-'::int4range;
+ select count(*) from test_range_gist where ir = range(10,20);
+ select count(*) from test_range_gist where ir @> 10;
+ select count(*) from test_range_gist where ir @> range(10,20);
+ select count(*) from test_range_gist where ir && range(10,20);
+ select count(*) from test_range_gist where ir <@ range(10,50);
+ select count(*) from test_range_gist where ir << range(100,500);
+ select count(*) from test_range_gist where ir >> range(100,500);
+ select count(*) from test_range_gist where ir &< range(100,500);
+ select count(*) from test_range_gist where ir &> range(100,500);
+ select count(*) from test_range_gist where ir -|- range(100,500);
+ COMMIT;
+
+ drop table test_range_gist;
+
+ --
+ -- Btree_gist is not included by default, so to test exclusion
+ -- constraints with range types, use singleton int ranges for the "="
+ -- portion of the constraint.
+ --
+
+ create table test_range_excl(
+ room int4range,
+ speaker int4range,
+ during tsrange,
+ exclude using gist (room with =, during with &&),
+ exclude using gist (speaker with =, during with &&)
+ );
+
+ insert into test_range_excl
+ values(range(123), range(1), '[2010-01-02 10:00, 2010-01-02 11:00)');
+ insert into test_range_excl
+ values(range(123), range(2), '[2010-01-02 11:00, 2010-01-02 12:00)');
+ insert into test_range_excl
+ values(range(123), range(3), '[2010-01-02 10:10, 2010-01-02 11:10)');
+ insert into test_range_excl
+ values(range(124), range(3), '[2010-01-02 10:10, 2010-01-02 11:10)');
+ insert into test_range_excl
+ values(range(125), range(1), '[2010-01-02 10:10, 2010-01-02 11:10)');
+
+ drop table test_range_excl;
+
+ -- test bigint ranges
+ select range_i(10000000000::int8, 20000000000::int8);
+ -- test tstz ranges
+ set timezone to '-08';
+ select '[2010-01-01 01:00:00 -05, 2010-01-01 02:00:00 -08)'::tstzrange;
+ -- should fail
+ select '[2010-01-01 01:00:00 -08, 2010-01-01 02:00:00 -05)'::tstzrange;
+ set timezone to default;
*** a/src/test/regress/sql/type_sanity.sql
--- b/src/test/regress/sql/type_sanity.sql
***************
*** 20,26 **** SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typnamespace = 0 OR
(p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
! (p1.typtype not in ('b', 'c', 'd', 'e', 'p')) OR
NOT p1.typisdefined OR
(p1.typalign not in ('c', 's', 'i', 'd')) OR
(p1.typstorage not in ('p', 'x', 'e', 'm'));
--- 20,26 ----
FROM pg_type as p1
WHERE p1.typnamespace = 0 OR
(p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
! (p1.typtype not in ('b', 'c', 'd', 'e', 'p', 'r')) OR
NOT p1.typisdefined OR
(p1.typalign not in ('c', 's', 'i', 'd')) OR
(p1.typstorage not in ('p', 'x', 'e', 'm'));