Further review of range-types patch.
Lots of documentation cleanup today, and still more type_sanity tests.
This commit is contained in:
parent
c1458cc495
commit
a1a233af66
|
@ -4607,7 +4607,9 @@
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The catalog <structname>pg_range</structname> stores information about range types.
|
The catalog <structname>pg_range</structname> stores information about
|
||||||
|
range types. This is in addition to the types' entries in
|
||||||
|
<link linkend="catalog-pg-type"><structname>pg_type</structname></link>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
@ -4628,47 +4630,57 @@
|
||||||
<entry><structfield>rngtypid</structfield></entry>
|
<entry><structfield>rngtypid</structfield></entry>
|
||||||
<entry><type>oid</type></entry>
|
<entry><type>oid</type></entry>
|
||||||
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
|
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
|
||||||
<entry>The type that is a range type</entry>
|
<entry>OID of the range type</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>rngsubtype</structfield></entry>
|
<entry><structfield>rngsubtype</structfield></entry>
|
||||||
<entry><type>oid</type></entry>
|
<entry><type>oid</type></entry>
|
||||||
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
|
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
|
||||||
<entry>Subtype of this range type, e.g. <type>integer</type> is the subtype of <type>int4range</type></entry>
|
<entry>OID of the element type (subtype) of this range type</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>rngcollation</structfield></entry>
|
<entry><structfield>rngcollation</structfield></entry>
|
||||||
<entry><type>oid</type></entry>
|
<entry><type>oid</type></entry>
|
||||||
<entry><literal><link linkend="catalog-pg-collation"><structname>pg_collation</structname></link>.oid</literal></entry>
|
<entry><literal><link linkend="catalog-pg-collation"><structname>pg_collation</structname></link>.oid</literal></entry>
|
||||||
<entry>The collation used when comparing range boundaries</entry>
|
<entry>OID of the collation used for range comparisons, or 0 if none</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>rngsubopc</structfield></entry>
|
<entry><structfield>rngsubopc</structfield></entry>
|
||||||
<entry><type>oid</type></entry>
|
<entry><type>oid</type></entry>
|
||||||
<entry><literal><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>.oid</literal></entry>
|
<entry><literal><link linkend="catalog-pg-opclass"><structname>pg_opclass</structname></link>.oid</literal></entry>
|
||||||
<entry>The operator class used when comparing range boundaries</entry>
|
<entry>OID of the subtype's operator class used for range comparisons</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>rngcanonical</structfield></entry>
|
<entry><structfield>rngcanonical</structfield></entry>
|
||||||
<entry><type>regproc</type></entry>
|
<entry><type>regproc</type></entry>
|
||||||
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
|
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
|
||||||
<entry>A function to convert a range into its canonical form</entry>
|
<entry>OID of the function to convert a range value into canonical form,
|
||||||
|
or 0 if none</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>rngsubdiff</structfield></entry>
|
<entry><structfield>rngsubdiff</structfield></entry>
|
||||||
<entry><type>regproc</type></entry>
|
<entry><type>regproc</type></entry>
|
||||||
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
|
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
|
||||||
<entry>A function to return the distance between two lower and upper bound, as a <type>double precision</type>. Used for GiST support</entry>
|
<entry>OID of the function to return the difference between two element
|
||||||
|
values as <type>double precision</type>, or 0 if none</entry>
|
||||||
</row>
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<structfield>rngsubopc</> (plus <structfield>rngcollation</>, if the
|
||||||
|
element type is collatable) determines the sort ordering used by the range
|
||||||
|
type. <structfield>rngcanonical</> is used when the element type is
|
||||||
|
discrete. <structfield>rngsubdiff</> is optional but should be supplied to
|
||||||
|
improve performance of GiST indexes on the range type.
|
||||||
|
</para>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="catalog-pg-rewrite">
|
<sect1 id="catalog-pg-rewrite">
|
||||||
|
@ -6059,7 +6071,8 @@
|
||||||
<literal>c</literal> for a composite type (e.g., a table's row type),
|
<literal>c</literal> for a composite type (e.g., a table's row type),
|
||||||
<literal>d</literal> for a domain,
|
<literal>d</literal> for a domain,
|
||||||
<literal>e</literal> for an enum type,
|
<literal>e</literal> for an enum type,
|
||||||
or <literal>p</literal> for a pseudo-type.
|
<literal>p</literal> for a pseudo-type, or
|
||||||
|
<literal>r</literal> for a range type.
|
||||||
See also <structfield>typrelid</structfield> and
|
See also <structfield>typrelid</structfield> and
|
||||||
<structfield>typbasetype</structfield>.
|
<structfield>typbasetype</structfield>.
|
||||||
</entry>
|
</entry>
|
||||||
|
@ -6429,6 +6442,10 @@
|
||||||
<entry><literal>P</literal></entry>
|
<entry><literal>P</literal></entry>
|
||||||
<entry>Pseudo-types</entry>
|
<entry>Pseudo-types</entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><literal>R</literal></entry>
|
||||||
|
<entry>Range types</entry>
|
||||||
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry><literal>S</literal></entry>
|
<entry><literal>S</literal></entry>
|
||||||
<entry>String types</entry>
|
<entry>String types</entry>
|
||||||
|
|
|
@ -200,13 +200,13 @@
|
||||||
<para>
|
<para>
|
||||||
Five pseudo-types of special interest are <type>anyelement</>,
|
Five pseudo-types of special interest are <type>anyelement</>,
|
||||||
<type>anyarray</>, <type>anynonarray</>, <type>anyenum</>,
|
<type>anyarray</>, <type>anynonarray</>, <type>anyenum</>,
|
||||||
and <type>anyrange</>, which are collectively
|
and <type>anyrange</>,
|
||||||
called <firstterm>polymorphic types</>. Any function declared
|
which are collectively called <firstterm>polymorphic types</>.
|
||||||
using these types is said to be a <firstterm>polymorphic
|
Any function declared using these types is said to be
|
||||||
function</>. A polymorphic function can operate on many
|
a <firstterm>polymorphic function</>. A polymorphic function can
|
||||||
different data types, with the specific data type(s) being
|
operate on many different data types, with the specific data type(s)
|
||||||
determined by the data types actually passed to it in a
|
being determined by the data types actually passed to it in a particular
|
||||||
particular call.
|
call.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -217,15 +217,16 @@
|
||||||
data type, but in any given call they must all be the
|
data type, but in any given call they must all be the
|
||||||
<emphasis>same</emphasis> actual type. Each
|
<emphasis>same</emphasis> actual type. Each
|
||||||
position declared as <type>anyarray</type> can have any array data type,
|
position declared as <type>anyarray</type> can have any array data type,
|
||||||
but similarly they must all be the same type. If there are
|
but similarly they must all be the same type. And similarly,
|
||||||
|
positions declared as <type>anyrange</type> must all be the same range
|
||||||
|
type. Furthermore, if there are
|
||||||
positions declared <type>anyarray</type> and others declared
|
positions declared <type>anyarray</type> and others declared
|
||||||
<type>anyelement</type>, the actual array type in the
|
<type>anyelement</type>, the actual array type in the
|
||||||
<type>anyarray</type> positions must be an array whose elements are
|
<type>anyarray</type> positions must be an array whose elements are
|
||||||
the same type appearing in the <type>anyelement</type> positions.
|
the same type appearing in the <type>anyelement</type> positions.
|
||||||
Similarly, if there are positions declared <type>anyrange</type>
|
Similarly, if there are positions declared <type>anyrange</type>
|
||||||
and others declared
|
and others declared <type>anyelement</type>, the actual range type in
|
||||||
<type>anyelement</type>, the actual range type in the
|
the <type>anyrange</type> positions must be a range whose subtype is
|
||||||
<type>anyrange</type> positions must be a range whose subtype is
|
|
||||||
the same type appearing in the <type>anyelement</type> positions.
|
the same type appearing in the <type>anyelement</type> positions.
|
||||||
<type>anynonarray</> is treated exactly the same as <type>anyelement</>,
|
<type>anynonarray</> is treated exactly the same as <type>anyelement</>,
|
||||||
but adds the additional constraint that the actual type must not be
|
but adds the additional constraint that the actual type must not be
|
||||||
|
|
|
@ -10525,18 +10525,32 @@ SELECT NULLIF(value, '(none)') ...
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry> <literal>@></literal> </entry>
|
<entry> <literal>@></literal> </entry>
|
||||||
<entry>contains</entry>
|
<entry>contains range</entry>
|
||||||
|
<entry><literal>int4range(2,4) @> int4range(2,3)</literal></entry>
|
||||||
|
<entry><literal>t</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry> <literal>@></literal> </entry>
|
||||||
|
<entry>contains element</entry>
|
||||||
<entry><literal>'[2011-01-01,2011-03-01)'::tsrange @> '2011-01-10'::timestamp</literal></entry>
|
<entry><literal>'[2011-01-01,2011-03-01)'::tsrange @> '2011-01-10'::timestamp</literal></entry>
|
||||||
<entry><literal>t</literal></entry>
|
<entry><literal>t</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry> <literal><@</literal> </entry>
|
<entry> <literal><@</literal> </entry>
|
||||||
<entry>is contained by</entry>
|
<entry>range is contained by</entry>
|
||||||
<entry><literal>int4range(2,4) <@ int4range(1,7)</literal></entry>
|
<entry><literal>int4range(2,4) <@ int4range(1,7)</literal></entry>
|
||||||
<entry><literal>t</literal></entry>
|
<entry><literal>t</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry> <literal><@</literal> </entry>
|
||||||
|
<entry>element is contained by</entry>
|
||||||
|
<entry><literal>42 <@ int4range(1,7)</literal></entry>
|
||||||
|
<entry><literal>f</literal></entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry> <literal>&&</literal> </entry>
|
<entry> <literal>&&</literal> </entry>
|
||||||
<entry>overlap (have points in common)</entry>
|
<entry>overlap (have points in common)</entry>
|
||||||
|
|
|
@ -8,137 +8,166 @@
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Range types are data types representing a range of values over some
|
Range types are data types representing a range of values of some
|
||||||
sub-type with a total order. For instance, ranges
|
element type (called the range's <firstterm>subtype</>).
|
||||||
|
For instance, ranges
|
||||||
of <type>timestamp</type> might be used to represent the ranges of
|
of <type>timestamp</type> might be used to represent the ranges of
|
||||||
time that a meeting room is reserved. In this case the data type
|
time that a meeting room is reserved. In this case the data type
|
||||||
is <type>tsrange</type> (short for "timestamp range"),
|
is <type>tsrange</type> (short for <quote>timestamp range</quote>),
|
||||||
and <type>timestamp</type> is the sub-type with a total order.
|
and <type>timestamp</type> is the subtype. The subtype must have
|
||||||
|
a total order so that it is well-defined whether element values are
|
||||||
|
within, before, or after a range of values.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Range types are useful because they represent many points in a
|
Range types are useful because they represent many element values in a
|
||||||
single value. The use of time and date ranges for scheduling
|
single range value, and because concepts such as overlapping ranges can
|
||||||
|
be expressed clearly. The use of time and date ranges for scheduling
|
||||||
purposes is the clearest example; but price ranges, measurement
|
purposes is the clearest example; but price ranges, measurement
|
||||||
ranges from an instrument, etc., are also useful.
|
ranges from an instrument, and so forth can also be useful.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<sect2 id="rangetypes-builtin">
|
<sect2 id="rangetypes-builtin">
|
||||||
<title>Built-in Range Types</title>
|
<title>Built-in Range Types</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
PostgreSQL comes with the following built-in range types:
|
PostgreSQL comes with the following built-in range types:
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<type>INT4RANGE</type> -- Range of <type>INTEGER</type>. This is a discrete range type, see <xref linkend="rangetypes-discrete">.
|
<type>INT4RANGE</type> — Range of <type>INTEGER</type>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<type>INT8RANGE</type> -- Range of <type>BIGINT</type>. This is a discrete range type, see <xref linkend="rangetypes-discrete">.
|
<type>INT8RANGE</type> — Range of <type>BIGINT</type>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<type>NUMRANGE</type> -- Range of <type>NUMERIC</type>.
|
<type>NUMRANGE</type> — Range of <type>NUMERIC</type>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<type>TSRANGE</type> -- Range of <type>TIMESTAMP WITHOUT TIME ZONE</type>.
|
<type>TSRANGE</type> — Range of <type>TIMESTAMP WITHOUT TIME ZONE</type>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<type>TSTZRANGE</type> -- Range of <type>TIMESTAMP WITH TIME ZONE</type>.
|
<type>TSTZRANGE</type> — Range of <type>TIMESTAMP WITH TIME ZONE</type>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<type>DATERANGE</type> -- Range of <type>DATE</type>. This is a discrete range type, see <xref linkend="rangetypes-discrete">.
|
<type>DATERANGE</type> — Range of <type>DATE</type>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
In addition, you can define your own; see <xref linkend="SQL-CREATETYPE"> for more information.
|
In addition, you can define your own range types;
|
||||||
|
see <xref linkend="SQL-CREATETYPE"> for more information.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="rangetypes-examples">
|
<sect2 id="rangetypes-examples">
|
||||||
<title>Examples</title>
|
<title>Examples</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE TABLE reservation ( during TSRANGE );
|
CREATE TABLE reservation ( room int, during TSRANGE );
|
||||||
INSERT INTO reservation VALUES
|
INSERT INTO reservation VALUES
|
||||||
( '[2010-01-01 14:30, 2010-01-01 15:30)' );
|
( 1108, '[2010-01-01 14:30, 2010-01-01 15:30)' );
|
||||||
|
|
||||||
-- Containment
|
-- Containment
|
||||||
SELECT int4range(10, 20) @> 3;
|
SELECT int4range(10, 20) @> 3;
|
||||||
|
|
||||||
-- Overlaps
|
-- Overlaps
|
||||||
SELECT numrange(11.1, 22.2) && numrange(20.0, 30.0);
|
SELECT numrange(11.1, 22.2) && numrange(20.0, 30.0);
|
||||||
|
|
||||||
-- Find the upper bound:
|
-- Extract the upper bound
|
||||||
SELECT upper(int8range(15, 25));
|
SELECT upper(int8range(15, 25));
|
||||||
|
|
||||||
-- Compute the intersection:
|
-- Compute the intersection
|
||||||
SELECT int4range(10, 20) * int4range(15, 25);
|
SELECT int4range(10, 20) * int4range(15, 25);
|
||||||
|
|
||||||
-- Is the range non-empty?
|
-- Is the range non-empty?
|
||||||
SELECT isempty(numrange(1, 5));
|
SELECT isempty(numrange(1, 5));
|
||||||
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
See <xref linkend="range-functions-table">
|
See <xref linkend="range-functions-table">
|
||||||
and <xref linkend="range-operators-table"> for complete lists of
|
and <xref linkend="range-operators-table"> for complete lists of
|
||||||
functions and operators on range types.
|
functions and operators on range types.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="rangetypes-inclusivity">
|
<sect2 id="rangetypes-inclusivity">
|
||||||
<title>Inclusive and Exclusive Bounds</title>
|
<title>Inclusive and Exclusive Bounds</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Every range has two bounds, the lower bound and the upper bound. All
|
Every non-empty range has two bounds, the lower bound and the upper
|
||||||
points in between those values are included in the range. An
|
bound. All points between these values are included in the range. An
|
||||||
inclusive bound means that the boundary point itself is included in
|
inclusive bound means that the boundary point itself is included in
|
||||||
the range as well, while an exclusive bound means that the boundary
|
the range as well, while an exclusive bound means that the boundary
|
||||||
point is not included in the range.
|
point is not included in the range.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
An inclusive lower bound is represented by <literal>[</literal>
|
In the text form of a range, an inclusive lower bound is represented by
|
||||||
while an exclusive lower bound is represented
|
<quote><literal>[</literal></quote> while an exclusive lower bound is
|
||||||
by <literal>(</literal> (see <xref linkend="rangetypes-construct">
|
represented by <quote><literal>(</literal></quote>. Likewise, an inclusive upper bound is represented by
|
||||||
and <xref linkend="rangetypes-io"> below). Likewise, an inclusive
|
<quote><literal>]</literal></quote>, while an exclusive upper bound is
|
||||||
upper bound is represented by <literal>]</literal>, while an
|
represented by <quote><literal>)</literal></quote>.
|
||||||
exclusive upper bound is represented by <literal>)</literal>.
|
(See <xref linkend="rangetypes-io"> for more details.)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Functions <literal>lower_inc</literal>
|
The functions <literal>lower_inc</literal>
|
||||||
and <literal>upper_inc</literal> test the inclusivity of the lower
|
and <literal>upper_inc</literal> test the inclusivity of the lower
|
||||||
and upper bounds of a range, respectively.
|
and upper bounds of a range value, respectively.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="rangetypes-infinite">
|
<sect2 id="rangetypes-infinite">
|
||||||
<title>Infinite (unbounded) Ranges</title>
|
<title>Infinite (Unbounded) Ranges</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The lower bound of a range can be omitted, meaning that all points
|
The lower bound of a range can be omitted, meaning that all points less
|
||||||
less (or equal to, if inclusive) than the upper bound are included
|
than the upper bound are included in the range. Likewise, if the upper
|
||||||
in the range. Likewise, if the upper bound of the range is omitted,
|
bound of the range is omitted, then all points greater than the lower bound
|
||||||
then all points greater than (or equal to, if omitted) the lower
|
are included in the range. If both lower and upper bounds are omitted, all
|
||||||
bound are included in the range. If both lower and upper bounds are
|
values of the element type are considered to be in the range.
|
||||||
omitted, all points are considered to be in the range.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Functions <literal>lower_inf</literal>
|
This is equivalent to considering that the lower bound is <quote>minus
|
||||||
and <literal>upper_inf</literal> test the range for infinite lower
|
infinity</quote>, or the upper bound is <quote>plus infinity</quote>,
|
||||||
and upper bounds of a range, respectively.
|
respectively. But note that these infinite values are never values of
|
||||||
|
the range's element type, and can never be part of the range. (So there
|
||||||
|
is no such thing as an inclusive infinite bound — if you try to
|
||||||
|
write one, it will automatically be converted to an exclusive bound.)
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Also, some element types have a notion of <quote>infinity</>, but that
|
||||||
|
is just another value so far as the range type mechanisms are concerned.
|
||||||
|
For example, in timestamp ranges, <literal>[today,]</> means the same
|
||||||
|
thing as <literal>[today,)</>. But <literal>[today,infinity]</> means
|
||||||
|
something different from <literal>[today,infinity)</> — the latter
|
||||||
|
excludes the special <type>timestamp</> value <literal>infinity</>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The functions <literal>lower_inf</literal>
|
||||||
|
and <literal>upper_inf</literal> test for infinite lower
|
||||||
|
and upper bounds of a range, respectively.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="rangetypes-io">
|
<sect2 id="rangetypes-io">
|
||||||
<title>Input/Output</title>
|
<title>Range Input/Output</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The input follows one of the following patterns:
|
The input for a range value must follow one of the following patterns:
|
||||||
<synopsis>
|
<synopsis>
|
||||||
(<replaceable>lower-bound</replaceable>,<replaceable>upper-bound</replaceable>)
|
(<replaceable>lower-bound</replaceable>,<replaceable>upper-bound</replaceable>)
|
||||||
(<replaceable>lower-bound</replaceable>,<replaceable>upper-bound</replaceable>]
|
(<replaceable>lower-bound</replaceable>,<replaceable>upper-bound</replaceable>]
|
||||||
|
@ -146,127 +175,173 @@ SELECT isempty(numrange(1, 5));
|
||||||
[<replaceable>lower-bound</replaceable>,<replaceable>upper-bound</replaceable>]
|
[<replaceable>lower-bound</replaceable>,<replaceable>upper-bound</replaceable>]
|
||||||
empty
|
empty
|
||||||
</synopsis>
|
</synopsis>
|
||||||
Notice that the final pattern is <literal>empty</literal>, which
|
The parentheses or brackets indicate whether the lower and upper bounds
|
||||||
represents an empty range (a range that contains no points).
|
are exclusive or inclusive, as described previously.
|
||||||
|
Notice that the final pattern is <literal>empty</literal>, which
|
||||||
|
represents an empty range (a range that contains no points).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <replaceable>lower-bound</replaceable> may be either a string
|
The <replaceable>lower-bound</replaceable> may be either a string
|
||||||
that is valid input for the sub-type, or omitted (to indicate no
|
that is valid input for the subtype, or empty to indicate no
|
||||||
lower bound); and <replaceable>upper-bound</replaceable> may be
|
lower bound. Likewise, <replaceable>upper-bound</replaceable> may be
|
||||||
either a string that is valid input for the sub-type, or omitted (to
|
either a string that is valid input for the subtype, or empty to
|
||||||
indicate no upper bound).
|
indicate no upper bound.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Either the <replaceable>lower-bound</replaceable> or
|
Each bound value can be quoted using <literal>"</literal> (double quote)
|
||||||
the <replaceable>upper-bound</replaceable> may be quoted
|
characters. This is necessary if the bound value contains parentheses,
|
||||||
using <literal>""</literal> (double quotation marks), which will allow
|
brackets, commas, double quotes, or backslashes, since these characters
|
||||||
special characters such as "<literal>,</literal>". Within quotation
|
would otherwise be taken as part of the range syntax. To put a double
|
||||||
marks, "<literal>\</literal>" (backslash) serves as an escape
|
quote or backslash in a quoted bound value, precede it with a
|
||||||
character.
|
backslash. (Also, a pair of double quotes within a double-quoted bound
|
||||||
|
value is taken to represent a double quote character, analogously to the
|
||||||
|
rules for single quotes in SQL literal strings.) Alternatively, you can
|
||||||
|
avoid quoting and use backslash-escaping to protect all data characters
|
||||||
|
that would otherwise be taken as range syntax. Also, to write a bound
|
||||||
|
value that is an empty string, write <literal>""</literal>, since writing
|
||||||
|
nothing means an infinite bound.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The choice between the other input formats affects the inclusivity
|
Whitespace is allowed before and after the range value, but any whitespace
|
||||||
of the bounds. See <xref linkend="rangetypes-inclusivity">.
|
between the parentheses or brackets is taken as part of the lower or upper
|
||||||
|
bound value. (Depending on the element type, it might or might not be
|
||||||
|
significant.)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
These rules are very similar to those for writing field values in
|
||||||
|
composite-type literals. See <xref linkend="rowtypes-io-syntax"> for
|
||||||
|
additional commentary.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Examples:
|
Examples:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
-- includes point 3, does not include point 7, and does include all points in between
|
-- includes 3, does not include 7, and does include all points in between
|
||||||
select '[3,7)'
|
select '[3,7)'::int4range;
|
||||||
|
|
||||||
-- does not include either 3 or 7, but includes all points in between
|
-- does not include either 3 or 7, but includes all points in between
|
||||||
select '(3,7)'
|
select '(3,7)'::int4range;
|
||||||
|
|
||||||
-- includes only the single point 4
|
-- includes only the single point 4
|
||||||
select '[4,4]'
|
select '[4,4]'::int4range;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="rangetypes-construct">
|
<sect2 id="rangetypes-construct">
|
||||||
<title>Constructing Ranges</title>
|
<title>Constructing Ranges</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Each range type has a constructor by the same name. The constructor
|
Each range type has a constructor function with the same name as the range
|
||||||
|
type. Using the constructor function is frequently more convenient than
|
||||||
|
writing a range literal constant, since it avoids the need for extra
|
||||||
|
quoting of the bound values. The constructor function
|
||||||
accepts from zero to three arguments. The zero-argument form
|
accepts from zero to three arguments. The zero-argument form
|
||||||
constructs an empty range; the one-argument form constructs a
|
constructs an empty range; the one-argument form constructs a
|
||||||
singleton range; the two-argument form constructs a range
|
singleton range; the two-argument form constructs a range in
|
||||||
in <literal>[ )</literal> form; and the three-argument form
|
standard form (lower bound inclusive, upper bound exclusive);
|
||||||
constructs a range in a form specified by the third argument. For
|
and the three-argument form constructs a range in a form specified by the
|
||||||
example:
|
third argument. The third argument must be one of the strings
|
||||||
|
<quote><literal>()</literal></quote>,
|
||||||
|
<quote><literal>(]</literal></quote>,
|
||||||
|
<quote><literal>[)</literal></quote>, or
|
||||||
|
<quote><literal>[]</literal></quote>.
|
||||||
|
For example:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
-- Three-argument form: lower bound, upper bound, and third argument indicating
|
-- Three-argument form: lower bound, upper bound, and third argument indicating
|
||||||
-- inclusivity/exclusivity of bounds (if omitted, defaults to <literal>'[)'</literal>).
|
-- inclusivity/exclusivity of bounds.
|
||||||
SELECT numrange(1.0, 14.0, '(]');
|
SELECT numrange(1.0, 14.0, '(]');
|
||||||
|
|
||||||
-- The int4range input will exclude the lower bound and include the upper bound; but the
|
-- If the third argument is omitted, '[)' is assumed.
|
||||||
-- resulting output will appear in the canonical form; see <xref linkend="rangetypes-discrete">.
|
SELECT numrange(1.0, 14.0);
|
||||||
|
|
||||||
|
-- Although '(]' is specified here, on display the value will be converted to
|
||||||
|
-- canonical form, since int8range is a discrete range type (see below).
|
||||||
SELECT int8range(1, 14, '(]');
|
SELECT int8range(1, 14, '(]');
|
||||||
|
|
||||||
-- Single argument form constructs a singleton range; that is a range consisting of just
|
-- Using NULL for either bound causes the range to be unbounded on that side.
|
||||||
-- one point.
|
SELECT numrange(NULL, 2.2);
|
||||||
|
|
||||||
|
-- Single argument constructs a singleton range; that is a range consisting of
|
||||||
|
-- just one point.
|
||||||
SELECT numrange(11.1);
|
SELECT numrange(11.1);
|
||||||
|
|
||||||
-- Zero-argument form constructs and empty range.
|
-- Zero-argument form constructs an empty range.
|
||||||
SELECT numrange();
|
SELECT numrange();
|
||||||
|
|
||||||
-- Using NULL for a bound causes the range to be unbounded on that side; that is, negative
|
|
||||||
-- infinity for the lower bound or positive infinity for the upper bound.
|
|
||||||
SELECT numrange(NULL,2.2);
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="rangetypes-discrete">
|
<sect2 id="rangetypes-discrete">
|
||||||
<title>Discrete Range Types</title>
|
<title>Discrete Range Types</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Discrete ranges are those that have a
|
A discrete range is one whose element type has a well-defined
|
||||||
defined <literal>canonical</literal> function. Loosely speaking, a
|
<quote>step</quote>, such as <type>INTEGER</type> or <type>DATE</type>.
|
||||||
discrete range has a sub-type with a well-defined "step";
|
In these types two elements can be said to be adjacent, since there are
|
||||||
e.g. <type>INTEGER</type> or <type>DATE</type>.
|
no valid values between them. This contrasts with continuous ranges,
|
||||||
|
where it's always (or almost always) possible to identify other element
|
||||||
|
values between two given values. For example, a range over the
|
||||||
|
<type>NUMERIC</> type is continuous, as is a range over <type>TIMESTAMP</>.
|
||||||
|
(Even though <type>TIMESTAMP</> has limited precision, and so could
|
||||||
|
theoretically be treated as discrete, it's better to consider it continuous
|
||||||
|
since the step size is normally not of interest.)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <literal>canonical</literal> function should take an input range
|
Another way to think about a discrete range type is that there is a clear
|
||||||
value, and return an equal range value that may have a different
|
idea of a <quote>next</> or <quote>previous</> value for each element value.
|
||||||
formatting. For instance, the integer range <literal>[1,
|
Knowing that, it is possible to convert between inclusive and exclusive
|
||||||
7]</literal> could be represented by the equal integer
|
representations of a range's bounds, by choosing the next or previous
|
||||||
range <literal>[1, 8)</literal>. The two values are equal because
|
element value instead of the one originally given.
|
||||||
there are no points within the integer domain
|
For example, in an integer range type <literal>[4,8]</> and
|
||||||
between <literal>7</literal> and <literal>8</literal>, so not
|
<literal>(3,9)</> denote the same set of values; but this would not be so
|
||||||
including the end point <literal>8</literal> is the same as
|
for a range over numeric.
|
||||||
including the end point <literal>7</literal>. The canonical output
|
|
||||||
for two values that are equal, like <literal>[1, 7]</literal>
|
|
||||||
and <literal>[1, 8)</literal>, must be equal. It doesn't matter
|
|
||||||
which representation you choose to be the canonical one, as long as
|
|
||||||
two equal values with different formattings are always mapped to the
|
|
||||||
same value with the same formatting. If the canonical function is
|
|
||||||
not specified, then ranges with different formatting
|
|
||||||
(e.g. <literal>[1, 7]</literal> and <literal>[1, 8)</literal>) will
|
|
||||||
always be treated as unequal.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
For types such as <type>NUMRANGE</type>, this is not possible,
|
A discrete range type should have a <firstterm>canonicalization</>
|
||||||
because there are always points in between two
|
function that is aware of the desired step size for the element type.
|
||||||
distinct <type>NUMERIC</type> values.
|
The canonicalization function is charged with converting values of the
|
||||||
|
range type to have consistently inclusive or exclusive bounds.
|
||||||
|
The canonicalization function takes an input range value, and
|
||||||
|
must return an equivalent range value that may have a different
|
||||||
|
formatting. The canonical output for two values that are equivalent, like
|
||||||
|
<literal>[1, 7]</literal> and <literal>[1, 8)</literal>, must be identical.
|
||||||
|
It doesn't matter which representation you choose to be the canonical one,
|
||||||
|
so long as two equivalent values with different formattings are always
|
||||||
|
mapped to the same value with the same formatting. If a canonicalization
|
||||||
|
function is not specified, then ranges with different formatting
|
||||||
|
will always be treated as unequal, even though they might represent the
|
||||||
|
same set of values.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The built-in range
|
The built-in range types <type>INT4RANGE</type>, <type>INT8RANGE</type>,
|
||||||
types <type>INT4RANGE</type>, <type>INT8RANGE</type>,
|
and <type>DATERANGE</type> all use a canonical form that includes
|
||||||
and <type>DATERNAGE</type> all use a canonical form that includes
|
the lower bound and excludes the upper bound; that is,
|
||||||
the lower bound and excludes the upper bound; that is, <literal>[
|
<literal>[)</literal>. User-defined range types can use other conventions,
|
||||||
)</literal>. User-defined ranges can use other conventions, however.
|
however.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="rangetypes-defining">
|
<sect2 id="rangetypes-defining">
|
||||||
<title>Defining New Range Types</title>
|
<title>Defining New Range Types</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Users can define their own range types. The most common reason to do
|
Users can define their own range types. The most common reason to do
|
||||||
this is to use ranges where the subtype is not among the built-in
|
this is to use ranges over subtypes not provided among the built-in
|
||||||
range types, e.g. a range of type <type>FLOAT</type> (or, if the
|
range types.
|
||||||
subtype itself is a user-defined type).
|
For example, to define a new range type of subtype <type>DOUBLE
|
||||||
</para>
|
PRECISION</type>:
|
||||||
<para>
|
|
||||||
For example: to define a new range type of sub-type <type>DOUBLE PRECISION</type>:
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE TYPE FLOATRANGE AS RANGE (
|
CREATE TYPE FLOATRANGE AS RANGE (
|
||||||
SUBTYPE = DOUBLE PRECISION
|
SUBTYPE = DOUBLE PRECISION
|
||||||
|
@ -274,99 +349,113 @@ CREATE TYPE FLOATRANGE AS RANGE (
|
||||||
|
|
||||||
SELECT '[1.234, 5.678]'::floatrange;
|
SELECT '[1.234, 5.678]'::floatrange;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
Because <type>DOUBLE PRECISION</type> has no meaningful "step", we
|
|
||||||
do not define a <literal>canonical</literal>
|
Because <type>DOUBLE PRECISION</type> has no meaningful
|
||||||
function. See <xref linkend="SQL-CREATETYPE"> for more
|
<quote>step</quote>, we do not define a canonicalization
|
||||||
information.
|
function.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Defining your own range type also allows you to specify a different
|
Defining your own range type also allows you to specify a different
|
||||||
operator class or collation to use (which affects the points that
|
operator class or collation to use, so as to change the sort ordering
|
||||||
fall between the range boundaries), or a different canonicalization
|
that determines which values fall into a given range. You might also
|
||||||
function.
|
choose to use a different canonicalization function, either to change
|
||||||
|
the displayed format or to modify the effective <quote>step size</>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
See <xref linkend="SQL-CREATETYPE"> for more information about creating
|
||||||
|
range types.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="rangetypes-gist">
|
<sect2 id="rangetypes-gist">
|
||||||
|
<title>Indexing</title>
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>range type</primary>
|
<primary>range type</primary>
|
||||||
<secondary>gist</secondary>
|
<secondary>GiST index</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
<title>Indexing</title>
|
|
||||||
<para>
|
<para>
|
||||||
GiST indexes can be applied to a table containing a range type. For instance:
|
GiST indexes can be applied to columns of range types. For instance:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE INDEX reservation_idx ON reservation USING gist (during);
|
CREATE INDEX reservation_idx ON reservation USING gist (during);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
This index may speed up queries
|
This index may speed up queries
|
||||||
involving <literal>&&</literal>
|
involving <literal>&&</literal>
|
||||||
(overlaps), <literal>@></literal> (contains), and all the boolean
|
(overlaps), <literal>@></literal> (contains), and other boolean
|
||||||
operators found in this
|
operators listed in <xref linkend="range-operators-table">.
|
||||||
table: <xref linkend="range-operators-table">.
|
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="rangetypes-constraint">
|
<sect2 id="rangetypes-constraint">
|
||||||
|
<title>Constraints on Ranges</title>
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>range type</primary>
|
<primary>range type</primary>
|
||||||
<secondary>exclude</secondary>
|
<secondary>exclude</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
<title>Constraints on Ranges</title>
|
|
||||||
<para>
|
<para>
|
||||||
While <literal>UNIQUE</literal> is a natural constraint for scalar
|
While <literal>UNIQUE</literal> is a natural constraint for scalar
|
||||||
values, it is usually unsuitable for range types. Instead, an
|
values, it is usually unsuitable for range types. Instead, an
|
||||||
exclusion constraint is often more appropriate
|
exclusion constraint is often more appropriate
|
||||||
(see <link linkend="SQL-CREATETABLE-EXCLUDE">CREATE TABLE
|
(see <link linkend="SQL-CREATETABLE-EXCLUDE">CREATE TABLE
|
||||||
... CONSTRAINT ... EXCLUDE</link>). Exclusion constraints allow the
|
... CONSTRAINT ... EXCLUDE</link>). Exclusion constraints allow the
|
||||||
specification of constraints such as "non-overlapping" on a range
|
specification of constraints such as <quote>non-overlapping</quote> on a
|
||||||
type. For example:
|
range type. For example:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
ALTER TABLE reservation
|
ALTER TABLE reservation
|
||||||
ADD EXCLUDE USING gist (during WITH &&);
|
ADD EXCLUDE USING gist (during WITH &&);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
That constraint will prevent any overlapping values from existing
|
That constraint will prevent any overlapping values from existing
|
||||||
in the table at the same time:
|
in the table at the same time:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
INSERT INTO reservation VALUES
|
INSERT INTO reservation VALUES
|
||||||
( '[2010-01-01 11:30, 2010-01-01 13:00)' );
|
( 1108, '[2010-01-01 11:30, 2010-01-01 13:00)' );
|
||||||
-- Result: INSERT 0 1
|
INSERT 0 1
|
||||||
INSERT INTO reservation VALUES
|
|
||||||
( '[2010-01-01 14:45, 2010-01-01 15:45)' );
|
INSERT INTO reservation VALUES
|
||||||
-- Result:
|
( 1108, '[2010-01-01 14:45, 2010-01-01 15:45)' );
|
||||||
-- ERROR: conflicting key value violates exclusion constraint "reservation_during_excl"
|
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
|
DETAIL: Key (during)=([ 2010-01-01 14:45:00, 2010-01-01 15:45:00 )) conflicts
|
||||||
-- existing key (during)=([ 2010-01-01 14:30:00, 2010-01-01 15:30:00 )).
|
with existing key (during)=([ 2010-01-01 14:30:00, 2010-01-01 15:30:00 )).
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
Combine range types and exclusion constraints
|
|
||||||
with <link linkend="btree-gist">btree_gist</link> for maximum
|
|
||||||
flexibility defining
|
|
||||||
constraints. After <literal>btree_gist</literal> is installed, the
|
|
||||||
following constraint will prevent overlapping ranges only if the
|
|
||||||
meeting room numbers are equal:
|
|
||||||
<programlisting>
|
|
||||||
|
|
||||||
|
<para>
|
||||||
|
You can use the <link linkend="btree-gist"><literal>btree_gist</></link>
|
||||||
|
extension to define exclusion constraints on plain scalar datatypes, which
|
||||||
|
can then be combined with range exclusions for maximum flexibility. For
|
||||||
|
example, after <literal>btree_gist</literal> is installed, the following
|
||||||
|
constraint will reject overlapping ranges only if the meeting room numbers
|
||||||
|
are equal:
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
CREATE TABLE room_reservation
|
CREATE TABLE room_reservation
|
||||||
(
|
(
|
||||||
room TEXT,
|
room TEXT,
|
||||||
during TSRANGE,
|
during TSRANGE,
|
||||||
EXCLUDE USING gist (room WITH =, during WITH &&)
|
EXCLUDE USING gist (room WITH =, during WITH &&)
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO room_reservation VALUES
|
INSERT INTO room_reservation VALUES
|
||||||
( '123A', '[2010-01-01 14:00, 2010-01-01 15:00)' );
|
( '123A', '[2010-01-01 14:00, 2010-01-01 15:00)' );
|
||||||
-- Result: INSERT 0 1
|
INSERT 0 1
|
||||||
|
|
||||||
INSERT INTO room_reservation VALUES
|
INSERT INTO room_reservation VALUES
|
||||||
( '123A', '[2010-01-01 14:30, 2010-01-01 15:30)' );
|
( '123A', '[2010-01-01 14:30, 2010-01-01 15:30)' );
|
||||||
-- Result:
|
ERROR: conflicting key value violates exclusion constraint "room_reservation_room_during_excl"
|
||||||
-- 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
|
||||||
-- 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 )).
|
||||||
-- existing key (room, during)=(123A, [ 2010-01-01 14:00:00, 2010-01-01 15:00:00 )).
|
|
||||||
INSERT INTO room_reservation VALUES
|
INSERT INTO room_reservation VALUES
|
||||||
( '123B', '[2010-01-01 14:30, 2010-01-01 15:30)' );
|
( '123B', '[2010-01-01 14:30, 2010-01-01 15:30)' );
|
||||||
-- Result: INSERT 0 1
|
INSERT 0 1
|
||||||
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
|
@ -28,12 +28,12 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
|
||||||
( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
|
( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
|
||||||
|
|
||||||
CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
|
CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
|
||||||
SUBTYPE = <replaceable class="parameter">subtype</replaceable>,
|
SUBTYPE = <replaceable class="parameter">subtype</replaceable>
|
||||||
[ , SUBTYPE_OPCLASS = <replaceable class="parameter">subtype_operator_class</replaceable> ]
|
[ , SUBTYPE_OPCLASS = <replaceable class="parameter">subtype_operator_class</replaceable> ]
|
||||||
[ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
|
|
||||||
[ , CANONICAL = <replaceable class="parameter">canonical_function</replaceable> ]
|
|
||||||
[ , ANALYZE = <replaceable class="parameter">analyze_function</replaceable> ]
|
|
||||||
[ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
|
[ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
|
||||||
|
[ , CANONICAL = <replaceable class="parameter">canonical_function</replaceable> ]
|
||||||
|
[ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
|
||||||
|
[ , ANALYZE = <replaceable class="parameter">analyze_function</replaceable> ]
|
||||||
)
|
)
|
||||||
|
|
||||||
CREATE TYPE <replaceable class="parameter">name</replaceable> (
|
CREATE TYPE <replaceable class="parameter">name</replaceable> (
|
||||||
|
@ -79,6 +79,18 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
|
||||||
table in the same schema.)
|
table in the same schema.)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
There are five forms of <command>CREATE TYPE</command>, as shown in the
|
||||||
|
syntax synopsis above. They respectively create a <firstterm>composite
|
||||||
|
type</>, an <firstterm>enum type</>, a <firstterm>range type</>, a
|
||||||
|
<firstterm>base type</>, or a <firstterm>shell type</>. The first four
|
||||||
|
of these are discussed in turn below. A shell type is simply a placeholder
|
||||||
|
for a type to be defined later; it is created by issuing <command>CREATE
|
||||||
|
TYPE</command> with no parameters except for the type name. Shell types
|
||||||
|
are needed as forward references when creating range types and base types,
|
||||||
|
as discussed in those sections.
|
||||||
|
</para>
|
||||||
|
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Composite Types</title>
|
<title>Composite Types</title>
|
||||||
|
|
||||||
|
@ -102,59 +114,65 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
|
||||||
The second form of <command>CREATE TYPE</command> creates an enumerated
|
The second form of <command>CREATE TYPE</command> creates an enumerated
|
||||||
(enum) type, as described in <xref linkend="datatype-enum">.
|
(enum) type, as described in <xref linkend="datatype-enum">.
|
||||||
Enum types take a list of one or more quoted labels, each of which
|
Enum types take a list of one or more quoted labels, each of which
|
||||||
must be less than <symbol>NAMEDATALEN</symbol> bytes long (64 in a standard
|
must be less than <symbol>NAMEDATALEN</symbol> bytes long (64 bytes in a
|
||||||
<productname>PostgreSQL</productname> build).
|
standard <productname>PostgreSQL</productname> build).
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2 id="SQL-CREATETYPE-RANGE">
|
<refsect2 id="SQL-CREATETYPE-RANGE">
|
||||||
<title>Range Types</title>
|
<title>Range Types</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The third form of <command>CREATE TYPE</command> creates a new
|
The third form of <command>CREATE TYPE</command> creates a new
|
||||||
range type, as described in <xref linkend="rangetypes">.
|
range type, as described in <xref linkend="rangetypes">.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <replaceable class="parameter">subtype</replaceable> parameter
|
The range type's <replaceable class="parameter">subtype</replaceable> can
|
||||||
can be any type with an associated btree opclass (uses the type's
|
be any type with an associated btree operator class (to determine the
|
||||||
default btree operator class unless specified with
|
ordering of values for the range type). Normally the subtype's default
|
||||||
<replaceable class="parameter">subtype_operator_class</replaceable>).
|
btree operator class is used to determine ordering; to use a non-default
|
||||||
</para>
|
opclass, specify its name with <replaceable
|
||||||
|
class="parameter">subtype_opclass</replaceable>. If the subtype is
|
||||||
|
collatable, and you want to use a non-default collation in the range's
|
||||||
|
ordering, specify the desired collation with the <replaceable
|
||||||
|
class="parameter">collation</replaceable> option.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <replaceable class="parameter">subtype_diff</replaceable>
|
The optional <replaceable class="parameter">canonical</replaceable>
|
||||||
function takes two values of type
|
function must take one argument of the range type being defined, and
|
||||||
<replaceable class="parameter">subtype</replaceable> as argument, and
|
return a value of the same type. This is used to convert the range value
|
||||||
returns the distance between the two values as
|
to a canonical form, when applicable. See <xref linkend="rangetypes">
|
||||||
<type>double precision</type>. This function is used for GiST indexing
|
|
||||||
(see <xref linkend="gist"> for more information), and should be provided
|
|
||||||
for efficiency.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The <replaceable class="parameter">canonical</replaceable>
|
|
||||||
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 <xref linkend="rangetypes">
|
|
||||||
for more information. To define
|
for more information. To define
|
||||||
a <replaceable class="parameter">canonical</replaceable> function,
|
the <replaceable class="parameter">canonical</replaceable> function,
|
||||||
you must first create a <firstterm>shell type</>, which is a
|
you must first create a shell type, which is a
|
||||||
placeholder type that has no properties except a name and an
|
placeholder type that has no properties except a name and an
|
||||||
owner. This is done by issuing the command <literal>CREATE TYPE
|
owner. This is done by issuing the command <literal>CREATE TYPE
|
||||||
<replaceable>name</></literal>, with no additional parameters.
|
<replaceable>name</></literal>, with no additional parameters. Then
|
||||||
</para>
|
the function can be declared, and finally the range type can be declared,
|
||||||
|
replacing the shell type entry with a valid range type.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <replaceable class="parameter">analyze</replaceable>
|
The optional <replaceable class="parameter">subtype_diff</replaceable>
|
||||||
function is the same as for creating a base type.
|
function must take two values of the
|
||||||
</para>
|
<replaceable class="parameter">subtype</replaceable> type as argument,
|
||||||
|
and return a <type>double precision</type> value representing the
|
||||||
|
difference between the two given values. While this is optional,
|
||||||
|
providing it allows much greater efficiency of GiST indexes on columns of
|
||||||
|
the range type. Note that the <replaceable
|
||||||
|
class="parameter">subtype_diff</replaceable> function should agree with
|
||||||
|
the sort ordering implied by the selected operator class and collation;
|
||||||
|
that is, its result should be positive whenever its first argument is
|
||||||
|
greater than its second according to the sort ordering.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The <replaceable class="parameter">collation</replaceable> option
|
The optional <replaceable class="parameter">analyze</replaceable>
|
||||||
specifies the collation used when determining the total order for
|
function performs type-specific statistics collection for columns of the
|
||||||
the range.
|
range type. This is defined the same as for base types; see below.
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2>
|
<refsect2>
|
||||||
|
@ -431,7 +449,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
|
||||||
<para>
|
<para>
|
||||||
Whenever a user-defined type is created,
|
Whenever a user-defined type is created,
|
||||||
<productname>PostgreSQL</productname> automatically creates an
|
<productname>PostgreSQL</productname> automatically creates an
|
||||||
associated array type, whose name consists of the base type's
|
associated array type, whose name consists of the element type's
|
||||||
name prepended with an underscore, and truncated if necessary to keep
|
name prepended with an underscore, and truncated if necessary to keep
|
||||||
it less than <symbol>NAMEDATALEN</symbol> bytes long. (If the name
|
it less than <symbol>NAMEDATALEN</symbol> bytes long. (If the name
|
||||||
so generated collides with an existing type name, the process is
|
so generated collides with an existing type name, the process is
|
||||||
|
@ -496,6 +514,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">collation</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The name of an existing collation to be associated with a column of
|
||||||
|
a composite type, or with a range type.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable class="parameter">label</replaceable></term>
|
<term><replaceable class="parameter">label</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -506,6 +534,43 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">subtype</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The name of the element type that the range type will represent ranges
|
||||||
|
of.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">subtype_operator_class</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The name of a btree operator class for the subtype.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">canonical_function</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The name of the canonicalization function for the range type.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">subtype_diff_function</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The name of a difference function for the subtype.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable class="parameter">input_function</replaceable></term>
|
<term><replaceable class="parameter">input_function</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -699,8 +764,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Because there are no restrictions on use of a data type once it's been
|
Because there are no restrictions on use of a data type once it's been
|
||||||
created, creating a base type is tantamount to granting public execute
|
created, creating a base type or range type is tantamount to granting
|
||||||
permission on the functions mentioned in the type definition.
|
public execute permission on the functions mentioned in the type definition.
|
||||||
This is usually
|
This is usually
|
||||||
not an issue for the sorts of functions that are useful in a type
|
not an issue for the sorts of functions that are useful in a type
|
||||||
definition. But you might want to think twice before designing a type
|
definition. But you might want to think twice before designing a type
|
||||||
|
@ -730,7 +795,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Before <productname>PostgreSQL</productname> version 8.2, the syntax
|
Before <productname>PostgreSQL</productname> version 8.2, the shell-type
|
||||||
|
creation syntax
|
||||||
<literal>CREATE TYPE <replaceable>name</></literal> did not exist.
|
<literal>CREATE TYPE <replaceable>name</></literal> did not exist.
|
||||||
The way to create a new base type was to create its input function first.
|
The way to create a new base type was to create its input function first.
|
||||||
In this approach, <productname>PostgreSQL</productname> will first see
|
In this approach, <productname>PostgreSQL</productname> will first see
|
||||||
|
@ -787,6 +853,13 @@ CREATE TABLE bug (
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This example creates a range type:
|
||||||
|
<programlisting>
|
||||||
|
CREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
This example creates the base data type <type>box</type> and then uses the
|
This example creates the base data type <type>box</type> and then uses the
|
||||||
type in a table definition:
|
type in a table definition:
|
||||||
|
@ -860,7 +933,7 @@ CREATE TABLE big_objs (
|
||||||
<para>
|
<para>
|
||||||
The ability to create a composite type with zero attributes is
|
The ability to create a composite type with zero attributes is
|
||||||
a <productname>PostgreSQL</productname>-specific deviation from the
|
a <productname>PostgreSQL</productname>-specific deviation from the
|
||||||
standard (analogous to <command>CREATE TABLE</command>).
|
standard (analogous to the same case in <command>CREATE TABLE</command>).
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|
|
@ -243,7 +243,7 @@ INSERT INTO mytab (complex_col.r, complex_col.i) VALUES(1.1, 2.2);
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2>
|
<sect2 id="rowtypes-io-syntax">
|
||||||
<title>Composite Type Input and Output Syntax</title>
|
<title>Composite Type Input and Output Syntax</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -2986,7 +2986,8 @@ getTypes(int *numTypes)
|
||||||
/*
|
/*
|
||||||
* If it's a base type, make a DumpableObject representing a shell
|
* If it's a base type, make a DumpableObject representing a shell
|
||||||
* definition of the type. We will need to dump that ahead of the I/O
|
* definition of the type. We will need to dump that ahead of the I/O
|
||||||
* functions for the type.
|
* functions for the type. Similarly, range types need a shell
|
||||||
|
* definition in case they have a canonicalize function.
|
||||||
*
|
*
|
||||||
* Note: the shell type doesn't have a catId. You might think it
|
* Note: the shell type doesn't have a catId. You might think it
|
||||||
* should copy the base type's catId, but then it might capture the
|
* should copy the base type's catId, but then it might capture the
|
||||||
|
@ -3006,8 +3007,8 @@ getTypes(int *numTypes)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initially mark the shell type as not to be dumped. We'll only
|
* Initially mark the shell type as not to be dumped. We'll only
|
||||||
* dump it if the I/O functions need to be dumped; this is taken
|
* dump it if the I/O or canonicalize functions need to be dumped;
|
||||||
* care of while sorting dependencies.
|
* this is taken care of while sorting dependencies.
|
||||||
*/
|
*/
|
||||||
stinfo->dobj.dump = false;
|
stinfo->dobj.dump = false;
|
||||||
|
|
||||||
|
@ -7340,6 +7341,9 @@ dumpType(Archive *fout, TypeInfo *tyinfo)
|
||||||
dumpEnumType(fout, tyinfo);
|
dumpEnumType(fout, tyinfo);
|
||||||
else if (tyinfo->typtype == TYPTYPE_RANGE)
|
else if (tyinfo->typtype == TYPTYPE_RANGE)
|
||||||
dumpRangeType(fout, tyinfo);
|
dumpRangeType(fout, tyinfo);
|
||||||
|
else
|
||||||
|
write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
|
||||||
|
tyinfo->dobj.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -636,7 +636,8 @@ findLoop(DumpableObject *obj,
|
||||||
/*
|
/*
|
||||||
* A user-defined datatype will have a dependency loop with each of its
|
* A user-defined datatype will have a dependency loop with each of its
|
||||||
* I/O functions (since those have the datatype as input or output).
|
* I/O functions (since those have the datatype as input or output).
|
||||||
* Break the loop and make the I/O function depend on the associated
|
* Similarly, a range type will have a loop with its canonicalize function,
|
||||||
|
* if any. Break the loop by making the function depend on the associated
|
||||||
* shell type, instead.
|
* shell type, instead.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
|
@ -651,7 +652,7 @@ repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj)
|
||||||
if (typeInfo->shellType)
|
if (typeInfo->shellType)
|
||||||
{
|
{
|
||||||
addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId);
|
addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId);
|
||||||
/* Mark shell type as to be dumped if any I/O function is */
|
/* Mark shell type as to be dumped if any such function is */
|
||||||
if (funcobj->dump)
|
if (funcobj->dump)
|
||||||
typeInfo->shellType->dobj.dump = true;
|
typeInfo->shellType->dobj.dump = true;
|
||||||
}
|
}
|
||||||
|
@ -789,7 +790,7 @@ repairDependencyLoop(DumpableObject **loop,
|
||||||
int i,
|
int i,
|
||||||
j;
|
j;
|
||||||
|
|
||||||
/* Datatype and one of its I/O functions */
|
/* Datatype and one of its I/O or canonicalize functions */
|
||||||
if (nLoop == 2 &&
|
if (nLoop == 2 &&
|
||||||
loop[0]->objType == DO_TYPE &&
|
loop[0]->objType == DO_TYPE &&
|
||||||
loop[1]->objType == DO_FUNC)
|
loop[1]->objType == DO_FUNC)
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
CATALOG(pg_range,3541) BKI_WITHOUT_OIDS
|
CATALOG(pg_range,3541) BKI_WITHOUT_OIDS
|
||||||
{
|
{
|
||||||
Oid rngtypid; /* OID of owning range type */
|
Oid rngtypid; /* OID of owning range type */
|
||||||
Oid rngsubtype; /* OID of range's subtype */
|
Oid rngsubtype; /* OID of range's element type (subtype) */
|
||||||
Oid rngcollation; /* collation for this range type, or 0 */
|
Oid rngcollation; /* collation for this range type, or 0 */
|
||||||
Oid rngsubopc; /* subtype's btree opclass */
|
Oid rngsubopc; /* subtype's btree opclass */
|
||||||
regproc rngcanonical; /* canonicalize range, or 0 */
|
regproc rngcanonical; /* canonicalize range, or 0 */
|
||||||
|
|
|
@ -61,8 +61,9 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71) BKI_SCHEMA_MACRO
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* typtype is 'b' for a base type, 'c' for a composite type (e.g., a
|
* typtype is 'b' for a base type, 'c' for a composite type (e.g., a
|
||||||
* table's rowtype), 'd' for a domain type, 'e' for an enum type, or 'p'
|
* table's rowtype), 'd' for a domain, 'e' for an enum type,
|
||||||
* for a pseudo-type. (Use the TYPTYPE macros below.)
|
* 'p' for a pseudo-type, or 'r' for a range type.
|
||||||
|
* (Use the TYPTYPE macros below.)
|
||||||
*
|
*
|
||||||
* If typtype is 'c', typrelid is the OID of the class' entry in pg_class.
|
* If typtype is 'c', typrelid is the OID of the class' entry in pg_class.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -56,11 +56,14 @@ WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR
|
||||||
-----+---------
|
-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
-- Look for basic or enum types that don't have an array type.
|
-- Look for types that should have an array type according to their typtype,
|
||||||
|
-- but don't. We exclude composites here because we have not bothered to
|
||||||
|
-- make array types corresponding to the system catalogs' rowtypes.
|
||||||
-- NOTE: as of 9.1, this check finds pg_node_tree, smgr, and unknown.
|
-- NOTE: as of 9.1, this check finds pg_node_tree, smgr, and unknown.
|
||||||
SELECT p1.oid, p1.typname
|
SELECT p1.oid, p1.typname
|
||||||
FROM pg_type as p1
|
FROM pg_type as p1
|
||||||
WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS
|
WHERE p1.typtype not in ('c','d','p') AND p1.typname NOT LIKE E'\\_%'
|
||||||
|
AND NOT EXISTS
|
||||||
(SELECT 1 FROM pg_type as p2
|
(SELECT 1 FROM pg_type as p2
|
||||||
WHERE p2.typname = ('_' || p1.typname)::name AND
|
WHERE p2.typname = ('_' || p1.typname)::name AND
|
||||||
p2.typelem = p1.oid and p1.typarray = p2.oid);
|
p2.typelem = p1.oid and p1.typarray = p2.oid);
|
||||||
|
@ -150,6 +153,19 @@ ORDER BY 1;
|
||||||
30 | oidvector | 54 | oidvectorin
|
30 | oidvector | 54 | oidvectorin
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
|
-- Composites, domains, enums, ranges should all use the same input routines
|
||||||
|
SELECT DISTINCT typtype, typinput
|
||||||
|
FROM pg_type AS p1
|
||||||
|
WHERE p1.typtype not in ('b', 'p')
|
||||||
|
ORDER BY 1;
|
||||||
|
typtype | typinput
|
||||||
|
---------+-----------
|
||||||
|
c | record_in
|
||||||
|
d | domain_in
|
||||||
|
e | enum_in
|
||||||
|
r | range_in
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
-- Check for bogus typoutput routines
|
-- Check for bogus typoutput routines
|
||||||
-- As of 8.0, this check finds refcursor, which is borrowing
|
-- As of 8.0, this check finds refcursor, which is borrowing
|
||||||
-- other types' I/O routines
|
-- other types' I/O routines
|
||||||
|
@ -174,6 +190,26 @@ WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||||
-----+---------+-----+---------
|
-----+---------+-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
|
-- Composites, enums, ranges should all use the same output routines
|
||||||
|
SELECT DISTINCT typtype, typoutput
|
||||||
|
FROM pg_type AS p1
|
||||||
|
WHERE p1.typtype not in ('b', 'd', 'p')
|
||||||
|
ORDER BY 1;
|
||||||
|
typtype | typoutput
|
||||||
|
---------+------------
|
||||||
|
c | record_out
|
||||||
|
e | enum_out
|
||||||
|
r | range_out
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- Domains should have same typoutput as their base types
|
||||||
|
SELECT p1.oid, p1.typname, p2.oid, p2.typname
|
||||||
|
FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid
|
||||||
|
WHERE p1.typtype = 'd' AND p1.typoutput IS DISTINCT FROM p2.typoutput;
|
||||||
|
oid | typname | oid | typname
|
||||||
|
-----+---------+-----+---------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
-- Check for bogus typreceive routines
|
-- Check for bogus typreceive routines
|
||||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||||
FROM pg_type AS p1, pg_proc AS p2
|
FROM pg_type AS p1, pg_proc AS p2
|
||||||
|
@ -222,6 +258,19 @@ WHERE p1.typinput = p2.oid AND p1.typreceive = p3.oid AND
|
||||||
-----+---------+-----+---------+-----+---------
|
-----+---------+-----+---------+-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
|
-- Composites, domains, enums, ranges should all use the same receive routines
|
||||||
|
SELECT DISTINCT typtype, typreceive
|
||||||
|
FROM pg_type AS p1
|
||||||
|
WHERE p1.typtype not in ('b', 'p')
|
||||||
|
ORDER BY 1;
|
||||||
|
typtype | typreceive
|
||||||
|
---------+-------------
|
||||||
|
c | record_recv
|
||||||
|
d | domain_recv
|
||||||
|
e | enum_recv
|
||||||
|
r | range_recv
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
-- Check for bogus typsend routines
|
-- Check for bogus typsend routines
|
||||||
-- As of 7.4, this check finds refcursor, which is borrowing
|
-- As of 7.4, this check finds refcursor, which is borrowing
|
||||||
-- other types' I/O routines
|
-- other types' I/O routines
|
||||||
|
@ -246,10 +295,30 @@ WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||||
-----+---------+-----+---------
|
-----+---------+-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
|
-- Composites, enums, ranges should all use the same send routines
|
||||||
|
SELECT DISTINCT typtype, typsend
|
||||||
|
FROM pg_type AS p1
|
||||||
|
WHERE p1.typtype not in ('b', 'd', 'p')
|
||||||
|
ORDER BY 1;
|
||||||
|
typtype | typsend
|
||||||
|
---------+-------------
|
||||||
|
c | record_send
|
||||||
|
e | enum_send
|
||||||
|
r | range_send
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- Domains should have same typsend as their base types
|
||||||
|
SELECT p1.oid, p1.typname, p2.oid, p2.typname
|
||||||
|
FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid
|
||||||
|
WHERE p1.typtype = 'd' AND p1.typsend IS DISTINCT FROM p2.typsend;
|
||||||
|
oid | typname | oid | typname
|
||||||
|
-----+---------+-----+---------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
-- Check for bogus typmodin routines
|
-- Check for bogus typmodin routines
|
||||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||||
FROM pg_type AS p1, pg_proc AS p2
|
FROM pg_type AS p1, pg_proc AS p2
|
||||||
WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
WHERE p1.typmodin = p2.oid AND NOT
|
||||||
(p2.pronargs = 1 AND
|
(p2.pronargs = 1 AND
|
||||||
p2.proargtypes[0] = 'cstring[]'::regtype AND
|
p2.proargtypes[0] = 'cstring[]'::regtype AND
|
||||||
p2.prorettype = 'int4'::regtype AND NOT p2.proretset);
|
p2.prorettype = 'int4'::regtype AND NOT p2.proretset);
|
||||||
|
@ -260,7 +329,7 @@ WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||||
-- Check for bogus typmodout routines
|
-- Check for bogus typmodout routines
|
||||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||||
FROM pg_type AS p1, pg_proc AS p2
|
FROM pg_type AS p1, pg_proc AS p2
|
||||||
WHERE p1.typmodout = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
WHERE p1.typmodout = p2.oid AND NOT
|
||||||
(p2.pronargs = 1 AND
|
(p2.pronargs = 1 AND
|
||||||
p2.proargtypes[0] = 'int4'::regtype AND
|
p2.proargtypes[0] = 'int4'::regtype AND
|
||||||
p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
|
p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
|
||||||
|
@ -298,7 +367,7 @@ WHERE p1.typarray = p2.oid AND
|
||||||
-- Check for bogus typanalyze routines
|
-- Check for bogus typanalyze routines
|
||||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||||
FROM pg_type AS p1, pg_proc AS p2
|
FROM pg_type AS p1, pg_proc AS p2
|
||||||
WHERE p1.typanalyze = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
WHERE p1.typanalyze = p2.oid AND NOT
|
||||||
(p2.pronargs = 1 AND
|
(p2.pronargs = 1 AND
|
||||||
p2.proargtypes[0] = 'internal'::regtype AND
|
p2.proargtypes[0] = 'internal'::regtype AND
|
||||||
p2.prorettype = 'bool'::regtype AND NOT p2.proretset);
|
p2.prorettype = 'bool'::regtype AND NOT p2.proretset);
|
||||||
|
|
|
@ -50,12 +50,15 @@ FROM pg_type as p1
|
||||||
WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR
|
WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR
|
||||||
(p1.typtype != 'c' AND p1.typrelid != 0);
|
(p1.typtype != 'c' AND p1.typrelid != 0);
|
||||||
|
|
||||||
-- Look for basic or enum types that don't have an array type.
|
-- Look for types that should have an array type according to their typtype,
|
||||||
|
-- but don't. We exclude composites here because we have not bothered to
|
||||||
|
-- make array types corresponding to the system catalogs' rowtypes.
|
||||||
-- NOTE: as of 9.1, this check finds pg_node_tree, smgr, and unknown.
|
-- NOTE: as of 9.1, this check finds pg_node_tree, smgr, and unknown.
|
||||||
|
|
||||||
SELECT p1.oid, p1.typname
|
SELECT p1.oid, p1.typname
|
||||||
FROM pg_type as p1
|
FROM pg_type as p1
|
||||||
WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS
|
WHERE p1.typtype not in ('c','d','p') AND p1.typname NOT LIKE E'\\_%'
|
||||||
|
AND NOT EXISTS
|
||||||
(SELECT 1 FROM pg_type as p2
|
(SELECT 1 FROM pg_type as p2
|
||||||
WHERE p2.typname = ('_' || p1.typname)::name AND
|
WHERE p2.typname = ('_' || p1.typname)::name AND
|
||||||
p2.typelem = p1.oid and p1.typarray = p2.oid);
|
p2.typelem = p1.oid and p1.typarray = p2.oid);
|
||||||
|
@ -117,6 +120,12 @@ WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND
|
||||||
(p2.oid = 'array_in'::regproc)
|
(p2.oid = 'array_in'::regproc)
|
||||||
ORDER BY 1;
|
ORDER BY 1;
|
||||||
|
|
||||||
|
-- Composites, domains, enums, ranges should all use the same input routines
|
||||||
|
SELECT DISTINCT typtype, typinput
|
||||||
|
FROM pg_type AS p1
|
||||||
|
WHERE p1.typtype not in ('b', 'p')
|
||||||
|
ORDER BY 1;
|
||||||
|
|
||||||
-- Check for bogus typoutput routines
|
-- Check for bogus typoutput routines
|
||||||
|
|
||||||
-- As of 8.0, this check finds refcursor, which is borrowing
|
-- As of 8.0, this check finds refcursor, which is borrowing
|
||||||
|
@ -135,6 +144,17 @@ FROM pg_type AS p1, pg_proc AS p2
|
||||||
WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||||
(p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
|
(p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
|
||||||
|
|
||||||
|
-- Composites, enums, ranges should all use the same output routines
|
||||||
|
SELECT DISTINCT typtype, typoutput
|
||||||
|
FROM pg_type AS p1
|
||||||
|
WHERE p1.typtype not in ('b', 'd', 'p')
|
||||||
|
ORDER BY 1;
|
||||||
|
|
||||||
|
-- Domains should have same typoutput as their base types
|
||||||
|
SELECT p1.oid, p1.typname, p2.oid, p2.typname
|
||||||
|
FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid
|
||||||
|
WHERE p1.typtype = 'd' AND p1.typoutput IS DISTINCT FROM p2.typoutput;
|
||||||
|
|
||||||
-- Check for bogus typreceive routines
|
-- Check for bogus typreceive routines
|
||||||
|
|
||||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||||
|
@ -169,6 +189,12 @@ FROM pg_type AS p1, pg_proc AS p2, pg_proc AS p3
|
||||||
WHERE p1.typinput = p2.oid AND p1.typreceive = p3.oid AND
|
WHERE p1.typinput = p2.oid AND p1.typreceive = p3.oid AND
|
||||||
p2.pronargs != p3.pronargs;
|
p2.pronargs != p3.pronargs;
|
||||||
|
|
||||||
|
-- Composites, domains, enums, ranges should all use the same receive routines
|
||||||
|
SELECT DISTINCT typtype, typreceive
|
||||||
|
FROM pg_type AS p1
|
||||||
|
WHERE p1.typtype not in ('b', 'p')
|
||||||
|
ORDER BY 1;
|
||||||
|
|
||||||
-- Check for bogus typsend routines
|
-- Check for bogus typsend routines
|
||||||
|
|
||||||
-- As of 7.4, this check finds refcursor, which is borrowing
|
-- As of 7.4, this check finds refcursor, which is borrowing
|
||||||
|
@ -187,11 +213,22 @@ FROM pg_type AS p1, pg_proc AS p2
|
||||||
WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||||
(p2.prorettype = 'bytea'::regtype AND NOT p2.proretset);
|
(p2.prorettype = 'bytea'::regtype AND NOT p2.proretset);
|
||||||
|
|
||||||
|
-- Composites, enums, ranges should all use the same send routines
|
||||||
|
SELECT DISTINCT typtype, typsend
|
||||||
|
FROM pg_type AS p1
|
||||||
|
WHERE p1.typtype not in ('b', 'd', 'p')
|
||||||
|
ORDER BY 1;
|
||||||
|
|
||||||
|
-- Domains should have same typsend as their base types
|
||||||
|
SELECT p1.oid, p1.typname, p2.oid, p2.typname
|
||||||
|
FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid
|
||||||
|
WHERE p1.typtype = 'd' AND p1.typsend IS DISTINCT FROM p2.typsend;
|
||||||
|
|
||||||
-- Check for bogus typmodin routines
|
-- Check for bogus typmodin routines
|
||||||
|
|
||||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||||
FROM pg_type AS p1, pg_proc AS p2
|
FROM pg_type AS p1, pg_proc AS p2
|
||||||
WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
WHERE p1.typmodin = p2.oid AND NOT
|
||||||
(p2.pronargs = 1 AND
|
(p2.pronargs = 1 AND
|
||||||
p2.proargtypes[0] = 'cstring[]'::regtype AND
|
p2.proargtypes[0] = 'cstring[]'::regtype AND
|
||||||
p2.prorettype = 'int4'::regtype AND NOT p2.proretset);
|
p2.prorettype = 'int4'::regtype AND NOT p2.proretset);
|
||||||
|
@ -200,7 +237,7 @@ WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||||
|
|
||||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||||
FROM pg_type AS p1, pg_proc AS p2
|
FROM pg_type AS p1, pg_proc AS p2
|
||||||
WHERE p1.typmodout = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
WHERE p1.typmodout = p2.oid AND NOT
|
||||||
(p2.pronargs = 1 AND
|
(p2.pronargs = 1 AND
|
||||||
p2.proargtypes[0] = 'int4'::regtype AND
|
p2.proargtypes[0] = 'int4'::regtype AND
|
||||||
p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
|
p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
|
||||||
|
@ -230,7 +267,7 @@ WHERE p1.typarray = p2.oid AND
|
||||||
|
|
||||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||||
FROM pg_type AS p1, pg_proc AS p2
|
FROM pg_type AS p1, pg_proc AS p2
|
||||||
WHERE p1.typanalyze = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
WHERE p1.typanalyze = p2.oid AND NOT
|
||||||
(p2.pronargs = 1 AND
|
(p2.pronargs = 1 AND
|
||||||
p2.proargtypes[0] = 'internal'::regtype AND
|
p2.proargtypes[0] = 'internal'::regtype AND
|
||||||
p2.prorettype = 'bool'::regtype AND NOT p2.proretset);
|
p2.prorettype = 'bool'::regtype AND NOT p2.proretset);
|
||||||
|
|
Loading…
Reference in a new issue