values. For example, a range over the
<type>numeric</type> type is continuous, as is a range over <type>timestamp</type>.
(Even though <type>timestamp</type> 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>
Another way to think about a discrete range type is that there is a clear
idea of a <quote>next</quote> or <quote>previous</quote> value for each element value.
Knowing that, it is possible to convert between inclusive and exclusive
representations of a range's bounds, by choosing the next or previous
element value instead of the one originally given.
For example, in an integer range type <literal>[4,8]</literal> and
<literal>(3,9)</literal> denote the same set of values; but this would not be so
for a range over numeric.
</para>
<para>
A discrete range type should have a <firstterm>canonicalization</firstterm>
function that is aware of the desired step size for the element type.
The canonicalization function is charged with converting equivalent values
of the range type to have identical representations, in particular
consistently inclusive or exclusive bounds.
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 in reality.
</para>
<para>
The built-in range types <type>int4range</type>, <type>int8range</type>,
and <type>daterange</type> all use a canonical form that includes
the lower bound and excludes the upper bound; that is,
<literal>[)</literal>. User-defined range types can use other conventions,
however.
</para>
</sect2>
<sect2 id="rangetypes-defining">
<title>Defining New Range Types</title>
<para>
Users can define their own range types. The most common reason to do
this is to use ranges over subtypes not provided among the built-in
range types.
For example, to define a new range type of subtype <type>float8</type>:
<programlisting>
CREATE TYPE floatrange AS RANGE (
subtype = float8,
subtype_diff = float8mi
);
SELECT '[1.234, 5.678]'::floatrange;
</programlisting>
Because <type>float8</type> has no meaningful
<quote>step</quote>, we do not define a canonicalization
function in this example.
</para>
<para>
When you define your own range you automatically get a corresponding
multirange type.
</para>
<para>
Defining your own range type also allows you to specify a different
subtype B-tree operator class or collation to use, so as to change the sort
ordering that determines which values fall into a given range.
</para>
<para>
If the subtype is considered to have discrete rather than continuous
values, the <command>CREATE TYPE</command> command should specify a
<literal>canonical</literal> function.
The canonicalization function takes an input range value, and must return
an equivalent range value that may have different bounds and formatting.
The canonical output for two ranges that represent the same set of values,
for example the integer ranges <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. In addition to adjusting the inclusive/exclusive bounds
format, a canonicalization function might round off boundary values, in
case the desired step size is larger than what the subtype is capable of
storing. For instance, a range type over <type>timestamp</type> could be
defined to have a step size of an hour, in which case the canonicalization
function would need to round off bounds that weren't a multiple of an hour,
or perhaps throw an error