Commit 4429f6a9 authored by Heikki Linnakangas's avatar Heikki Linnakangas

Support range data types.

Selectivity estimation functions are missing for some range type operators,
which is a TODO.

Jeff Davis
parent 43342891
......@@ -218,6 +218,11 @@
<entry>functions and procedures</entry>
</row>
<row>
<entry><link linkend="catalog-pg-range"><structname>pg_range</structname></link></entry>
<entry>information about range types</entry>
</row>
<row>
<entry><link linkend="catalog-pg-rewrite"><structname>pg_rewrite</structname></link></entry>
<entry>query rewrite rules</entry>
......@@ -4594,6 +4599,78 @@
</sect1>
<sect1 id="catalog-pg-range">
<title><structname>pg_range</structname></title>
<indexterm zone="catalog-pg-range">
<primary>pg_range</primary>
</indexterm>
<para>
The catalog <structname>pg_range</structname> stores information about range types.
</para>
<table>
<title><structname>pg_range</> Columns</title>
<tgroup cols="4">
<thead>
<row>
<entry>Name</entry>
<entry>Type</entry>
<entry>References</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><structfield>rngtypid</structfield></entry>
<entry><type>oid</type></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>
</row>
<row>
<entry><structfield>rngsubtype</structfield></entry>
<entry><type>oid</type></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>
</row>
<row>
<entry><structfield>rngcollation</structfield></entry>
<entry><type>oid</type></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>
</row>
<row>
<entry><structfield>rngsubopc</structfield></entry>
<entry><type>oid</type></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>
</row>
<row>
<entry><structfield>rngcanonical</structfield></entry>
<entry><type>regproc</type></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>
</row>
<row>
<entry><structfield>rngsubdiff</structfield></entry>
<entry><type>regproc</type></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>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1 id="catalog-pg-rewrite">
<title><structname>pg_rewrite</structname></title>
......
......@@ -4173,6 +4173,8 @@ SET xmloption TO { DOCUMENT | CONTENT };
&rowtypes;
&rangetypes;
<sect1 id="datatype-oid">
<title>Object Identifier Types</title>
......@@ -4443,6 +4445,10 @@ SELECT * FROM pg_attribute
<primary>anyenum</primary>
</indexterm>
<indexterm zone="datatype-pseudo">
<primary>anyrange</primary>
</indexterm>
<indexterm zone="datatype-pseudo">
<primary>void</primary>
</indexterm>
......@@ -4519,6 +4525,13 @@ SELECT * FROM pg_attribute
<xref linkend="datatype-enum">).</entry>
</row>
<row>
<entry><type>anyrange</></entry>
<entry>Indicates that a function accepts any range data type
(see <xref linkend="extend-types-polymorphic"> and
<xref linkend="rangetypes">).</entry>
</row>
<row>
<entry><type>anynonarray</></entry>
<entry>Indicates that a function accepts any non-array data type
......@@ -4583,7 +4596,8 @@ SELECT * FROM pg_attribute
only <type>void</> and <type>record</> as a result type (plus
<type>trigger</> when the function is used as a trigger). Some also
support polymorphic functions using the types <type>anyarray</>,
<type>anyelement</>, <type>anyenum</>, and <type>anynonarray</>.
<type>anyelement</>, <type>anyenum</>, <type>anyrange</>, and
<type>anynonarray</>.
</para>
<para>
......
......@@ -198,14 +198,15 @@
</indexterm>
<para>
Four pseudo-types of special interest are <type>anyelement</>,
<type>anyarray</>, <type>anynonarray</>, and <type>anyenum</>,
which are collectively called <firstterm>polymorphic types</>.
Any function declared using these types is said to be
a <firstterm>polymorphic function</>. A polymorphic function can
operate on many different data types, with the specific data type(s)
being determined by the data types actually passed to it in a particular
call.
Five pseudo-types of special interest are <type>anyelement</>,
<type>anyarray</>, <type>anynonarray</>, <type>anyenum</>,
and <type>anyrange</>, which are collectively
called <firstterm>polymorphic types</>. Any function declared
using these types is said to be a <firstterm>polymorphic
function</>. A polymorphic function can operate on many
different data types, with the specific data type(s) being
determined by the data types actually passed to it in a
particular call.
</para>
<para>
......@@ -221,6 +222,11 @@
<type>anyelement</type>, the actual array type in the
<type>anyarray</type> positions must be an array whose elements are
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>, 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.
<type>anynonarray</> is treated exactly the same as <type>anyelement</>,
but adds the additional constraint that the actual type must not be
an array type.
......
......@@ -25,6 +25,7 @@
<!ENTITY mvcc SYSTEM "mvcc.sgml">
<!ENTITY perform SYSTEM "perform.sgml">
<!ENTITY queries SYSTEM "queries.sgml">
<!entity rangetypes SYSTEM "rangetypes.sgml">
<!ENTITY rowtypes SYSTEM "rowtypes.sgml">
<!ENTITY syntax SYSTEM "syntax.sgml">
<!ENTITY textsearch SYSTEM "textsearch.sgml">
......
......@@ -10457,6 +10457,310 @@ SELECT NULLIF(value, '(none)') ...
</para>
</sect1>
<sect1 id="functions-range">
<title>Range Functions and Operators</title>
<para>
<xref linkend="range-operators-table"> shows the operators
available for range types.
</para>
<table id="range-operators-table">
<title>Range Operators</title>
<tgroup cols="4">
<thead>
<row>
<entry>Operator</entry>
<entry>Description</entry>
<entry>Example</entry>
<entry>Result</entry>
</row>
</thead>
<tbody>
<row>
<entry> <literal>=</literal> </entry>
<entry>equal</entry>
<entry><literal>int4range(1,5) = '[1,4]'::int4range</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&lt;&gt;</literal> </entry>
<entry>not equal</entry>
<entry><literal>numrange(1.1,2.2) &lt;&gt; numrange(1.1,2.3)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&lt;</literal> </entry>
<entry>less than</entry>
<entry><literal>int4range(1,10) &lt; int4range(2,3)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&gt;</literal> </entry>
<entry>greater than</entry>
<entry><literal>int4range(1,10) &gt; int4range(1,5)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&lt;=</literal> </entry>
<entry>less than or equal</entry>
<entry><literal>numrange(1.1,2.2) &lt;= numrange(1.1,2.2)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&gt;=</literal> </entry>
<entry>greater than or equal</entry>
<entry><literal>numrange(1.1,2.2) &gt;= numrange(1.1,2.0)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>@&gt;</literal> </entry>
<entry>contains</entry>
<entry><literal>'[2011-01-01,2011-03-01)'::tsrange @&gt; '2011-01-10'::timestamp</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&lt;@</literal> </entry>
<entry>is contained by</entry>
<entry><literal>int4range(2,4) &lt;@ int4range(1,7)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&amp;&amp;</literal> </entry>
<entry>overlap (have points in common)</entry>
<entry><literal>int8range(3,7) &amp;&amp; int8range(4,12)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&lt;&lt;</literal> </entry>
<entry>strictly left of</entry>
<entry><literal>int8range(1,10) &lt;&lt; int8range(100,110)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&gt;&gt;</literal> </entry>
<entry>strictly right of</entry>
<entry><literal>int8range(50,60) &gt;&gt; int8range(20,30)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&amp;&lt;</literal> </entry>
<entry>Does not extend to the right of?</entry>
<entry><literal>int8range(1,20) &amp;&lt; int8range(18,20)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>&amp;&gt;</literal> </entry>
<entry>Does not extend to the left of?</entry>
<entry><literal>int8range(7,20) &amp;&gt; int8range(5,10)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>-|-</literal> </entry>
<entry>adjacent?</entry>
<entry><literal>numrange(1.1,2.2) -|- numrange(2.2,3.3)</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>+</literal> </entry>
<entry>Union</entry>
<entry><literal>numrange(5,15) + numrange(10,20)</literal></entry>
<entry><literal>[5,20)</literal></entry>
</row>
<row>
<entry> <literal>-</literal> </entry>
<entry>Difference</entry>
<entry><literal>int8range(5,15) - int8range(10,20)</literal></entry>
<entry><literal>[5,10)</literal></entry>
</row>
<row>
<entry> <literal>*</literal> </entry>
<entry>Intersection</entry>
<entry><literal>int8range(5,15) * int8range(10,20)</literal></entry>
<entry><literal>[10,15)</literal></entry>
</row>
<row>
<entry> <literal>!?</literal> </entry>
<entry>Is empty?</entry>
<entry><literal>'empty'::int4range !?</literal></entry>
<entry><literal>t</literal></entry>
</row>
<row>
<entry> <literal>?</literal> </entry>
<entry>Is non-empty?</entry>
<entry><literal>numrange(1.0,2.0)?</literal></entry>
<entry><literal>t</literal></entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Range comparisons compare the lower bounds first, and only if
equal, compare the upper bounds. This is generally most useful for
B-tree indexes, rather than being useful comparisons by themselves.
</para>
<para>
See <xref linkend="rangetypes"> for more details about range operator
behavior.
</para>
<para>
<xref linkend="range-functions-table"> shows the functions
available for use with range types. See <xref linkend="rangetypes">
for more information and examples of the use of these functions.
</para>
<indexterm>
<primary>lower</primary>
</indexterm>
<indexterm>
<primary>upper</primary>
</indexterm>
<indexterm>
<primary>empty</primary>
</indexterm>
<indexterm>
<primary>non_empty</primary>
</indexterm>
<indexterm>
<primary>lower_inc</primary>
</indexterm>
<indexterm>
<primary>upper_inc</primary>
</indexterm>
<indexterm>
<primary>lower_inf</primary>
</indexterm>
<indexterm>
<primary>upper_inf</primary>
</indexterm>
<table id="range-functions-table">
<title>Range Functions</title>
<tgroup cols="5">
<thead>
<row>
<entry>Function</entry>
<entry>Return Type</entry>
<entry>Description</entry>
<entry>Example</entry>
<entry>Result</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<literal>
<function>lower</function>(<type>anyrange</type>)
</literal>
</entry>
<entry><type>anyrange</type></entry>
<entry>lower bound of range</entry>
<entry><literal>lower(numrange(1.1,2.2))</literal></entry>
<entry><literal>1.1</literal></entry>
</row>
<row>
<entry>
<literal>
<function>upper</function>(<type>anyrange</type>)
</literal>
</entry>
<entry><type>anyrange</type></entry>
<entry>upper bound of range</entry>
<entry><literal>upper(numrange(1.1,2.2))</literal></entry>
<entry><literal>2.2</literal></entry>
</row>
<row>
<entry>
<literal>
<function>empty</function>(<type>anyrange</type>)
</literal>
</entry>
<entry><type>anyrange</type></entry>
<entry>is the range empty?</entry>
<entry><literal>empty(numrange(1.1,2.2))</literal></entry>
<entry><literal>false</literal></entry>
</row>
<row>
<entry>
<literal>
<function>non_empty</function>(<type>anyrange</type>)
</literal>
</entry>
<entry><type>anyrange</type></entry>
<entry>is the range non-empty?</entry>
<entry><literal>non_empty(numrange(1.1,2.2))</literal></entry>
<entry><literal>true</literal></entry>
</row>
<row>
<entry>
<literal>
<function>lower_inc</function>(<type>anyrange</type>)
</literal>
</entry>
<entry><type>anyrange</type></entry>
<entry>is the lower bound of the range inclusive?</entry>
<entry><literal>lower_inc(numrange(1.1,2.2))</literal></entry>
<entry><literal>true</literal></entry>
</row>
<row>
<entry>
<literal>
<function>upper_inc</function>(<type>anyrange</type>)
</literal>
</entry>
<entry><type>anyrange</type></entry>
<entry>is the upper bound of the range inclusive?</entry>
<entry><literal>upper_inc(numrange(1.1,2.2))</literal></entry>
<entry><literal>false</literal></entry>
</row>
<row>
<entry>
<literal>
<function>lower_inf</function>(<type>anyrange</type>)
</literal>
</entry>
<entry><type>anyrange</type></entry>
<entry>is the lower bound of the range infinite?</entry>
<entry><literal>lower_inf('(,)'::daterange)</literal></entry>
<entry><literal>true</literal></entry>
</row>
<row>
<entry>
<literal>
<function>upper_inf</function>(<type>anyrange</type>)
</literal>
</entry>
<entry><type>anyrange</type></entry>
<entry>is the upper bound of the range infinite?</entry>
<entry><literal>upper_inf('(,)'::daterange)</literal></entry>
<entry><literal>true</literal></entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1 id="functions-aggregate">
<title>Aggregate Functions</title>
......
......@@ -139,7 +139,7 @@
<application>PL/pgSQL</> functions can also be declared to accept
and return the polymorphic types
<type>anyelement</type>, <type>anyarray</type>, <type>anynonarray</type>,
and <type>anyenum</>. The actual
<type>anyenum</>, and <type>anyrange</type>. The actual
data types handled by a polymorphic function can vary from call to
call, as discussed in <xref linkend="extend-types-polymorphic">.
An example is shown in <xref linkend="plpgsql-declaration-parameters">.
......@@ -500,8 +500,8 @@ $$ LANGUAGE plpgsql;
<para>
When the return type of a <application>PL/pgSQL</application>
function is declared as a polymorphic type (<type>anyelement</type>,
<type>anyarray</type>, <type>anynonarray</type>, or <type>anyenum</>),
a special parameter <literal>$0</literal>
<type>anyarray</type>, <type>anynonarray</type>, <type>anyenum</type>,
or <type>anyrange</type>), a special parameter <literal>$0</literal>
is created. Its data type is the actual return type of the function,
as deduced from the actual input types (see <xref
linkend="extend-types-polymorphic">).
......
This diff is collapsed.
......@@ -27,6 +27,15 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> AS
CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
( [ '<replaceable class="parameter">label</replaceable>' [, ... ] ] )
CREATE TYPE <replaceable class="parameter">name</replaceable> AS RANGE (
SUBTYPE = <replaceable class="parameter">subtype</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> ]
)
CREATE TYPE <replaceable class="parameter">name</replaceable> (
INPUT = <replaceable class="parameter">input_function</replaceable>,
OUTPUT = <replaceable class="parameter">output_function</replaceable>
......@@ -98,11 +107,61 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
</para>
</refsect2>
<refsect2 id="SQL-CREATETYPE-RANGE">
<title>Range Types</title>
<para>
The third form of <command>CREATE TYPE</command> creates a new
range type, as described in <xref linkend="rangetypes">.
</para>
<para>
The <replaceable class="parameter">subtype</replaceable> parameter
can be any type with an associated btree opclass (uses the type's
default btree operator class unless specified with
<replaceable class="parameter">subtype_operator_class</replaceable>).
</para>
<para>
The <replaceable class="parameter">subtype_diff</replaceable>
function takes two values of type
<replaceable class="parameter">subtype</replaceable> as argument, and
returns the distance between the two values as
<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
a <replaceable class="parameter">canonical</replaceable> function,
you must first create a <firstterm>shell type</>, which is a
placeholder type that has no properties except a name and an
owner. This is done by issuing the command <literal>CREATE TYPE
<replaceable>name</></literal>, with no additional parameters.
</para>
<para>
The <replaceable class="parameter">analyze</replaceable>
function is the same as for creating a base type.
</para>
<para>
The <replaceable class="parameter">collation</replaceable> option
specifies the collation used when determining the total order for
the range.
</para>
</refsect2>
<refsect2>
<title>Base Types</title>
<para>
The third form of <command>CREATE TYPE</command> creates a new base type
The fourth form of <command>CREATE TYPE</command> creates a new base type
(scalar type). To create a new base type, you must be a superuser.
(This restriction is made because an erroneous type definition could
confuse or even crash the server.)
......
......@@ -997,8 +997,8 @@ $$ LANGUAGE SQL;
<para>
<acronym>SQL</acronym> functions can be declared to accept and
return the polymorphic types <type>anyelement</type>,
<type>anyarray</type>, <type>anynonarray</type>, and
<type>anyenum</type>. See <xref
<type>anyarray</type>, <type>anynonarray</type>,
<type>anyenum</type>, and <type>anyrange</type>. See <xref
linkend="extend-types-polymorphic"> for a more detailed
explanation of polymorphic functions. Here is a polymorphic
function <function>make_array</function> that builds up an array
......@@ -3046,7 +3046,7 @@ CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
C-language functions can be declared to accept and
return the polymorphic types
<type>anyelement</type>, <type>anyarray</type>, <type>anynonarray</type>,
and <type>anyenum</type>.
<type>anyenum</type>, and <type>anyrange</type>.
See <xref linkend="extend-types-polymorphic"> for a more detailed explanation
of polymorphic functions. When function arguments or return types
are defined as polymorphic types, the function author cannot know
......
......@@ -13,8 +13,8 @@ include $(top_builddir)/src/Makefile.global
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
pg_operator.o pg_proc.o pg_db_role_setting.o pg_shdepend.o pg_type.o \
storage.o toasting.o
pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \
pg_type.o storage.o toasting.o
BKIFILES = postgres.bki postgres.description postgres.shdescription
......@@ -39,7 +39,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_ts_parser.h pg_ts_template.h pg_extension.h \
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
pg_foreign_table.h \
pg_default_acl.h pg_seclabel.h pg_shseclabel.h pg_collation.h \
pg_default_acl.h pg_seclabel.h pg_shseclabel.h pg_collation.h pg_range.h \
toasting.h indexing.h \
)
......
......@@ -91,8 +91,11 @@ ProcedureCreate(const char *procedureName,
int parameterCount;
int allParamCount;
Oid *allParams;
char *modes = NULL;
bool genericInParam = false;
bool genericOutParam = false;
bool anyrangeInParam = false;
bool anyrangeOutParam = false;
bool internalInParam = false;
bool internalOutParam = false;
Oid variadicType = InvalidOid;
......@@ -152,6 +155,24 @@ ProcedureCreate(const char *procedureName,
allParams = parameterTypes->values;
}
if (parameterModes != PointerGetDatum(NULL))
{
/*
* We expect the array to be a 1-D CHAR array; verify that. We don't
* need to use deconstruct_array() since the array data is just going
* to look like a C array of char values.
*/
ArrayType *modesArray = (ArrayType *) DatumGetPointer(parameterModes);
if (ARR_NDIM(modesArray) != 1 ||
ARR_DIMS(modesArray)[0] != allParamCount ||
ARR_HASNULL(modesArray) ||
ARR_ELEMTYPE(modesArray) != CHAROID)
elog(ERROR, "parameterModes is not a 1-D char array");
modes = (char *) ARR_DATA_PTR(modesArray);
}
/*
* Do not allow polymorphic return type unless at least one input argument
* is polymorphic. Also, do not allow return type INTERNAL unless at
......@@ -161,6 +182,9 @@ ProcedureCreate(const char *procedureName,
{
switch (parameterTypes->values[i])
{
case ANYRANGEOID:
anyrangeInParam = true;
/* FALL THROUGH */
case ANYARRAYOID:
case ANYELEMENTOID:
case ANYNONARRAYOID:
......@@ -177,14 +201,17 @@ ProcedureCreate(const char *procedureName,
{
for (i = 0; i < allParamCount; i++)
{
/*
* We don't bother to distinguish input and output params here, so
* if there is, say, just an input INTERNAL param then we will
* still set internalOutParam. This is OK since we don't really
* care.
*/
if (modes == NULL ||
(modes[i] != PROARGMODE_OUT &&
modes[i] != PROARGMODE_INOUT &&
modes[i] != PROARGMODE_TABLE))
continue;
switch (allParams[i])
{
case ANYRANGEOID:
anyrangeOutParam = true;
/* FALL THROUGH */
case ANYARRAYOID:
case ANYELEMENTOID:
case ANYNONARRAYOID:
......@@ -205,6 +232,13 @@ ProcedureCreate(const char *procedureName,
errmsg("cannot determine result data type"),
errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));
if ((returnType == ANYRANGEOID || anyrangeOutParam) &&
!anyrangeInParam)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("cannot determine result data type"),
errdetail("A function returning ANYRANGE must have at least one ANYRANGE argument.")));
if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
......@@ -225,23 +259,8 @@ ProcedureCreate(const char *procedureName,
procedureName,
format_type_be(parameterTypes->values[0]))));
if (parameterModes != PointerGetDatum(NULL))
if (modes != NULL)
{
/*
* We expect the array to be a 1-D CHAR array; verify that. We don't
* need to use deconstruct_array() since the array data is just going
* to look like a C array of char values.
*/
ArrayType *modesArray = (ArrayType *) DatumGetPointer(parameterModes);
char *modes;
if (ARR_NDIM(modesArray) != 1 ||
ARR_DIMS(modesArray)[0] != allParamCount ||
ARR_HASNULL(modesArray) ||
ARR_ELEMTYPE(modesArray) != CHAROID)
elog(ERROR, "parameterModes is not a 1-D char array");
modes = (char *) ARR_DATA_PTR(modesArray);
/*
* Only the last input parameter can be variadic; if it is, save its
* element type. Errors here are just elog since caller should have
......
/*-------------------------------------------------------------------------
*
* pg_range.c
* routines to support manipulation of the pg_range relation
*
* Copyright (c) 2006-2010, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
* src/backend/catalog/pg_range.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_range.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/tqual.h"
#include "utils/rel.h"
/*
* RangeCreate
* Create an entry in pg_range.
*/
void
RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation,
Oid rangeSubOpclass, RegProcedure rangeCanonical,
RegProcedure rangeSubDiff)
{
Relation pg_range;
Datum values[Natts_pg_range];
bool nulls[Natts_pg_range];
HeapTuple tup;
ObjectAddress myself;
ObjectAddress referenced;
pg_range = heap_open(RangeRelationId, RowExclusiveLock);
memset(nulls, 0, Natts_pg_range * sizeof(bool));
values[Anum_pg_range_rngtypid - 1] = ObjectIdGetDatum(rangeTypeOid);
values[Anum_pg_range_rngsubtype - 1] = ObjectIdGetDatum(rangeSubType);
values[Anum_pg_range_rngcollation - 1] = ObjectIdGetDatum(rangeCollation);
values[Anum_pg_range_rngsubopc - 1] = ObjectIdGetDatum(rangeSubOpclass);
values[Anum_pg_range_rngcanonical - 1] = ObjectIdGetDatum(rangeCanonical);
values[Anum_pg_range_rngsubdiff - 1] = ObjectIdGetDatum(rangeSubDiff);
tup = heap_form_tuple(RelationGetDescr(pg_range), values, nulls);
simple_heap_insert(pg_range, tup);
CatalogUpdateIndexes(pg_range, tup);
heap_freetuple(tup);
/* record dependencies */
myself.classId = TypeRelationId;
myself.objectId = rangeTypeOid;
myself.objectSubId = 0;
referenced.classId = TypeRelationId;
referenced.objectId = rangeSubType;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
referenced.classId = OperatorClassRelationId;
referenced.objectId = rangeSubOpclass;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
if (OidIsValid(rangeCollation))
{
referenced.classId = CollationRelationId;
referenced.objectId = rangeCollation;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
if (OidIsValid(rangeCanonical))
{
referenced.classId = ProcedureRelationId;
referenced.objectId = rangeCanonical;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
if (OidIsValid(rangeSubDiff))
{
referenced.classId = ProcedureRelationId;
referenced.objectId = rangeSubDiff;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
heap_close(pg_range, RowExclusiveLock);
}
/*
* RangeDelete
* Remove the pg_range entry.
*/
void
RangeDelete(Oid rangeTypeOid)
{
Relation pg_range;
ScanKeyData key[1];
SysScanDesc scan;
HeapTuple tup;
pg_range = heap_open(RangeRelationId, RowExclusiveLock);
ScanKeyInit(&key[0],
Anum_pg_range_rngtypid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(rangeTypeOid));
scan = systable_beginscan(pg_range, RangeTypidIndexId, true,
SnapshotNow, 1, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
simple_heap_delete(pg_range, &tup->t_self);
}
systable_endscan(scan);
heap_close(pg_range, RowExclusiveLock);
}
This diff is collapsed.
......@@ -1352,6 +1352,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
if (fn_typtype == TYPTYPE_BASE ||
fn_typtype == TYPTYPE_DOMAIN ||
fn_typtype == TYPTYPE_ENUM ||
fn_typtype == TYPTYPE_RANGE ||
rettype == VOIDOID)
{
/*
......
......@@ -3055,6 +3055,17 @@ _copyCreateEnumStmt(CreateEnumStmt *from)
return newnode;
}
static CreateRangeStmt *
_copyCreateRangeStmt(CreateRangeStmt *from)
{
CreateRangeStmt *newnode = makeNode(CreateRangeStmt);
COPY_NODE_FIELD(typeName);
COPY_NODE_FIELD(params);
return newnode;
}
static AlterEnumStmt *
_copyAlterEnumStmt(AlterEnumStmt *from)
{
......@@ -4297,6 +4308,9 @@ copyObject(void *from)
case T_CreateEnumStmt:
retval = _copyCreateEnumStmt(from);
break;
case T_CreateRangeStmt:
retval = _copyCreateRangeStmt(from);
break;
case T_AlterEnumStmt:
retval = _copyAlterEnumStmt(from);
break;
......
......@@ -1438,6 +1438,15 @@ _equalCreateEnumStmt(CreateEnumStmt *a, CreateEnumStmt *b)
return true;
}
static bool
_equalCreateRangeStmt(CreateRangeStmt *a, CreateRangeStmt *b)
{
COMPARE_NODE_FIELD(typeName);
COMPARE_NODE_FIELD(params);
return true;
}
static bool
_equalAlterEnumStmt(AlterEnumStmt *a, AlterEnumStmt *b)
{
......@@ -2826,6 +2835,9 @@ equal(void *a, void *b)
case T_CreateEnumStmt:
retval = _equalCreateEnumStmt(a, b);
break;
case T_CreateRangeStmt:
retval = _equalCreateRangeStmt(a, b);
break;
case T_AlterEnumStmt:
retval = _equalAlterEnumStmt(a, b);
break;
......
......@@ -4336,6 +4336,13 @@ DefineStmt:
n->vals = $7;
$$ = (Node *)n;
}
| CREATE TYPE_P any_name AS RANGE definition
{
CreateRangeStmt *n = makeNode(CreateRangeStmt);
n->typeName = $3;
n->params = $6;
$$ = (Node *)n;
}
| CREATE TEXT_P SEARCH PARSER any_name definition
{
DefineStmt *n = makeNode(DefineStmt);
......
This diff is collapsed.
......@@ -202,6 +202,7 @@ check_xact_readonly(Node *parsetree)
case T_CreateTrigStmt:
case T_CompositeTypeStmt:
case T_CreateEnumStmt:
case T_CreateRangeStmt:
case T_AlterEnumStmt:
case T_ViewStmt:
case T_DropCastStmt:
......@@ -870,6 +871,10 @@ standard_ProcessUtility(Node *parsetree,
DefineEnum((CreateEnumStmt *) parsetree);
break;
case T_CreateRangeStmt:
DefineRange((CreateRangeStmt *) parsetree);
break;
case T_AlterEnumStmt: /* ALTER TYPE (enum) */
/*
......@@ -1854,6 +1859,10 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE TYPE";
break;
case T_CreateRangeStmt:
tag = "CREATE TYPE";
break;
case T_AlterEnumStmt:
tag = "ALTER TYPE";
break;
......@@ -2401,6 +2410,10 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL;
break;
case T_CreateRangeStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterEnumStmt:
lev = LOGSTMT_DDL;
break;
......
......@@ -20,8 +20,8 @@ OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
enum.o float.o format_type.o \
geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o \
misc.o nabstime.o name.o numeric.o numutils.o \
oid.o oracle_compat.o pseudotypes.o rowtypes.o \
regexp.o regproc.o ruleutils.o selfuncs.o \
oid.o oracle_compat.o pseudotypes.o rangetypes.o rangetypes_gist.o \
rowtypes.o regexp.o regproc.o ruleutils.o selfuncs.o \
tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \
network.o mac.o inet_cidr_ntop.o inet_net_pton.o \
ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
......
......@@ -889,7 +889,6 @@ date_timestamp(PG_FUNCTION_ARGS)
PG_RETURN_TIMESTAMP(result);
}
/* timestamp_date()
* Convert timestamp to date data type.
*/
......
......@@ -25,6 +25,7 @@
#include "libpq/pqformat.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/rangetypes.h"
/*
......@@ -187,6 +188,29 @@ anyenum_out(PG_FUNCTION_ARGS)
return enum_out(fcinfo);
}
/*
* anyrange_in - input routine for pseudo-type ANYRANGE.
*/
Datum
anyrange_in(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type anyrange")));
PG_RETURN_VOID(); /* keep compiler quiet */
}
/*
* anyrange_out - output routine for pseudo-type ANYRANGE.
*
* We may as well allow this, since range_out will in fact work.
*/
Datum
anyrange_out(PG_FUNCTION_ARGS)
{
return range_out(fcinfo);
}
/*
* void_in - input routine for pseudo-type VOID.
......
This diff is collapsed.
This diff is collapsed.
......@@ -26,6 +26,7 @@
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_range.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
......@@ -2250,6 +2251,16 @@ type_is_enum(Oid typid)
return (get_typtype(typid) == TYPTYPE_ENUM);
}
/*
* type_is_range
* Returns true if the given type is an range type.
*/
bool
type_is_range(Oid typid)
{
return (get_typtype(typid) == TYPTYPE_RANGE);
}
/*
* get_type_category_preferred
*
......@@ -2855,3 +2866,22 @@ get_namespace_name(Oid nspid)
else
return NULL;
}
Oid
get_range_subtype(Oid rangeOid)
{
HeapTuple tp;
tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
if (HeapTupleIsValid(tp))
{
Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
Oid result;
result = rngtup->rngsubtype;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
......@@ -43,6 +43,7 @@
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_range.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_tablespace.h"
......@@ -554,6 +555,17 @@ static const struct cachedesc cacheinfo[] = {
},
2048
},
{RangeRelationId, /* RANGETYPE */
RangeTypidIndexId,
1,
{
Anum_pg_range_rngtypid,
0,
0,
0
},
1024
},
{RelationRelationId, /* RELNAMENSP */
ClassNameNspIndexId,
2,
......
This diff is collapsed.
This diff is collapsed.
......@@ -53,6 +53,7 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201110221
/* COMMITTER: please set appropriately */
#define CATALOG_VERSION_NO 201111111
#endif
......@@ -303,6 +303,9 @@ DECLARE_UNIQUE_INDEX(pg_extension_oid_index, 3080, on pg_extension using btree(o
DECLARE_UNIQUE_INDEX(pg_extension_name_index, 3081, on pg_extension using btree(extname name_ops));
#define ExtensionNameIndexId 3081
DECLARE_UNIQUE_INDEX(pg_range_rgntypid_index, 3542, on pg_range using btree(rngtypid oid_ops));
#define RangeTypidIndexId 3542
/* last step of initialization script: build the indexes declared above */
BUILD_INDICES
......
This diff is collapsed.
This diff is collapsed.
......@@ -213,5 +213,8 @@ DATA(insert ( 783 tsvector_ops PGNSP PGUID 3655 3614 t 3642 ));
DATA(insert ( 2742 tsvector_ops PGNSP PGUID 3659 3614 t 25 ));
DATA(insert ( 403 tsquery_ops PGNSP PGUID 3683 3615 t 0 ));
DATA(insert ( 783 tsquery_ops PGNSP PGUID 3702 3615 t 20 ));
DATA(insert ( 403 range_ops PGNSP PGUID 3901 3831 t 0 ));
DATA(insert ( 405 range_ops PGNSP PGUID 3903 3831 t 0 ));
DATA(insert ( 783 range_ops PGNSP PGUID 3919 3831 t 0 ));
#endif /* PG_OPCLASS_H */
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