Commit 6df7a969 authored by Alexander Korotkov's avatar Alexander Korotkov

Multirange datatypes

Multiranges are basically sorted arrays of non-overlapping ranges with
set-theoretic operations defined over them.

Since v14, each range type automatically gets a corresponding multirange
datatype.  There are both manual and automatic mechanisms for naming multirange
types.  Once can specify multirange type name using multirange_type_name
attribute in CREATE TYPE.  Otherwise, a multirange type name is generated
automatically.  If the range type name contains "range" then we change that to
"multirange".  Otherwise, we add "_multirange" to the end.

Implementation of multiranges comes with a space-efficient internal
representation format, which evades extra paddings and duplicated storage of
oids.  Altogether this format allows fetching a particular range by its index
in O(n).

Statistic gathering and selectivity estimation are implemented for multiranges.
For this purpose, stored multirange is approximated as union range without gaps.
This field will likely need improvements in the future.

Catversion is bumped.

Discussion: https://postgr.es/m/CALNJ-vSUpQ_Y%3DjXvTxt1VYFztaBSsWVXeF1y6gTYQ4bOiWDLgQ%40mail.gmail.com
Discussion: https://postgr.es/m/a0b8026459d1e6167933be2104a6174e7d40d0ab.camel%40j-davis.com#fe7218c83b08068bfffb0c5293eceda0
Author: Paul Jungwirth, revised by me
Reviewed-by: David Fetter, Corey Huinker, Jeff Davis, Pavel Stehule
Reviewed-by: Alvaro Herrera, Tom Lane, Isaac Morland, David G. Johnston
Reviewed-by: Zhihong Yu, Alexander Korotkov
parent 08b01d4d
...@@ -6237,6 +6237,16 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l ...@@ -6237,6 +6237,16 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
</para></entry> </para></entry>
</row> </row>
<row>
<entry role="catalog_table_entry"><para role="column_definition">
<structfield>rngmultitypid</structfield> <type>oid</type>
(references <link linkend="catalog-pg-type"><structname>pg_type</structname></link>.<structfield>oid</structfield>)
</para>
<para>
OID of the multirange type for this range type
</para></entry>
</row>
<row> <row>
<entry role="catalog_table_entry"><para role="column_definition"> <entry role="catalog_table_entry"><para role="column_definition">
<structfield>rngcollation</structfield> <type>oid</type> <structfield>rngcollation</structfield> <type>oid</type>
...@@ -8671,8 +8681,9 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l ...@@ -8671,8 +8681,9 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
<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,
<literal>p</literal> for a pseudo-type, or <literal>p</literal> for a pseudo-type,
<literal>r</literal> for a range type. <literal>r</literal> for a range type, or
<literal>m</literal> for a multirange type.
See also <structfield>typrelid</structfield> and See also <structfield>typrelid</structfield> and
<structfield>typbasetype</structfield>. <structfield>typbasetype</structfield>.
</para></entry> </para></entry>
......
...@@ -4907,6 +4907,10 @@ SELECT * FROM pg_attribute ...@@ -4907,6 +4907,10 @@ SELECT * FROM pg_attribute
<primary>anyrange</primary> <primary>anyrange</primary>
</indexterm> </indexterm>
<indexterm zone="datatype-pseudo">
<primary>anymultirange</primary>
</indexterm>
<indexterm zone="datatype-pseudo"> <indexterm zone="datatype-pseudo">
<primary>anycompatible</primary> <primary>anycompatible</primary>
</indexterm> </indexterm>
...@@ -4923,6 +4927,10 @@ SELECT * FROM pg_attribute ...@@ -4923,6 +4927,10 @@ SELECT * FROM pg_attribute
<primary>anycompatiblerange</primary> <primary>anycompatiblerange</primary>
</indexterm> </indexterm>
<indexterm zone="datatype-pseudo">
<primary>anycompatiblemultirange</primary>
</indexterm>
<indexterm zone="datatype-pseudo"> <indexterm zone="datatype-pseudo">
<primary>void</primary> <primary>void</primary>
</indexterm> </indexterm>
...@@ -5034,6 +5042,13 @@ SELECT * FROM pg_attribute ...@@ -5034,6 +5042,13 @@ SELECT * FROM pg_attribute
<xref linkend="rangetypes"/>).</entry> <xref linkend="rangetypes"/>).</entry>
</row> </row>
<row>
<entry><type>anymultirange</type></entry>
<entry>Indicates that a function accepts any multirange data type
(see <xref linkend="extend-types-polymorphic"/> and
<xref linkend="rangetypes"/>).</entry>
</row>
<row> <row>
<entry><type>anycompatible</type></entry> <entry><type>anycompatible</type></entry>
<entry>Indicates that a function accepts any data type, <entry>Indicates that a function accepts any data type,
...@@ -5063,6 +5078,14 @@ SELECT * FROM pg_attribute ...@@ -5063,6 +5078,14 @@ SELECT * FROM pg_attribute
<xref linkend="rangetypes"/>).</entry> <xref linkend="rangetypes"/>).</entry>
</row> </row>
<row>
<entry><type>anycompatiblemultirange</type></entry>
<entry>Indicates that a function accepts any multirange data type,
with automatic promotion of multiple arguments to a common data type
(see <xref linkend="extend-types-polymorphic"/> and
<xref linkend="rangetypes"/>).</entry>
</row>
<row> <row>
<entry><type>cstring</type></entry> <entry><type>cstring</type></entry>
<entry>Indicates that a function accepts or returns a null-terminated C string.</entry> <entry>Indicates that a function accepts or returns a null-terminated C string.</entry>
......
...@@ -288,6 +288,14 @@ ...@@ -288,6 +288,14 @@
</entry> </entry>
</row> </row>
<row>
<entry><type>anymultirange</type></entry>
<entry>Simple</entry>
<entry>Indicates that a function accepts any multirange data type
(see <xref linkend="rangetypes"/>)
</entry>
</row>
<row> <row>
<entry><type>anycompatible</type></entry> <entry><type>anycompatible</type></entry>
<entry>Common</entry> <entry>Common</entry>
...@@ -319,6 +327,14 @@ ...@@ -319,6 +327,14 @@
with automatic promotion of multiple arguments to a common data type with automatic promotion of multiple arguments to a common data type
</entry> </entry>
</row> </row>
<row>
<entry><type>anycompatiblemultirange</type></entry>
<entry>Common</entry>
<entry>Indicates that a function accepts any multirange data type,
with automatic promotion of multiple arguments to a common data type
</entry>
</row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
...@@ -346,17 +362,15 @@ ...@@ -346,17 +362,15 @@
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. And similarly, but similarly they must all be the same type. And similarly,
positions declared as <type>anyrange</type> must all be the same range positions declared as <type>anyrange</type> must all be the same range
type. Furthermore, if there are type. Likewise for <type>anymultirange</type>.
</para>
<para>
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>
and others declared <type>anyelement</type> or <type>anyarray</type>,
the actual range type in the <type>anyrange</type> positions must be a
range whose subtype is the same type appearing in
the <type>anyelement</type> positions and the same as the element type
of the <type>anyarray</type> positions.
<type>anynonarray</type> is treated exactly the same as <type>anyelement</type>, <type>anynonarray</type> is treated exactly the same as <type>anyelement</type>,
but adds the additional constraint that the actual type must not be but adds the additional constraint that the actual type must not be
an array type. an array type.
...@@ -365,6 +379,19 @@ ...@@ -365,6 +379,19 @@
be an enum type. be an enum type.
</para> </para>
<para>
Similarly, if there are positions declared <type>anyrange</type>
and others declared <type>anyelement</type> or <type>anyarray</type>,
the actual range type in the <type>anyrange</type> positions must be a
range whose subtype is the same type appearing in
the <type>anyelement</type> positions and the same as the element type
of the <type>anyarray</type> positions.
If there are positions declared <type>anymultirange</type>,
their actual multirange type must contain ranges matching parameters declared
<type>anyrange</type> and base elements matching parameters declared
<type>anyelement</type> and <type>anyarray</type>.
</para>
<para> <para>
Thus, when more than one argument position is declared with a polymorphic Thus, when more than one argument position is declared with a polymorphic
type, the net effect is that only certain combinations of actual argument type, the net effect is that only certain combinations of actual argument
...@@ -420,7 +447,8 @@ ...@@ -420,7 +447,8 @@
Selection of the common type considers the actual types Selection of the common type considers the actual types
of <type>anycompatible</type> and <type>anycompatiblenonarray</type> of <type>anycompatible</type> and <type>anycompatiblenonarray</type>
inputs, the array element types of <type>anycompatiblearray</type> inputs, the array element types of <type>anycompatiblearray</type>
inputs, and the range subtypes of <type>anycompatiblerange</type> inputs, the range subtypes of <type>anycompatiblerange</type> inputs,
and the multirange subtypes of <type>anycompatiablemultirange</type>
inputs. If <type>anycompatiblenonarray</type> is present then the inputs. If <type>anycompatiblenonarray</type> is present then the
common type is required to be a non-array type. Once a common type is common type is required to be a non-array type. Once a common type is
identified, arguments in <type>anycompatible</type> identified, arguments in <type>anycompatible</type>
...@@ -431,12 +459,15 @@ ...@@ -431,12 +459,15 @@
<para> <para>
Since there is no way to select a range type knowing only its subtype, Since there is no way to select a range type knowing only its subtype,
use of <type>anycompatiblerange</type> requires that all arguments use of <type>anycompatiblerange</type> and/or
declared with that type have the same actual range type, and that that <type>anycompatiblemultirange</type> requires that all arguments declared
type's subtype agree with the selected common type, so that no casting with that type have the same actual range and/or multirange type, and that
of the range values is required. As with <type>anyrange</type>, use that type's subtype agree with the selected common type, so that no casting
of <type>anycompatiblerange</type> as a function result type requires of the range values is required. As with <type>anyrange</type> and
that there be an <type>anycompatiblerange</type> argument. <type>anymultirange</type>, use of <type>anycompatiblerange</type> and
<type>anymultirange</type> as a function result type requires that there be
an <type>anycompatiblerange</type> or <type>anycompatiblemultirange</type>
argument.
</para> </para>
<para> <para>
......
This diff is collapsed.
...@@ -27,40 +27,53 @@ ...@@ -27,40 +27,53 @@
ranges from an instrument, and so forth can also be useful. ranges from an instrument, and so forth can also be useful.
</para> </para>
<para>
Every range type has a corresponding multirange type. A multirange is
an ordered list of non-continguous, non-empty, non-null ranges. Most
range operators also work on multiranges, and they have a few functions
of their own.
</para>
<sect2 id="rangetypes-builtin"> <sect2 id="rangetypes-builtin">
<title>Built-in Range Types</title> <title>Built-in Range and Multirange 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> &mdash; Range of <type>integer</type> <type>int4range</type> &mdash; Range of <type>integer</type>,
<type>int4multirange</type> &mdash; corresponding Multirange
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<type>int8range</type> &mdash; Range of <type>bigint</type> <type>int8range</type> &mdash; Range of <type>bigint</type>,
<type>int8multirange</type> &mdash; corresponding Multirange
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<type>numrange</type> &mdash; Range of <type>numeric</type> <type>numrange</type> &mdash; Range of <type>numeric</type>,
<type>nummultirange</type> &mdash; corresponding Multirange
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<type>tsrange</type> &mdash; Range of <type>timestamp without time zone</type> <type>tsrange</type> &mdash; Range of <type>timestamp without time zone</type>,
<type>tsmultirange</type> &mdash; corresponding Multirange
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<type>tstzrange</type> &mdash; Range of <type>timestamp with time zone</type> <type>tstzrange</type> &mdash; Range of <type>timestamp with time zone</type>,
<type>tstzmultirange</type> &mdash; corresponding Multirange
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<type>daterange</type> &mdash; Range of <type>date</type> <type>daterange</type> &mdash; Range of <type>date</type>,
<type>datemultirange</type> &mdash; corresponding Multirange
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
...@@ -232,10 +245,30 @@ SELECT '[4,4]'::int4range; ...@@ -232,10 +245,30 @@ SELECT '[4,4]'::int4range;
SELECT '[4,4)'::int4range; SELECT '[4,4)'::int4range;
</programlisting> </programlisting>
</para> </para>
<para>
The input for a multirange is curly brackets (<literal>{</literal> and
<literal>}</literal>) containing zero or more valid ranges,
separated by commas. Whitespace is permitted around the brackets and
commas. This is intended to be reminiscent of array syntax, although
multiranges are much simpler: they have just one dimension and there is
no need to quote their contents. (The bounds of their ranges may be
quoted as above however.)
</para>
<para>
Examples:
<programlisting>
SELECT '{}'::int4multirange;
SELECT '{[3,7)}'::int4multirange;
SELECT '{[3,7), [8,9)}'::int4multirange;
</programlisting>
</para>
</sect2> </sect2>
<sect2 id="rangetypes-construct"> <sect2 id="rangetypes-construct">
<title>Constructing Ranges</title> <title>Constructing Ranges and Multiranges</title>
<para> <para>
Each range type has a constructor function with the same name as the range Each range type has a constructor function with the same name as the range
...@@ -267,6 +300,19 @@ SELECT int8range(1, 14, '(]'); ...@@ -267,6 +300,19 @@ SELECT int8range(1, 14, '(]');
-- Using NULL for either bound causes the range to be unbounded on that side. -- Using NULL for either bound causes the range to be unbounded on that side.
SELECT numrange(NULL, 2.2); SELECT numrange(NULL, 2.2);
</programlisting>
</para>
<para>
Each range type also has a multirange constructor with the same name as the
multirange type. The constructor function takes zero or more arguments
which are all ranges of the appropriate type.
For example:
<programlisting>
SELECT nummultirange();
SELECT nummultirange(numrange(1.0, 14.0));
SELECT nummultirange(numrange(1.0, 14.0), numrange(20.0, 25.0));
</programlisting> </programlisting>
</para> </para>
</sect2> </sect2>
...@@ -341,6 +387,11 @@ SELECT '[1.234, 5.678]'::floatrange; ...@@ -341,6 +387,11 @@ SELECT '[1.234, 5.678]'::floatrange;
function in this example. function in this example.
</para> </para>
<para>
When you define your own range you automatically get a corresponding
multirange type.
</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
subtype B-tree operator class or collation to use, so as to change the sort subtype B-tree operator class or collation to use, so as to change the sort
......
...@@ -33,6 +33,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE ( ...@@ -33,6 +33,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
[ , COLLATION = <replaceable class="parameter">collation</replaceable> ] [ , COLLATION = <replaceable class="parameter">collation</replaceable> ]
[ , CANONICAL = <replaceable class="parameter">canonical_function</replaceable> ] [ , CANONICAL = <replaceable class="parameter">canonical_function</replaceable> ]
[ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ] [ , SUBTYPE_DIFF = <replaceable class="parameter">subtype_diff_function</replaceable> ]
[ , MULTIRANGE_TYPE_NAME = <replaceable class="parameter">multirange_type_name</replaceable> ]
) )
CREATE TYPE <replaceable class="parameter">name</replaceable> ( CREATE TYPE <replaceable class="parameter">name</replaceable> (
...@@ -174,6 +175,17 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ...@@ -174,6 +175,17 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
the range type. See <xref linkend="rangetypes-defining"/> for more the range type. See <xref linkend="rangetypes-defining"/> for more
information. information.
</para> </para>
<para>
The optional <replaceable class="parameter">multirange_type_name</replaceable>
parameter specifies the name of the corresponding multirange type. If not
specified, this name is chosen automatically as follows.
If range type name contains <literal>range</literal> substring, then
multirange type name is formed by replacement of the <literal>range</literal>
substring with <literal>multirange</literal> substring in the range
type name. Otherwise, multirange type name is formed by appending
<literal>_multirange</literal> suffix to the range type name.
</para>
</refsect2> </refsect2>
<refsect2> <refsect2>
...@@ -630,6 +642,15 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ...@@ -630,6 +642,15 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><replaceable class="parameter">multirange_type_name</replaceable></term>
<listitem>
<para>
The name of the corresponding multirange type.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="parameter">input_function</replaceable></term> <term><replaceable class="parameter">input_function</replaceable></term>
<listitem> <listitem>
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
void void
RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation,
Oid rangeSubOpclass, RegProcedure rangeCanonical, Oid rangeSubOpclass, RegProcedure rangeCanonical,
RegProcedure rangeSubDiff) RegProcedure rangeSubDiff, Oid multirangeTypeOid)
{ {
Relation pg_range; Relation pg_range;
Datum values[Natts_pg_range]; Datum values[Natts_pg_range];
...@@ -43,6 +43,7 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, ...@@ -43,6 +43,7 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation,
HeapTuple tup; HeapTuple tup;
ObjectAddress myself; ObjectAddress myself;
ObjectAddress referenced; ObjectAddress referenced;
ObjectAddress referencing;
ObjectAddresses *addrs; ObjectAddresses *addrs;
pg_range = table_open(RangeRelationId, RowExclusiveLock); pg_range = table_open(RangeRelationId, RowExclusiveLock);
...@@ -55,6 +56,7 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, ...@@ -55,6 +56,7 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation,
values[Anum_pg_range_rngsubopc - 1] = ObjectIdGetDatum(rangeSubOpclass); values[Anum_pg_range_rngsubopc - 1] = ObjectIdGetDatum(rangeSubOpclass);
values[Anum_pg_range_rngcanonical - 1] = ObjectIdGetDatum(rangeCanonical); values[Anum_pg_range_rngcanonical - 1] = ObjectIdGetDatum(rangeCanonical);
values[Anum_pg_range_rngsubdiff - 1] = ObjectIdGetDatum(rangeSubDiff); values[Anum_pg_range_rngsubdiff - 1] = ObjectIdGetDatum(rangeSubDiff);
values[Anum_pg_range_rngmultitypid - 1] = ObjectIdGetDatum(multirangeTypeOid);
tup = heap_form_tuple(RelationGetDescr(pg_range), values, nulls); tup = heap_form_tuple(RelationGetDescr(pg_range), values, nulls);
...@@ -93,6 +95,12 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, ...@@ -93,6 +95,12 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation,
record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL); record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs); free_object_addresses(addrs);
/* record multirange type's dependency on the range type */
referencing.classId = TypeRelationId;
referencing.objectId = multirangeTypeOid;
referencing.objectSubId = 0;
recordDependencyOn(&referencing, &myself, DEPENDENCY_INTERNAL);
table_close(pg_range, RowExclusiveLock); table_close(pg_range, RowExclusiveLock);
} }
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/typecmds.h" #include "commands/typecmds.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/scansup.h" #include "parser/scansup.h"
#include "utils/acl.h" #include "utils/acl.h"
...@@ -37,6 +38,9 @@ ...@@ -37,6 +38,9 @@
#include "utils/rel.h" #include "utils/rel.h"
#include "utils/syscache.h" #include "utils/syscache.h"
static char *makeUniqueTypeName(const char *typeName, Oid typeNamespace,
bool tryOriginal);
/* Potentially set by pg_upgrade_support functions */ /* Potentially set by pg_upgrade_support functions */
Oid binary_upgrade_next_pg_type_oid = InvalidOid; Oid binary_upgrade_next_pg_type_oid = InvalidOid;
...@@ -863,31 +867,10 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace) ...@@ -863,31 +867,10 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
char * char *
makeArrayTypeName(const char *typeName, Oid typeNamespace) makeArrayTypeName(const char *typeName, Oid typeNamespace)
{ {
char *arr = (char *) palloc(NAMEDATALEN); char *arr;
int namelen = strlen(typeName);
int i;
/* arr = makeUniqueTypeName(typeName, typeNamespace, false);
* The idea is to prepend underscores as needed until we make a name that if (arr == NULL)
* doesn't collide with anything...
*/
for (i = 1; i < NAMEDATALEN - 1; i++)
{
arr[i - 1] = '_';
if (i + namelen < NAMEDATALEN)
strcpy(arr + i, typeName);
else
{
memcpy(arr + i, typeName, NAMEDATALEN - i);
truncate_identifier(arr, NAMEDATALEN, false);
}
if (!SearchSysCacheExists2(TYPENAMENSP,
CStringGetDatum(arr),
ObjectIdGetDatum(typeNamespace)))
break;
}
if (i >= NAMEDATALEN - 1)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT), (errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("could not form array type name for type \"%s\"", errmsg("could not form array type name for type \"%s\"",
...@@ -958,3 +941,90 @@ moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace) ...@@ -958,3 +941,90 @@ moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
return true; return true;
} }
/*
* makeMultirangeTypeName
* - given a range type name, make a multirange type name for it
*
* caller is responsible for pfreeing the result
*/
char *
makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace)
{
char *buf;
char *rangestr;
/*
* If the range type name contains "range" then change that to
* "multirange". Otherwise add "_multirange" to the end.
*/
rangestr = strstr(rangeTypeName, "range");
if (rangestr)
{
char *prefix = pnstrdup(rangeTypeName, rangestr - rangeTypeName);
buf = psprintf("%s%s%s", prefix, "multi", rangestr);
}
else
buf = psprintf("%s_multirange", pnstrdup(rangeTypeName, NAMEDATALEN - 12));
/* clip it at NAMEDATALEN-1 bytes */
buf[pg_mbcliplen(buf, strlen(buf), NAMEDATALEN - 1)] = '\0';
if (SearchSysCacheExists2(TYPENAMENSP,
CStringGetDatum(buf),
ObjectIdGetDatum(typeNamespace)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("type \"%s\" already exists", buf),
errdetail("Failed while creating a multirange type for type \"%s\".", rangeTypeName),
errhint("You can manually specify a multirange type name using the \"multirange_type_name\" attribute")));
return pstrdup(buf);
}
/*
* makeUniqueTypeName
* Generate a unique name for a prospective new type
*
* Given a typeName, return a new palloc'ed name by preprending underscores
* until a non-conflicting name results.
*
* If tryOriginal, first try with zero underscores.
*/
static char *
makeUniqueTypeName(const char *typeName, Oid typeNamespace, bool tryOriginal)
{
int i;
int namelen;
char dest[NAMEDATALEN];
Assert(strlen(typeName) <= NAMEDATALEN - 1);
if (tryOriginal &&
!SearchSysCacheExists2(TYPENAMENSP,
CStringGetDatum(typeName),
ObjectIdGetDatum(typeNamespace)))
return pstrdup(typeName);
/*
* The idea is to prepend underscores as needed until we make a name that
* doesn't collide with anything ...
*/
namelen = strlen(typeName);
for (i = 1; i < NAMEDATALEN - 1; i++)
{
dest[i - 1] = '_';
strlcpy(dest + i, typeName, NAMEDATALEN - i);
if (namelen + i >= NAMEDATALEN)
truncate_identifier(dest, NAMEDATALEN, false);
if (!SearchSysCacheExists2(TYPENAMENSP,
CStringGetDatum(dest),
ObjectIdGetDatum(typeNamespace)))
return pstrdup(dest);
}
return NULL;
}
This diff is collapsed.
...@@ -1711,7 +1711,8 @@ check_sql_fn_retval(List *queryTreeLists, ...@@ -1711,7 +1711,8 @@ check_sql_fn_retval(List *queryTreeLists,
if (fn_typtype == TYPTYPE_BASE || if (fn_typtype == TYPTYPE_BASE ||
fn_typtype == TYPTYPE_DOMAIN || fn_typtype == TYPTYPE_DOMAIN ||
fn_typtype == TYPTYPE_ENUM || fn_typtype == TYPTYPE_ENUM ||
fn_typtype == TYPTYPE_RANGE) fn_typtype == TYPTYPE_RANGE ||
fn_typtype == TYPTYPE_MULTIRANGE)
{ {
/* /*
* For scalar-type returns, the target list must have exactly one * For scalar-type returns, the target list must have exactly one
......
This diff is collapsed.
...@@ -60,6 +60,8 @@ OBJS = \ ...@@ -60,6 +60,8 @@ OBJS = \
mac8.o \ mac8.o \
mcxtfuncs.o \ mcxtfuncs.o \
misc.o \ misc.o \
multirangetypes.o \
multirangetypes_selfuncs.o \
name.o \ name.o \
network.o \ network.o \
network_gist.o \ network_gist.o \
......
This diff is collapsed.
This diff is collapsed.
...@@ -52,6 +52,28 @@ binary_upgrade_set_next_array_pg_type_oid(PG_FUNCTION_ARGS) ...@@ -52,6 +52,28 @@ binary_upgrade_set_next_array_pg_type_oid(PG_FUNCTION_ARGS)
PG_RETURN_VOID(); PG_RETURN_VOID();
} }
Datum
binary_upgrade_set_next_multirange_pg_type_oid(PG_FUNCTION_ARGS)
{
Oid typoid = PG_GETARG_OID(0);
CHECK_IS_BINARY_UPGRADE;
binary_upgrade_next_mrng_pg_type_oid = typoid;
PG_RETURN_VOID();
}
Datum
binary_upgrade_set_next_multirange_array_pg_type_oid(PG_FUNCTION_ARGS)
{
Oid typoid = PG_GETARG_OID(0);
CHECK_IS_BINARY_UPGRADE;
binary_upgrade_next_mrng_array_pg_type_oid = typoid;
PG_RETURN_VOID();
}
Datum Datum
binary_upgrade_set_next_heap_pg_class_oid(PG_FUNCTION_ARGS) binary_upgrade_set_next_heap_pg_class_oid(PG_FUNCTION_ARGS)
{ {
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "utils/array.h" #include "utils/array.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/rangetypes.h" #include "utils/rangetypes.h"
#include "utils/multirangetypes.h"
/* /*
...@@ -227,6 +228,43 @@ anycompatiblerange_out(PG_FUNCTION_ARGS) ...@@ -227,6 +228,43 @@ anycompatiblerange_out(PG_FUNCTION_ARGS)
return range_out(fcinfo); return range_out(fcinfo);
} }
/*
* anycompatiblemultirange
*
* We may as well allow output, since multirange_out will in fact work.
*/
PSEUDOTYPE_DUMMY_INPUT_FUNC(anycompatiblemultirange);
Datum
anycompatiblemultirange_out(PG_FUNCTION_ARGS)
{
return multirange_out(fcinfo);
}
/*
* anymultirange_in - input routine for pseudo-type ANYMULTIRANGE.
*/
Datum
anymultirange_in(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type %s", "anymultirange")));
PG_RETURN_VOID(); /* keep compiler quiet */
}
/*
* anymultirange_out - output routine for pseudo-type ANYMULTIRANGE.
*
* We may as well allow this, since multirange_out will in fact work.
*/
Datum
anymultirange_out(PG_FUNCTION_ARGS)
{
return multirange_out(fcinfo);
}
/* /*
* void * void
* *
......
This diff is collapsed.
This diff is collapsed.
...@@ -650,6 +650,18 @@ static const struct cachedesc cacheinfo[] = { ...@@ -650,6 +650,18 @@ static const struct cachedesc cacheinfo[] = {
}, },
64 64
}, },
{RangeRelationId, /* RANGEMULTIRANGE */
RangeMultirangeTypidIndexId,
1,
{
Anum_pg_range_rngmultitypid,
0,
0,
0
},
4
},
{RangeRelationId, /* RANGETYPE */ {RangeRelationId, /* RANGETYPE */
RangeTypidIndexId, RangeTypidIndexId,
1, 1,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -176,6 +176,7 @@ typedef struct _typeInfo ...@@ -176,6 +176,7 @@ typedef struct _typeInfo
char typrelkind; /* 'r', 'v', 'c', etc */ char typrelkind; /* 'r', 'v', 'c', etc */
char typtype; /* 'b', 'c', etc */ char typtype; /* 'b', 'c', etc */
bool isArray; /* true if auto-generated array type */ bool isArray; /* true if auto-generated array type */
bool isMultirange; /* true if auto-generated multirange type */
bool isDefined; /* true if typisdefined */ bool isDefined; /* true if typisdefined */
/* If needed, we'll create a "shell type" entry for it; link that here: */ /* If needed, we'll create a "shell type" entry for it; link that here: */
struct _shellTypeInfo *shellType; /* shell-type entry, or NULL */ struct _shellTypeInfo *shellType; /* shell-type entry, or NULL */
......
...@@ -1601,6 +1601,7 @@ my %tests = ( ...@@ -1601,6 +1601,7 @@ my %tests = (
\QOPERATOR 3 dump_test.~~(integer,integer);\E\n.+ \QOPERATOR 3 dump_test.~~(integer,integer);\E\n.+
\QCREATE TYPE dump_test.range_type_custom AS RANGE (\E\n\s+ \QCREATE TYPE dump_test.range_type_custom AS RANGE (\E\n\s+
\Qsubtype = integer,\E\n\s+ \Qsubtype = integer,\E\n\s+
\Qmultirange_type_name = dump_test.multirange_type_custom,\E\n\s+
\Qsubtype_opclass = dump_test.op_class_custom\E\n \Qsubtype_opclass = dump_test.op_class_custom\E\n
\Q);\E \Q);\E
/xms, /xms,
...@@ -1698,6 +1699,7 @@ my %tests = ( ...@@ -1698,6 +1699,7 @@ my %tests = (
regexp => qr/^ regexp => qr/^
\QCREATE TYPE dump_test.textrange AS RANGE (\E \QCREATE TYPE dump_test.textrange AS RANGE (\E
\n\s+\Qsubtype = text,\E \n\s+\Qsubtype = text,\E
\n\s+\Qmultirange_type_name = dump_test.textmultirange,\E
\n\s+\Qcollation = pg_catalog."C"\E \n\s+\Qcollation = pg_catalog."C"\E
\n\);/xm, \n\);/xm,
like => like =>
......
...@@ -139,8 +139,8 @@ ...@@ -139,8 +139,8 @@
* * we need to estimate alignment padding cost abstractly, ie without * * we need to estimate alignment padding cost abstractly, ie without
* reference to a real tuple. We must assume the worst case that * reference to a real tuple. We must assume the worst case that
* all varlenas are aligned. * all varlenas are aligned.
* * within arrays, we unconditionally align varlenas (XXX this should be * * within arrays and multiranges, we unconditionally align varlenas (XXX this
* revisited, probably). * should be revisited, probably).
* *
* The attalign cases are tested in what is hopefully something like their * The attalign cases are tested in what is hopefully something like their
* frequency of occurrence. * frequency of occurrence.
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
extern PGDLLIMPORT Oid binary_upgrade_next_pg_type_oid; extern PGDLLIMPORT Oid binary_upgrade_next_pg_type_oid;
extern PGDLLIMPORT Oid binary_upgrade_next_array_pg_type_oid; extern PGDLLIMPORT Oid binary_upgrade_next_array_pg_type_oid;
extern PGDLLIMPORT Oid binary_upgrade_next_mrng_pg_type_oid;
extern PGDLLIMPORT Oid binary_upgrade_next_mrng_array_pg_type_oid;
extern PGDLLIMPORT Oid binary_upgrade_next_heap_pg_class_oid; extern PGDLLIMPORT Oid binary_upgrade_next_heap_pg_class_oid;
extern PGDLLIMPORT Oid binary_upgrade_next_index_pg_class_oid; extern PGDLLIMPORT Oid binary_upgrade_next_index_pg_class_oid;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment