Support enum data types. Along the way, use macros for the values of
pg_type.typtype whereever practical. Tom Dunstan, with some kibitzing from Tom Lane.
This commit is contained in:
parent
a482a3e58b
commit
57690c6803
|
@ -1,4 +1,4 @@
|
||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.148 2007/03/26 16:58:37 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.149 2007/04/02 03:49:36 tgl Exp $ -->
|
||||||
<!--
|
<!--
|
||||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||||
-->
|
-->
|
||||||
|
@ -128,6 +128,11 @@
|
||||||
<entry>descriptions or comments on database objects</entry>
|
<entry>descriptions or comments on database objects</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><link linkend="catalog-pg-enum"><structname>pg_enum</structname></link></entry>
|
||||||
|
<entry>enum label and value definitions</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><link linkend="catalog-pg-index"><structname>pg_index</structname></link></entry>
|
<entry><link linkend="catalog-pg-index"><structname>pg_index</structname></link></entry>
|
||||||
<entry>additional index information</entry>
|
<entry>additional index information</entry>
|
||||||
|
@ -1425,11 +1430,7 @@
|
||||||
in which the source and target types are the same, if the associated
|
in which the source and target types are the same, if the associated
|
||||||
function takes more than one argument. Such entries represent
|
function takes more than one argument. Such entries represent
|
||||||
<quote>length coercion functions</> that coerce values of the type
|
<quote>length coercion functions</> that coerce values of the type
|
||||||
to be legal for a particular type modifier value. Note however that
|
to be legal for a particular type modifier value.
|
||||||
at present there is no support for associating non-default type
|
|
||||||
modifiers with user-created data types, and so this facility is only
|
|
||||||
of use for the small number of built-in types that have type modifier
|
|
||||||
syntax built into the grammar.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -2413,6 +2414,55 @@
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
|
||||||
|
<sect1 id="catalog-pg-enum">
|
||||||
|
<title><structname>pg_enum</structname></title>
|
||||||
|
|
||||||
|
<indexterm zone="catalog-pg-enum">
|
||||||
|
<primary>pg_enum</primary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <structname>pg_enum</structname> catalog contains entries
|
||||||
|
matching enum types to their associated values and labels. The
|
||||||
|
internal representation of a given enum value is actually the OID
|
||||||
|
of its associated row in <structname>pg_enum</structname>. The
|
||||||
|
OIDs for a particular enum type are guaranteed to be ordered in
|
||||||
|
the way the type should sort, but there is no guarantee about the
|
||||||
|
ordering of OIDs of unrelated enum types.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<title><structname>pg_enum</> 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>enumtypid</structfield></entry>
|
||||||
|
<entry><type>oid</type></entry>
|
||||||
|
<entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
|
||||||
|
<entry>The OID of the <structname>pg_type</> entry owning this enum value</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>enumlabel</structfield></entry>
|
||||||
|
<entry><type>name</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>The textual label for this enum value</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="catalog-pg-index">
|
<sect1 id="catalog-pg-index">
|
||||||
<title><structname>pg_index</structname></title>
|
<title><structname>pg_index</structname></title>
|
||||||
|
|
||||||
|
@ -4395,11 +4445,13 @@
|
||||||
<entry><type>char</type></entry>
|
<entry><type>char</type></entry>
|
||||||
<entry></entry>
|
<entry></entry>
|
||||||
<entry>
|
<entry>
|
||||||
<structfield>typtype</structfield> is <literal>b</literal> for
|
<structfield>typtype</structfield> is
|
||||||
a base type, <literal>c</literal> for a composite type (e.g., a
|
<literal>b</literal> for a base type,
|
||||||
table's row type), <literal>d</literal> for a domain, or
|
<literal>c</literal> for a composite type (e.g., a table's row type),
|
||||||
<literal>p</literal> for a pseudo-type. See also
|
<literal>d</literal> for a domain,
|
||||||
<structfield>typrelid</structfield> and
|
<literal>e</literal> for an enum type,
|
||||||
|
or <literal>p</literal> for a pseudo-type.
|
||||||
|
See also <structfield>typrelid</structfield> and
|
||||||
<structfield>typbasetype</structfield>
|
<structfield>typbasetype</structfield>
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.191 2007/03/14 17:38:05 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.192 2007/04/02 03:49:36 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="datatype">
|
<chapter id="datatype">
|
||||||
<title id="datatype-title">Data Types</title>
|
<title id="datatype-title">Data Types</title>
|
||||||
|
@ -2424,6 +2424,161 @@ SELECT * FROM test1 WHERE a;
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
<sect1 id="datatype-enum">
|
||||||
|
<title>Enumerated Types</title>
|
||||||
|
|
||||||
|
<indexterm zone="datatype-enum">
|
||||||
|
<primary>data type</primary>
|
||||||
|
<secondary>enumerated (enum)</secondary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Enumerated (enum) types are data types that
|
||||||
|
are comprised of a static, predefined set of values with a
|
||||||
|
specific order. They are equivalent to the <type>enum</type>
|
||||||
|
types in a number of programming languages. An example of an enum
|
||||||
|
type might be the days of the week, or a set of status values for
|
||||||
|
a piece of data.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Declaration of Enumerated Types</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Enum types are created using the <xref
|
||||||
|
linkend="sql-createtype" endterm="sql-createtype-title"> command,
|
||||||
|
for example:
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
Once created, the enum type can be used in table and function
|
||||||
|
definitions much like any other type:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title>Basic Enum Usage</title>
|
||||||
|
<programlisting>
|
||||||
|
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
|
||||||
|
CREATE TABLE person (
|
||||||
|
name text,
|
||||||
|
current_mood mood
|
||||||
|
);
|
||||||
|
INSERT INTO person VALUES ('Moe', 'happy');
|
||||||
|
SELECT * FROM person WHERE current_mood = 'happy';
|
||||||
|
name | current_mood
|
||||||
|
------+--------------
|
||||||
|
Moe | happy
|
||||||
|
(1 row)
|
||||||
|
</programlisting>
|
||||||
|
</example>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Ordering</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The ordering of the values in an enum type is the
|
||||||
|
order in which the values were listed when the type was declared.
|
||||||
|
All standard comparison operators and related
|
||||||
|
aggregate functions are supported for enums. For example:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title>Enum Ordering</title>
|
||||||
|
<programlisting>
|
||||||
|
INSERT INTO person VALUES ('Larry', 'sad');
|
||||||
|
INSERT INTO person VALUES ('Curly', 'ok');
|
||||||
|
SELECT * FROM person WHERE current_mood > 'sad';
|
||||||
|
name | current_mood
|
||||||
|
-------+--------------
|
||||||
|
Moe | happy
|
||||||
|
Curly | ok
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT * FROM person WHERE current_mood > 'sad' ORDER BY current_mood;
|
||||||
|
name | current_mood
|
||||||
|
-------+--------------
|
||||||
|
Curly | ok
|
||||||
|
Moe | happy
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT name FROM person
|
||||||
|
WHERE current_mood = (SELECT MIN(current_mood) FROM person);
|
||||||
|
name
|
||||||
|
-------
|
||||||
|
Larry
|
||||||
|
(1 row)
|
||||||
|
</programlisting>
|
||||||
|
</example>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Type Safety</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Enumerated types are completely separate data types and may not
|
||||||
|
be compared with each other.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title>Lack of Casting</title>
|
||||||
|
<programlisting>
|
||||||
|
CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
|
||||||
|
CREATE TABLE holidays (
|
||||||
|
num_weeks int,
|
||||||
|
happiness happiness
|
||||||
|
);
|
||||||
|
INSERT INTO holidays(num_weeks,happiness) VALUES (4, 'happy');
|
||||||
|
INSERT INTO holidays(num_weeks,happiness) VALUES (6, 'very happy');
|
||||||
|
INSERT INTO holidays(num_weeks,happiness) VALUES (8, 'ecstatic');
|
||||||
|
INSERT INTO holidays(num_weeks,happiness) VALUES (2, 'sad');
|
||||||
|
ERROR: invalid input value for enum happiness: "sad"
|
||||||
|
SELECT person.name, holidays.num_weeks FROM person, holidays
|
||||||
|
WHERE person.current_mood = holidays.happiness;
|
||||||
|
ERROR: operator does not exist: mood = happiness
|
||||||
|
</programlisting>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If you really need to do something like that, you can either
|
||||||
|
write a custom operator or add explicit casts to your query:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title>Comparing Different Enums by Casting to Text</title>
|
||||||
|
<programlisting>
|
||||||
|
SELECT person.name, holidays.num_weeks FROM person, holidays
|
||||||
|
WHERE person.current_mood::text = holidays.happiness::text;
|
||||||
|
name | num_weeks
|
||||||
|
------+-----------
|
||||||
|
Moe | 4
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
</programlisting>
|
||||||
|
</example>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>Implementation Details</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
An enum value occupies four bytes on disk. The length of an enum
|
||||||
|
value's textual label is limited by the <symbol>NAMEDATALEN</symbol>
|
||||||
|
setting compiled into <productname>PostgreSQL</productname>; in standard
|
||||||
|
builds this means at most 63 bytes.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Enum labels are case sensitive, so
|
||||||
|
<type>'happy'</type> is not the same as <type>'HAPPY'</type>.
|
||||||
|
Spaces in the labels are significant, too.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</sect2>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="datatype-geometric">
|
<sect1 id="datatype-geometric">
|
||||||
<title>Geometric Types</title>
|
<title>Geometric Types</title>
|
||||||
|
|
||||||
|
@ -3278,6 +3433,10 @@ SELECT * FROM pg_attribute
|
||||||
<primary>anyelement</primary>
|
<primary>anyelement</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
|
<indexterm zone="datatype-pseudo">
|
||||||
|
<primary>anyenum</primary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
<indexterm zone="datatype-pseudo">
|
<indexterm zone="datatype-pseudo">
|
||||||
<primary>void</primary>
|
<primary>void</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
@ -3343,6 +3502,13 @@ SELECT * FROM pg_attribute
|
||||||
(see <xref linkend="extend-types-polymorphic">).</entry>
|
(see <xref linkend="extend-types-polymorphic">).</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><type>anyenum</></entry>
|
||||||
|
<entry>Indicates that a function accepts any enum data type
|
||||||
|
(see <xref linkend="extend-types-polymorphic"> and
|
||||||
|
<xref linkend="datatype-enum">).</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><type>cstring</></entry>
|
<entry><type>cstring</></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>
|
||||||
|
@ -3395,8 +3561,8 @@ SELECT * FROM pg_attribute
|
||||||
languages all forbid use of a pseudo-type as argument type, and allow
|
languages all forbid use of a pseudo-type as argument type, and allow
|
||||||
only <type>void</> and <type>record</> as a result type (plus
|
only <type>void</> and <type>record</> as a result type (plus
|
||||||
<type>trigger</> when the function is used as a trigger). Some also
|
<type>trigger</> when the function is used as a trigger). Some also
|
||||||
support polymorphic functions using the types <type>anyarray</> and
|
support polymorphic functions using the types <type>anyarray</>,
|
||||||
<type>anyelement</>.
|
<type>anyelement</> and <type>anyenum</>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/extend.sgml,v 1.33 2007/01/31 20:56:17 momjian Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/extend.sgml,v 1.34 2007/04/02 03:49:36 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="extend">
|
<chapter id="extend">
|
||||||
<title>Extending <acronym>SQL</acronym></title>
|
<title>Extending <acronym>SQL</acronym></title>
|
||||||
|
@ -193,9 +193,10 @@
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Two pseudo-types of special interest are <type>anyelement</> and
|
Three pseudo-types of special interest are <type>anyelement</>,
|
||||||
<type>anyarray</>, which are collectively called <firstterm>polymorphic
|
<type>anyarray</>, and <type>anyenum</>,
|
||||||
types</>. Any function declared using these types is said to be
|
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
|
a <firstterm>polymorphic function</>. A polymorphic function can
|
||||||
operate on many different data types, with the specific data type(s)
|
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
|
being determined by the data types actually passed to it in a particular
|
||||||
|
@ -215,6 +216,9 @@
|
||||||
<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.
|
||||||
|
<type>anyenum</> is treated exactly the same as <type>anyelement</>,
|
||||||
|
but adds the additional constraint that the actual type must
|
||||||
|
be an enum type.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -234,7 +238,9 @@
|
||||||
implements subscripting as <literal>subscript(anyarray, integer)
|
implements subscripting as <literal>subscript(anyarray, integer)
|
||||||
returns anyelement</>. This declaration constrains the actual first
|
returns anyelement</>. This declaration constrains the actual first
|
||||||
argument to be an array type, and allows the parser to infer the correct
|
argument to be an array type, and allows the parser to infer the correct
|
||||||
result type from the actual first argument's type.
|
result type from the actual first argument's type. Another example
|
||||||
|
is that a function declared as <literal>f(anyarray) returns anyenum</>
|
||||||
|
will only accept arrays of enum types.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.372 2007/04/01 09:00:24 petere Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.373 2007/04/02 03:49:36 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="functions">
|
<chapter id="functions">
|
||||||
<title>Functions and Operators</title>
|
<title>Functions and Operators</title>
|
||||||
|
@ -6646,6 +6646,87 @@ SELECT pg_sleep(1.5);
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
|
||||||
|
<sect1 id="functions-enum">
|
||||||
|
<title>Enum Support Functions</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For enum types (described in <xref linkend="datatype-enum">),
|
||||||
|
there are several functions that allow cleaner programming without
|
||||||
|
hard-coding particular values of an enum type.
|
||||||
|
These are listed in <xref linkend="functions-enum-table">. The examples
|
||||||
|
assume an enum type created as:
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<table id="functions-enum-table">
|
||||||
|
<title>Enum Support Functions</title>
|
||||||
|
<tgroup cols="4">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Function</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
<entry>Example</entry>
|
||||||
|
<entry>Example Result</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry><literal>enum_first(anyenum)</literal></entry>
|
||||||
|
<entry>Returns the first value of the input enum type</entry>
|
||||||
|
<entry><literal>enum_first(null::rainbow)</literal></entry>
|
||||||
|
<entry><literal>red</literal></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><literal>enum_last(anyenum)</literal></entry>
|
||||||
|
<entry>Returns the last value of the input enum type</entry>
|
||||||
|
<entry><literal>enum_last(null::rainbow)</literal></entry>
|
||||||
|
<entry><literal>purple</literal></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><literal>enum_range(anyenum)</literal></entry>
|
||||||
|
<entry>Returns all values of the input enum type in an ordered array</entry>
|
||||||
|
<entry><literal>enum_range(null::rainbow)</literal></entry>
|
||||||
|
<entry><literal>{red,orange,yellow,green,blue,purple}</literal></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry morerows="2"><literal>enum_range(anyenum, anyenum)</literal></entry>
|
||||||
|
<entry morerows="2">
|
||||||
|
Returns the range between the two given enum values, as an ordered
|
||||||
|
array. The values must be from the same enum type. If the first
|
||||||
|
parameter is null, the result will start with the first value of
|
||||||
|
the enum type.
|
||||||
|
If the second parameter is null, the result will end with the last
|
||||||
|
value of the enum type.
|
||||||
|
</entry>
|
||||||
|
<entry><literal>enum_range('orange'::rainbow, 'green'::rainbow)</literal></entry>
|
||||||
|
<entry><literal>{orange,yellow,green}</literal></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><literal>enum_range(NULL, 'green'::rainbow)</literal></entry>
|
||||||
|
<entry><literal>{red,orange,yellow,green}</literal></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><literal>enum_range('orange'::rainbow, NULL)</literal></entry>
|
||||||
|
<entry><literal>{orange,yellow,green,blue,purple}</literal></entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Notice that except for the two-argument form of <function>enum_range</>,
|
||||||
|
these functions disregard the specific value passed to them; they care
|
||||||
|
only about its declared datatype. Either NULL or a specific value of
|
||||||
|
the type can be passed, with the same result. It is more common to
|
||||||
|
apply these functions to a table column or function argument than to
|
||||||
|
a hardwired type name as suggested by the examples.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="functions-geometry">
|
<sect1 id="functions-geometry">
|
||||||
<title>Geometric Functions and Operators</title>
|
<title>Geometric Functions and Operators</title>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.105 2007/02/01 00:28:17 momjian Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.106 2007/04/02 03:49:37 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="plpgsql">
|
<chapter id="plpgsql">
|
||||||
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
|
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
|
||||||
|
@ -210,7 +210,8 @@ $$ LANGUAGE plpgsql;
|
||||||
<para>
|
<para>
|
||||||
<application>PL/pgSQL</> functions can also be declared to accept
|
<application>PL/pgSQL</> functions can also be declared to accept
|
||||||
and return the polymorphic types
|
and return the polymorphic types
|
||||||
<type>anyelement</type> and <type>anyarray</type>. The actual
|
<type>anyelement</type>, <type>anyarray</type>, and <type>anyenum</>.
|
||||||
|
The actual
|
||||||
data types handled by a polymorphic function can vary from call to
|
data types handled by a polymorphic function can vary from call to
|
||||||
call, as discussed in <xref linkend="extend-types-polymorphic">.
|
call, as discussed in <xref linkend="extend-types-polymorphic">.
|
||||||
An example is shown in <xref linkend="plpgsql-declaration-aliases">.
|
An example is shown in <xref linkend="plpgsql-declaration-aliases">.
|
||||||
|
@ -698,8 +699,9 @@ $$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
When the return type of a <application>PL/pgSQL</application>
|
When the return type of a <application>PL/pgSQL</application>
|
||||||
function is declared as a polymorphic type (<type>anyelement</type>
|
function is declared as a polymorphic type (<type>anyelement</type>,
|
||||||
or <type>anyarray</type>), a special parameter <literal>$0</literal>
|
<type>anyarray</type>, or <type>anyenum</>),
|
||||||
|
a special parameter <literal>$0</literal>
|
||||||
is created. Its data type is the actual return type of the function,
|
is created. Its data type is the actual return type of the function,
|
||||||
as deduced from the actual input types (see <xref
|
as deduced from the actual input types (see <xref
|
||||||
linkend="extend-types-polymorphic">).
|
linkend="extend-types-polymorphic">).
|
||||||
|
@ -726,7 +728,7 @@ $$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The same effect can be had by declaring one or more output parameters as
|
The same effect can be had by declaring one or more output parameters as
|
||||||
<type>anyelement</type> or <type>anyarray</type>. In this case the
|
polymorphic types. In this case the
|
||||||
special <literal>$0</literal> parameter is not used; the output
|
special <literal>$0</literal> parameter is not used; the output
|
||||||
parameters themselves serve the same purpose. For example:
|
parameters themselves serve the same purpose. For example:
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.68 2007/02/01 00:28:18 momjian Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.69 2007/04/02 03:49:37 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
@ -23,6 +23,9 @@ PostgreSQL documentation
|
||||||
CREATE TYPE <replaceable class="parameter">name</replaceable> AS
|
CREATE TYPE <replaceable class="parameter">name</replaceable> AS
|
||||||
( <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [, ... ] )
|
( <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [, ... ] )
|
||||||
|
|
||||||
|
CREATE TYPE <replaceable class="parameter">name</replaceable> AS ENUM
|
||||||
|
( '<replaceable class="parameter">label</replaceable>' [, ... ] )
|
||||||
|
|
||||||
CREATE TYPE <replaceable class="parameter">name</replaceable> (
|
CREATE TYPE <replaceable class="parameter">name</replaceable> (
|
||||||
INPUT = <replaceable class="parameter">input_function</replaceable>,
|
INPUT = <replaceable class="parameter">input_function</replaceable>,
|
||||||
OUTPUT = <replaceable class="parameter">output_function</replaceable>
|
OUTPUT = <replaceable class="parameter">output_function</replaceable>
|
||||||
|
@ -77,11 +80,23 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2>
|
||||||
|
<title>Enumerated Types</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The second form of <command>CREATE TYPE</command> creates an enumerated
|
||||||
|
(enum) type, as described in <xref linkend="datatype-enum">.
|
||||||
|
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
|
||||||
|
<productname>PostgreSQL</productname> build).
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Base Types</title>
|
<title>Base Types</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The second form of <command>CREATE TYPE</command> creates a new base type
|
The third form of <command>CREATE TYPE</command> creates a new base type
|
||||||
(scalar type). The parameters can appear in any order, not only that
|
(scalar type). The parameters can appear in any order, not only that
|
||||||
illustrated above, and most are optional. You must register
|
illustrated above, and most are optional. You must register
|
||||||
two or more functions (using <command>CREATE FUNCTION</command>) before
|
two or more functions (using <command>CREATE FUNCTION</command>) before
|
||||||
|
@ -297,7 +312,7 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
|
||||||
<title>Array Types</title>
|
<title>Array Types</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Whenever a user-defined base data type is created,
|
Whenever a user-defined base or enum data 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 base type's
|
||||||
name prepended with an underscore. The parser understands this
|
name prepended with an underscore. The parser understands this
|
||||||
|
@ -363,6 +378,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">label</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
A string literal representing the textual label associated with
|
||||||
|
one value of an enum type.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable class="parameter">input_function</replaceable></term>
|
<term><replaceable class="parameter">input_function</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -567,6 +592,20 @@ $$ LANGUAGE SQL;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This example creates an enumerated type and uses it in
|
||||||
|
a table definition:
|
||||||
|
<programlisting>
|
||||||
|
CREATE TYPE bug_status AS ENUM ('new', 'open', 'closed');
|
||||||
|
|
||||||
|
CREATE TABLE bug (
|
||||||
|
serial id,
|
||||||
|
description text,
|
||||||
|
status bug_status
|
||||||
|
);
|
||||||
|
</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:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.126 2007/02/27 23:48:06 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.127 2007/04/02 03:49:37 tgl Exp $ -->
|
||||||
|
|
||||||
<sect1 id="xfunc">
|
<sect1 id="xfunc">
|
||||||
<title>User-Defined Functions</title>
|
<title>User-Defined Functions</title>
|
||||||
|
@ -717,8 +717,8 @@ SELECT name, listchildren(name) FROM nodes;
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<acronym>SQL</acronym> functions can be declared to accept and
|
<acronym>SQL</acronym> functions can be declared to accept and
|
||||||
return the polymorphic types <type>anyelement</type> and
|
return the polymorphic types <type>anyelement</type>,
|
||||||
<type>anyarray</type>. See <xref
|
<type>anyarray</type>, and <type>anyenum</type>. See <xref
|
||||||
linkend="extend-types-polymorphic"> for a more detailed
|
linkend="extend-types-polymorphic"> for a more detailed
|
||||||
explanation of polymorphic functions. Here is a polymorphic
|
explanation of polymorphic functions. Here is a polymorphic
|
||||||
function <function>make_array</function> that builds up an array
|
function <function>make_array</function> that builds up an array
|
||||||
|
@ -746,7 +746,7 @@ SELECT make_array(1, 2) AS intarray, make_array('a'::text, 'b') AS textarray;
|
||||||
Without the typecast, you will get errors like this:
|
Without the typecast, you will get errors like this:
|
||||||
<screen>
|
<screen>
|
||||||
<computeroutput>
|
<computeroutput>
|
||||||
ERROR: could not determine "anyarray"/"anyelement" type because input has type "unknown"
|
ERROR: could not determine polymorphic type because input has type "unknown"
|
||||||
</computeroutput>
|
</computeroutput>
|
||||||
</screen>
|
</screen>
|
||||||
</para>
|
</para>
|
||||||
|
@ -769,7 +769,7 @@ CREATE FUNCTION invalid_func() RETURNS anyelement AS $$
|
||||||
SELECT 1;
|
SELECT 1;
|
||||||
$$ LANGUAGE SQL;
|
$$ LANGUAGE SQL;
|
||||||
ERROR: cannot determine result data type
|
ERROR: cannot determine result data type
|
||||||
DETAIL: A function returning "anyarray" or "anyelement" must have at least one argument of either type.
|
DETAIL: A function returning a polymorphic type must have at least one polymorphic argument.
|
||||||
</screen>
|
</screen>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -2831,7 +2831,7 @@ CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
|
||||||
<para>
|
<para>
|
||||||
C-language functions can be declared to accept and
|
C-language functions can be declared to accept and
|
||||||
return the polymorphic types
|
return the polymorphic types
|
||||||
<type>anyelement</type> and <type>anyarray</type>.
|
<type>anyelement</type>, <type>anyarray</type>, and <type>anyenum</type>.
|
||||||
See <xref linkend="extend-types-polymorphic"> for a more detailed explanation
|
See <xref linkend="extend-types-polymorphic"> for a more detailed explanation
|
||||||
of polymorphic functions. When function arguments or return types
|
of polymorphic functions. When function arguments or return types
|
||||||
are defined as polymorphic types, the function author cannot know
|
are defined as polymorphic types, the function author cannot know
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.50 2007/01/05 22:19:22 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.51 2007/04/02 03:49:37 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* These functions are stored in pg_amproc. For each operator class
|
* These functions are stored in pg_amproc. For each operator class
|
||||||
|
@ -72,6 +72,12 @@ hashoid(PG_FUNCTION_ARGS)
|
||||||
PG_RETURN_UINT32(~((uint32) PG_GETARG_OID(0)));
|
PG_RETURN_UINT32(~((uint32) PG_GETARG_OID(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
hashenum(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
PG_RETURN_UINT32(~((uint32) PG_GETARG_OID(0)));
|
||||||
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
hashfloat4(PG_FUNCTION_ARGS)
|
hashfloat4(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# Makefile for backend/catalog
|
# Makefile for backend/catalog
|
||||||
#
|
#
|
||||||
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.63 2007/02/09 15:55:58 petere Exp $
|
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.64 2007/04/02 03:49:37 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ top_builddir = ../../..
|
||||||
include $(top_builddir)/src/Makefile.global
|
include $(top_builddir)/src/Makefile.global
|
||||||
|
|
||||||
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
|
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
|
||||||
pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o \
|
pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
|
||||||
pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
|
pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
|
||||||
pg_type.o toasting.o
|
pg_type.o toasting.o
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
|
||||||
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
|
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
|
||||||
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
|
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
|
||||||
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
|
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
|
||||||
pg_namespace.h pg_conversion.h pg_depend.h \
|
pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
|
||||||
pg_database.h pg_tablespace.h pg_pltemplate.h \
|
pg_database.h pg_tablespace.h pg_pltemplate.h \
|
||||||
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
|
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
|
||||||
toasting.h indexing.h \
|
toasting.h indexing.h \
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.317 2007/02/14 01:58:56 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.318 2007/04/02 03:49:37 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
|
@ -412,7 +412,7 @@ CheckAttributeType(const char *attname, Oid atttypid)
|
||||||
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
||||||
errmsg("column \"%s\" has type \"unknown\"", attname),
|
errmsg("column \"%s\" has type \"unknown\"", attname),
|
||||||
errdetail("Proceeding with relation creation anyway.")));
|
errdetail("Proceeding with relation creation anyway.")));
|
||||||
else if (att_typtype == 'p')
|
else if (att_typtype == TYPTYPE_PSEUDO)
|
||||||
{
|
{
|
||||||
/* Special hack for pg_statistic: allow ANYARRAY during initdb */
|
/* Special hack for pg_statistic: allow ANYARRAY during initdb */
|
||||||
if (atttypid != ANYARRAYOID || IsUnderPostmaster)
|
if (atttypid != ANYARRAYOID || IsUnderPostmaster)
|
||||||
|
@ -718,7 +718,7 @@ AddNewRelationType(const char *typeName,
|
||||||
new_rel_oid, /* relation oid */
|
new_rel_oid, /* relation oid */
|
||||||
new_rel_kind, /* relation kind */
|
new_rel_kind, /* relation kind */
|
||||||
-1, /* internal size (varlena) */
|
-1, /* internal size (varlena) */
|
||||||
'c', /* type-type (complex) */
|
TYPTYPE_COMPOSITE, /* type-type (composite) */
|
||||||
',', /* default array delimiter */
|
',', /* default array delimiter */
|
||||||
F_RECORD_IN, /* input procedure */
|
F_RECORD_IN, /* input procedure */
|
||||||
F_RECORD_OUT, /* output procedure */
|
F_RECORD_OUT, /* output procedure */
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.85 2007/01/22 01:35:20 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.86 2007/04/02 03:49:37 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -80,8 +80,7 @@ AggregateCreate(const char *aggName,
|
||||||
hasPolyArg = false;
|
hasPolyArg = false;
|
||||||
for (i = 0; i < numArgs; i++)
|
for (i = 0; i < numArgs; i++)
|
||||||
{
|
{
|
||||||
if (aggArgTypes[i] == ANYARRAYOID ||
|
if (IsPolymorphicType(aggArgTypes[i]))
|
||||||
aggArgTypes[i] == ANYELEMENTOID)
|
|
||||||
{
|
{
|
||||||
hasPolyArg = true;
|
hasPolyArg = true;
|
||||||
break;
|
break;
|
||||||
|
@ -92,12 +91,11 @@ AggregateCreate(const char *aggName,
|
||||||
* If transtype is polymorphic, must have polymorphic argument also; else
|
* If transtype is polymorphic, must have polymorphic argument also; else
|
||||||
* we will have no way to deduce the actual transtype.
|
* we will have no way to deduce the actual transtype.
|
||||||
*/
|
*/
|
||||||
if (!hasPolyArg &&
|
if (IsPolymorphicType(aggTransType) && !hasPolyArg)
|
||||||
(aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID))
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||||
errmsg("cannot determine transition data type"),
|
errmsg("cannot determine transition data type"),
|
||||||
errdetail("An aggregate using \"anyarray\" or \"anyelement\" as transition type must have at least one argument of either type.")));
|
errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
|
||||||
|
|
||||||
/* find the transfn */
|
/* find the transfn */
|
||||||
nargs_transfn = numArgs + 1;
|
nargs_transfn = numArgs + 1;
|
||||||
|
@ -170,13 +168,12 @@ AggregateCreate(const char *aggName,
|
||||||
* that itself violates the rule against polymorphic result with no
|
* that itself violates the rule against polymorphic result with no
|
||||||
* polymorphic input.)
|
* polymorphic input.)
|
||||||
*/
|
*/
|
||||||
if (!hasPolyArg &&
|
if (IsPolymorphicType(finaltype) && !hasPolyArg)
|
||||||
(finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID))
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
errmsg("cannot determine result data type"),
|
errmsg("cannot determine result data type"),
|
||||||
errdetail("An aggregate returning \"anyarray\" or \"anyelement\" "
|
errdetail("An aggregate returning a polymorphic type "
|
||||||
"must have at least one argument of either type.")));
|
"must have at least one polymorphic argument.")));
|
||||||
|
|
||||||
/* handle sortop, if supplied */
|
/* handle sortop, if supplied */
|
||||||
if (aggsortopName)
|
if (aggsortopName)
|
||||||
|
@ -329,8 +326,7 @@ lookup_agg_function(List *fnName,
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < nargs; i++)
|
for (i = 0; i < nargs; i++)
|
||||||
{
|
{
|
||||||
if (input_types[i] != ANYARRAYOID &&
|
if (!IsPolymorphicType(input_types[i]))
|
||||||
input_types[i] != ANYELEMENTOID)
|
|
||||||
{
|
{
|
||||||
allPolyArgs = false;
|
allPolyArgs = false;
|
||||||
break;
|
break;
|
||||||
|
@ -351,8 +347,7 @@ lookup_agg_function(List *fnName,
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < nargs; i++)
|
for (i = 0; i < nargs; i++)
|
||||||
{
|
{
|
||||||
if (true_oid_array[i] != ANYARRAYOID &&
|
if (!IsPolymorphicType(true_oid_array[i]) &&
|
||||||
true_oid_array[i] != ANYELEMENTOID &&
|
|
||||||
!IsBinaryCoercible(input_types[i], true_oid_array[i]))
|
!IsBinaryCoercible(input_types[i], true_oid_array[i]))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* pg_enum.c
|
||||||
|
* routines to support manipulation of the pg_enum relation
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006-2007, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* IDENTIFICATION
|
||||||
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_enum.c,v 1.1 2007/04/02 03:49:37 tgl Exp $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "access/genam.h"
|
||||||
|
#include "access/heapam.h"
|
||||||
|
#include "catalog/catalog.h"
|
||||||
|
#include "catalog/indexing.h"
|
||||||
|
#include "catalog/pg_enum.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/fmgroids.h"
|
||||||
|
|
||||||
|
static int oid_cmp(const void *p1, const void *p2);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EnumValuesCreate
|
||||||
|
* Create an entry in pg_enum for each of the supplied enum values.
|
||||||
|
*
|
||||||
|
* vals is a list of Value strings.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
EnumValuesCreate(Oid enumTypeOid, List *vals)
|
||||||
|
{
|
||||||
|
Relation pg_enum;
|
||||||
|
TupleDesc tupDesc;
|
||||||
|
NameData enumlabel;
|
||||||
|
Oid *oids;
|
||||||
|
int i, n;
|
||||||
|
Datum values[Natts_pg_enum];
|
||||||
|
char nulls[Natts_pg_enum];
|
||||||
|
ListCell *lc;
|
||||||
|
HeapTuple tup;
|
||||||
|
|
||||||
|
n = list_length(vals);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX we do not bother to check the list of values for duplicates ---
|
||||||
|
* if you have any, you'll get a less-than-friendly unique-index
|
||||||
|
* violation. Is it worth trying harder?
|
||||||
|
*/
|
||||||
|
|
||||||
|
pg_enum = heap_open(EnumRelationId, RowExclusiveLock);
|
||||||
|
tupDesc = pg_enum->rd_att;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate oids. While this method does not absolutely guarantee
|
||||||
|
* that we generate no duplicate oids (since we haven't entered each
|
||||||
|
* oid into the table before allocating the next), trouble could only
|
||||||
|
* occur if the oid counter wraps all the way around before we finish.
|
||||||
|
* Which seems unlikely.
|
||||||
|
*/
|
||||||
|
oids = (Oid *) palloc(n * sizeof(Oid));
|
||||||
|
for(i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
oids[i] = GetNewOid(pg_enum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort them, just in case counter wrapped from high to low */
|
||||||
|
qsort(oids, n, sizeof(Oid), oid_cmp);
|
||||||
|
|
||||||
|
/* and make the entries */
|
||||||
|
memset(nulls, ' ', sizeof(nulls));
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
foreach(lc, vals)
|
||||||
|
{
|
||||||
|
char *lab = strVal(lfirst(lc));
|
||||||
|
|
||||||
|
values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
|
||||||
|
namestrcpy(&enumlabel, lab);
|
||||||
|
values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
|
||||||
|
|
||||||
|
tup = heap_formtuple(tupDesc, values, nulls);
|
||||||
|
HeapTupleSetOid(tup, oids[i]);
|
||||||
|
|
||||||
|
simple_heap_insert(pg_enum, tup);
|
||||||
|
CatalogUpdateIndexes(pg_enum, tup);
|
||||||
|
heap_freetuple(tup);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clean up */
|
||||||
|
pfree(oids);
|
||||||
|
heap_close(pg_enum, RowExclusiveLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EnumValuesDelete
|
||||||
|
* Remove all the pg_enum entries for the specified enum type.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
EnumValuesDelete(Oid enumTypeOid)
|
||||||
|
{
|
||||||
|
Relation pg_enum;
|
||||||
|
ScanKeyData key[1];
|
||||||
|
SysScanDesc scan;
|
||||||
|
HeapTuple tup;
|
||||||
|
|
||||||
|
pg_enum = heap_open(EnumRelationId, RowExclusiveLock);
|
||||||
|
|
||||||
|
ScanKeyInit(&key[0],
|
||||||
|
Anum_pg_enum_enumtypid,
|
||||||
|
BTEqualStrategyNumber, F_OIDEQ,
|
||||||
|
ObjectIdGetDatum(enumTypeOid));
|
||||||
|
|
||||||
|
scan = systable_beginscan(pg_enum, EnumTypIdLabelIndexId, true,
|
||||||
|
SnapshotNow, 1, key);
|
||||||
|
|
||||||
|
while (HeapTupleIsValid(tup = systable_getnext(scan)))
|
||||||
|
{
|
||||||
|
simple_heap_delete(pg_enum, &tup->t_self);
|
||||||
|
}
|
||||||
|
|
||||||
|
systable_endscan(scan);
|
||||||
|
|
||||||
|
heap_close(pg_enum, RowExclusiveLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* qsort comparison function */
|
||||||
|
static int
|
||||||
|
oid_cmp(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
Oid v1 = *((const Oid *) p1);
|
||||||
|
Oid v2 = *((const Oid *) p2);
|
||||||
|
|
||||||
|
if (v1 < v2)
|
||||||
|
return -1;
|
||||||
|
if (v1 > v2)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.143 2007/01/22 01:35:20 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.144 2007/04/02 03:49:37 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -137,9 +137,9 @@ ProcedureCreate(const char *procedureName,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do not allow return type ANYARRAY or ANYELEMENT unless at least one
|
* Do not allow polymorphic return type unless at least one input argument
|
||||||
* input argument is ANYARRAY or ANYELEMENT. Also, do not allow return
|
* is polymorphic. Also, do not allow return type INTERNAL unless at
|
||||||
* type INTERNAL unless at least one input argument is INTERNAL.
|
* least one input argument is INTERNAL.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < parameterCount; i++)
|
for (i = 0; i < parameterCount; i++)
|
||||||
{
|
{
|
||||||
|
@ -147,6 +147,7 @@ ProcedureCreate(const char *procedureName,
|
||||||
{
|
{
|
||||||
case ANYARRAYOID:
|
case ANYARRAYOID:
|
||||||
case ANYELEMENTOID:
|
case ANYELEMENTOID:
|
||||||
|
case ANYENUMOID:
|
||||||
genericInParam = true;
|
genericInParam = true;
|
||||||
break;
|
break;
|
||||||
case INTERNALOID:
|
case INTERNALOID:
|
||||||
|
@ -169,6 +170,7 @@ ProcedureCreate(const char *procedureName,
|
||||||
{
|
{
|
||||||
case ANYARRAYOID:
|
case ANYARRAYOID:
|
||||||
case ANYELEMENTOID:
|
case ANYELEMENTOID:
|
||||||
|
case ANYENUMOID:
|
||||||
genericOutParam = true;
|
genericOutParam = true;
|
||||||
break;
|
break;
|
||||||
case INTERNALOID:
|
case INTERNALOID:
|
||||||
|
@ -178,12 +180,12 @@ ProcedureCreate(const char *procedureName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((returnType == ANYARRAYOID || returnType == ANYELEMENTOID ||
|
if ((IsPolymorphicType(returnType) || genericOutParam)
|
||||||
genericOutParam) && !genericInParam)
|
&& !genericInParam)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||||
errmsg("cannot determine result data type"),
|
errmsg("cannot determine result data type"),
|
||||||
errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));
|
errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));
|
||||||
|
|
||||||
if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
|
if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -533,26 +535,24 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
|
||||||
proc = (Form_pg_proc) GETSTRUCT(tuple);
|
proc = (Form_pg_proc) GETSTRUCT(tuple);
|
||||||
|
|
||||||
/* Disallow pseudotype result */
|
/* Disallow pseudotype result */
|
||||||
/* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */
|
/* except for RECORD, VOID, or polymorphic */
|
||||||
if (get_typtype(proc->prorettype) == 'p' &&
|
if (get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
|
||||||
proc->prorettype != RECORDOID &&
|
proc->prorettype != RECORDOID &&
|
||||||
proc->prorettype != VOIDOID &&
|
proc->prorettype != VOIDOID &&
|
||||||
proc->prorettype != ANYARRAYOID &&
|
!IsPolymorphicType(proc->prorettype))
|
||||||
proc->prorettype != ANYELEMENTOID)
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||||
errmsg("SQL functions cannot return type %s",
|
errmsg("SQL functions cannot return type %s",
|
||||||
format_type_be(proc->prorettype))));
|
format_type_be(proc->prorettype))));
|
||||||
|
|
||||||
/* Disallow pseudotypes in arguments */
|
/* Disallow pseudotypes in arguments */
|
||||||
/* except for ANYARRAY or ANYELEMENT */
|
/* except for polymorphic */
|
||||||
haspolyarg = false;
|
haspolyarg = false;
|
||||||
for (i = 0; i < proc->pronargs; i++)
|
for (i = 0; i < proc->pronargs; i++)
|
||||||
{
|
{
|
||||||
if (get_typtype(proc->proargtypes.values[i]) == 'p')
|
if (get_typtype(proc->proargtypes.values[i]) == TYPTYPE_PSEUDO)
|
||||||
{
|
{
|
||||||
if (proc->proargtypes.values[i] == ANYARRAYOID ||
|
if (IsPolymorphicType(proc->proargtypes.values[i]))
|
||||||
proc->proargtypes.values[i] == ANYELEMENTOID)
|
|
||||||
haspolyarg = true;
|
haspolyarg = true;
|
||||||
else
|
else
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.110 2007/01/05 22:19:25 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.111 2007/04/02 03:49:37 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -75,7 +75,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
|
||||||
*
|
*
|
||||||
* The representational details are the same as int4 ... it doesn't really
|
* The representational details are the same as int4 ... it doesn't really
|
||||||
* matter what they are so long as they are consistent. Also note that we
|
* matter what they are so long as they are consistent. Also note that we
|
||||||
* give it typtype = 'p' (pseudotype) as extra insurance that it won't be
|
* give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
|
||||||
* mistaken for a usable type.
|
* mistaken for a usable type.
|
||||||
*/
|
*/
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -85,7 +85,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
|
||||||
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
|
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
|
||||||
values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */
|
values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */
|
||||||
values[i++] = BoolGetDatum(true); /* typbyval */
|
values[i++] = BoolGetDatum(true); /* typbyval */
|
||||||
values[i++] = CharGetDatum('p'); /* typtype */
|
values[i++] = CharGetDatum(TYPTYPE_PSEUDO); /* typtype */
|
||||||
values[i++] = BoolGetDatum(false); /* typisdefined */
|
values[i++] = BoolGetDatum(false); /* typisdefined */
|
||||||
values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
|
values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
|
||||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
|
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
|
||||||
|
@ -159,7 +159,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
|
||||||
Oid
|
Oid
|
||||||
TypeCreate(const char *typeName,
|
TypeCreate(const char *typeName,
|
||||||
Oid typeNamespace,
|
Oid typeNamespace,
|
||||||
Oid relationOid, /* only for 'c'atalog types */
|
Oid relationOid, /* only for composite types */
|
||||||
char relationKind, /* ditto */
|
char relationKind, /* ditto */
|
||||||
int16 internalSize,
|
int16 internalSize,
|
||||||
char typeType,
|
char typeType,
|
||||||
|
@ -243,7 +243,8 @@ TypeCreate(const char *typeName,
|
||||||
values[i++] = CharGetDatum(typeType); /* typtype */
|
values[i++] = CharGetDatum(typeType); /* typtype */
|
||||||
values[i++] = BoolGetDatum(true); /* typisdefined */
|
values[i++] = BoolGetDatum(true); /* typisdefined */
|
||||||
values[i++] = CharGetDatum(typDelim); /* typdelim */
|
values[i++] = CharGetDatum(typDelim); /* typdelim */
|
||||||
values[i++] = ObjectIdGetDatum(typeType == 'c' ? relationOid : InvalidOid); /* typrelid */
|
values[i++] = ObjectIdGetDatum(typeType == TYPTYPE_COMPOSITE ?
|
||||||
|
relationOid : InvalidOid); /* typrelid */
|
||||||
values[i++] = ObjectIdGetDatum(elementType); /* typelem */
|
values[i++] = ObjectIdGetDatum(elementType); /* typelem */
|
||||||
values[i++] = ObjectIdGetDatum(inputProcedure); /* typinput */
|
values[i++] = ObjectIdGetDatum(inputProcedure); /* typinput */
|
||||||
values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */
|
values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */
|
||||||
|
@ -377,7 +378,7 @@ TypeCreate(const char *typeName,
|
||||||
void
|
void
|
||||||
GenerateTypeDependencies(Oid typeNamespace,
|
GenerateTypeDependencies(Oid typeNamespace,
|
||||||
Oid typeObjectId,
|
Oid typeObjectId,
|
||||||
Oid relationOid, /* only for 'c'atalog types */
|
Oid relationOid, /* only for composite types */
|
||||||
char relationKind, /* ditto */
|
char relationKind, /* ditto */
|
||||||
Oid owner,
|
Oid owner,
|
||||||
Oid inputProcedure,
|
Oid inputProcedure,
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.42 2007/01/05 22:19:25 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.43 2007/04/02 03:49:37 tgl Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* The "DefineFoo" routines take the parse tree and pick out the
|
* The "DefineFoo" routines take the parse tree and pick out the
|
||||||
|
@ -176,9 +176,8 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
|
||||||
* in some cases (AggregateCreate will check).
|
* in some cases (AggregateCreate will check).
|
||||||
*/
|
*/
|
||||||
transTypeId = typenameTypeId(NULL, transType);
|
transTypeId = typenameTypeId(NULL, transType);
|
||||||
if (get_typtype(transTypeId) == 'p' &&
|
if (get_typtype(transTypeId) == TYPTYPE_PSEUDO &&
|
||||||
transTypeId != ANYARRAYOID &&
|
!IsPolymorphicType(transTypeId))
|
||||||
transTypeId != ANYELEMENTOID)
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||||
errmsg("aggregate transition data type cannot be %s",
|
errmsg("aggregate transition data type cannot be %s",
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.82 2007/01/22 01:35:20 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.83 2007/04/02 03:49:37 tgl Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* These routines take the parse tree and pick out the
|
* These routines take the parse tree and pick out the
|
||||||
|
@ -1259,13 +1259,13 @@ CreateCast(CreateCastStmt *stmt)
|
||||||
targettypeid = typenameTypeId(NULL, stmt->targettype);
|
targettypeid = typenameTypeId(NULL, stmt->targettype);
|
||||||
|
|
||||||
/* No pseudo-types allowed */
|
/* No pseudo-types allowed */
|
||||||
if (get_typtype(sourcetypeid) == 'p')
|
if (get_typtype(sourcetypeid) == TYPTYPE_PSEUDO)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
errmsg("source data type %s is a pseudo-type",
|
errmsg("source data type %s is a pseudo-type",
|
||||||
TypeNameToString(stmt->sourcetype))));
|
TypeNameToString(stmt->sourcetype))));
|
||||||
|
|
||||||
if (get_typtype(targettypeid) == 'p')
|
if (get_typtype(targettypeid) == TYPTYPE_PSEUDO)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
errmsg("target data type %s is a pseudo-type",
|
errmsg("target data type %s is a pseudo-type",
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.100 2007/02/14 01:58:57 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.101 2007/04/02 03:49:38 tgl Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* The "DefineFoo" routines take the parse tree and pick out the
|
* The "DefineFoo" routines take the parse tree and pick out the
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
#include "catalog/indexing.h"
|
#include "catalog/indexing.h"
|
||||||
#include "catalog/pg_constraint.h"
|
#include "catalog/pg_constraint.h"
|
||||||
#include "catalog/pg_depend.h"
|
#include "catalog/pg_depend.h"
|
||||||
|
#include "catalog/pg_enum.h"
|
||||||
#include "catalog/pg_namespace.h"
|
#include "catalog/pg_namespace.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
|
@ -205,7 +206,7 @@ DefineType(List *names, List *parameters)
|
||||||
{
|
{
|
||||||
elemType = typenameTypeId(NULL, defGetTypeName(defel));
|
elemType = typenameTypeId(NULL, defGetTypeName(defel));
|
||||||
/* disallow arrays of pseudotypes */
|
/* disallow arrays of pseudotypes */
|
||||||
if (get_typtype(elemType) == 'p')
|
if (get_typtype(elemType) == TYPTYPE_PSEUDO)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
errmsg("array element type cannot be %s",
|
errmsg("array element type cannot be %s",
|
||||||
|
@ -404,7 +405,7 @@ DefineType(List *names, List *parameters)
|
||||||
InvalidOid, /* relation oid (n/a here) */
|
InvalidOid, /* relation oid (n/a here) */
|
||||||
0, /* relation kind (ditto) */
|
0, /* relation kind (ditto) */
|
||||||
internalLength, /* internal size */
|
internalLength, /* internal size */
|
||||||
'b', /* type-type (base type) */
|
TYPTYPE_BASE, /* type-type (base type) */
|
||||||
delimiter, /* array element delimiter */
|
delimiter, /* array element delimiter */
|
||||||
inputOid, /* input procedure */
|
inputOid, /* input procedure */
|
||||||
outputOid, /* output procedure */
|
outputOid, /* output procedure */
|
||||||
|
@ -438,7 +439,7 @@ DefineType(List *names, List *parameters)
|
||||||
InvalidOid, /* relation oid (n/a here) */
|
InvalidOid, /* relation oid (n/a here) */
|
||||||
0, /* relation kind (ditto) */
|
0, /* relation kind (ditto) */
|
||||||
-1, /* internal size */
|
-1, /* internal size */
|
||||||
'b', /* type-type (base type) */
|
TYPTYPE_BASE, /* type-type (base type) */
|
||||||
DEFAULT_TYPDELIM, /* array element delimiter */
|
DEFAULT_TYPDELIM, /* array element delimiter */
|
||||||
F_ARRAY_IN, /* input procedure */
|
F_ARRAY_IN, /* input procedure */
|
||||||
F_ARRAY_OUT, /* output procedure */
|
F_ARRAY_OUT, /* output procedure */
|
||||||
|
@ -543,6 +544,14 @@ RemoveTypeById(Oid typeOid)
|
||||||
|
|
||||||
simple_heap_delete(relation, &tup->t_self);
|
simple_heap_delete(relation, &tup->t_self);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If it is an enum, delete the pg_enum entries too; we don't bother
|
||||||
|
* with making dependency entries for those, so it has to be done
|
||||||
|
* "by hand" here.
|
||||||
|
*/
|
||||||
|
if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
|
||||||
|
EnumValuesDelete(typeOid);
|
||||||
|
|
||||||
ReleaseSysCache(tup);
|
ReleaseSysCache(tup);
|
||||||
|
|
||||||
heap_close(relation, RowExclusiveLock);
|
heap_close(relation, RowExclusiveLock);
|
||||||
|
@ -620,12 +629,15 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||||
basetypeMod = typenameTypeMod(NULL, stmt->typename, basetypeoid);
|
basetypeMod = typenameTypeMod(NULL, stmt->typename, basetypeoid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Base type must be a plain base type or another domain. Domains over
|
* Base type must be a plain base type, another domain or an enum.
|
||||||
* pseudotypes would create a security hole. Domains over composite types
|
* Domains over pseudotypes would create a security hole. Domains
|
||||||
* might be made to work in the future, but not today.
|
* over composite types might be made to work in the future, but not
|
||||||
|
* today.
|
||||||
*/
|
*/
|
||||||
typtype = baseType->typtype;
|
typtype = baseType->typtype;
|
||||||
if (typtype != 'b' && typtype != 'd')
|
if (typtype != TYPTYPE_BASE &&
|
||||||
|
typtype != TYPTYPE_DOMAIN &&
|
||||||
|
typtype != TYPTYPE_ENUM)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
errmsg("\"%s\" is not a valid base type for a domain",
|
errmsg("\"%s\" is not a valid base type for a domain",
|
||||||
|
@ -798,7 +810,7 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||||
InvalidOid, /* relation oid (n/a here) */
|
InvalidOid, /* relation oid (n/a here) */
|
||||||
0, /* relation kind (ditto) */
|
0, /* relation kind (ditto) */
|
||||||
internalLength, /* internal size */
|
internalLength, /* internal size */
|
||||||
'd', /* type-type (domain type) */
|
TYPTYPE_DOMAIN, /* type-type (domain type) */
|
||||||
delimiter, /* array element delimiter */
|
delimiter, /* array element delimiter */
|
||||||
inputProcedure, /* input procedure */
|
inputProcedure, /* input procedure */
|
||||||
outputProcedure, /* output procedure */
|
outputProcedure, /* output procedure */
|
||||||
|
@ -907,7 +919,7 @@ RemoveDomain(List *names, DropBehavior behavior, bool missing_ok)
|
||||||
/* Check that this is actually a domain */
|
/* Check that this is actually a domain */
|
||||||
typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
|
typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
|
||||||
|
|
||||||
if (typtype != 'd')
|
if (typtype != TYPTYPE_DOMAIN)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
errmsg("\"%s\" is not a domain",
|
errmsg("\"%s\" is not a domain",
|
||||||
|
@ -925,6 +937,100 @@ RemoveDomain(List *names, DropBehavior behavior, bool missing_ok)
|
||||||
performDeletion(&object, behavior);
|
performDeletion(&object, behavior);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DefineEnum
|
||||||
|
* Registers a new enum.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
DefineEnum(CreateEnumStmt *stmt)
|
||||||
|
{
|
||||||
|
char *enumName;
|
||||||
|
char *enumArrayName;
|
||||||
|
Oid enumNamespace;
|
||||||
|
Oid enumTypeOid;
|
||||||
|
AclResult aclresult;
|
||||||
|
|
||||||
|
/* Convert list of names to a name and namespace */
|
||||||
|
enumNamespace = QualifiedNameGetCreationNamespace(stmt->typename,
|
||||||
|
&enumName);
|
||||||
|
|
||||||
|
/* Check we have creation rights in target namespace */
|
||||||
|
aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
|
||||||
|
if (aclresult != ACLCHECK_OK)
|
||||||
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
||||||
|
get_namespace_name(enumNamespace));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type names must be one character shorter than other names, allowing
|
||||||
|
* room to create the corresponding array type name with prepended "_".
|
||||||
|
*/
|
||||||
|
if (strlen(enumName) > (NAMEDATALEN - 2))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_NAME),
|
||||||
|
errmsg("type names must be %d characters or less",
|
||||||
|
NAMEDATALEN - 2)));
|
||||||
|
|
||||||
|
/* Create the pg_type entry */
|
||||||
|
enumTypeOid =
|
||||||
|
TypeCreate(enumName, /* type name */
|
||||||
|
enumNamespace, /* namespace */
|
||||||
|
InvalidOid, /* relation oid (n/a here) */
|
||||||
|
0, /* relation kind (ditto) */
|
||||||
|
sizeof(Oid), /* internal size */
|
||||||
|
TYPTYPE_ENUM, /* type-type (enum type) */
|
||||||
|
DEFAULT_TYPDELIM, /* array element delimiter */
|
||||||
|
F_ENUM_IN, /* input procedure */
|
||||||
|
F_ENUM_OUT, /* output procedure */
|
||||||
|
InvalidOid, /* receive procedure - none */
|
||||||
|
InvalidOid, /* send procedure - none */
|
||||||
|
InvalidOid, /* typmodin procedure - none */
|
||||||
|
InvalidOid, /* typmodout procedure - none */
|
||||||
|
InvalidOid, /* analyze procedure - default */
|
||||||
|
InvalidOid, /* element type ID */
|
||||||
|
InvalidOid, /* base type ID (only for domains) */
|
||||||
|
NULL, /* never a default type value */
|
||||||
|
NULL, /* binary default isn't sent either */
|
||||||
|
true, /* always passed by value */
|
||||||
|
'i', /* int alignment */
|
||||||
|
'p', /* TOAST strategy always plain */
|
||||||
|
-1, /* typMod (Domains only) */
|
||||||
|
0, /* Array dimensions of typbasetype */
|
||||||
|
false); /* Type NOT NULL */
|
||||||
|
|
||||||
|
/* Enter the enum's values into pg_enum */
|
||||||
|
EnumValuesCreate(enumTypeOid, stmt->vals);
|
||||||
|
|
||||||
|
/* Create array type for enum */
|
||||||
|
enumArrayName = makeArrayTypeName(enumName);
|
||||||
|
|
||||||
|
TypeCreate(enumArrayName, /* type name */
|
||||||
|
enumNamespace, /* namespace */
|
||||||
|
InvalidOid, /* relation oid (n/a here) */
|
||||||
|
0, /* relation kind (ditto) */
|
||||||
|
-1, /* internal size */
|
||||||
|
TYPTYPE_BASE, /* type-type (base type) */
|
||||||
|
DEFAULT_TYPDELIM, /* array element delimiter */
|
||||||
|
F_ARRAY_IN, /* input procedure */
|
||||||
|
F_ARRAY_OUT, /* output procedure */
|
||||||
|
F_ARRAY_RECV, /* receive procedure */
|
||||||
|
F_ARRAY_SEND, /* send procedure */
|
||||||
|
InvalidOid, /* typmodin procedure - none */
|
||||||
|
InvalidOid, /* typmodout procedure - none */
|
||||||
|
InvalidOid, /* analyze procedure - default */
|
||||||
|
enumTypeOid, /* element type ID */
|
||||||
|
InvalidOid, /* base type ID */
|
||||||
|
NULL, /* never a default type value */
|
||||||
|
NULL, /* binary default isn't sent either */
|
||||||
|
false, /* never passed by value */
|
||||||
|
'i', /* enums have align i, so do their arrays */
|
||||||
|
'x', /* ARRAY is always toastable */
|
||||||
|
-1, /* typMod (Domains only) */
|
||||||
|
0, /* Array dimensions of typbasetype */
|
||||||
|
false); /* Type NOT NULL */
|
||||||
|
|
||||||
|
pfree(enumArrayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find suitable I/O functions for a type.
|
* Find suitable I/O functions for a type.
|
||||||
|
@ -1835,7 +1941,7 @@ checkDomainOwner(HeapTuple tup, TypeName *typename)
|
||||||
Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
|
Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
|
||||||
|
|
||||||
/* Check that this is actually a domain */
|
/* Check that this is actually a domain */
|
||||||
if (typTup->typtype != 'd')
|
if (typTup->typtype != TYPTYPE_DOMAIN)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
errmsg("\"%s\" is not a domain",
|
errmsg("\"%s\" is not a domain",
|
||||||
|
@ -2021,7 +2127,7 @@ GetDomainConstraints(Oid typeOid)
|
||||||
elog(ERROR, "cache lookup failed for type %u", typeOid);
|
elog(ERROR, "cache lookup failed for type %u", typeOid);
|
||||||
typTup = (Form_pg_type) GETSTRUCT(tup);
|
typTup = (Form_pg_type) GETSTRUCT(tup);
|
||||||
|
|
||||||
if (typTup->typtype != 'd')
|
if (typTup->typtype != TYPTYPE_DOMAIN)
|
||||||
{
|
{
|
||||||
/* Not a domain, so done */
|
/* Not a domain, so done */
|
||||||
ReleaseSysCache(tup);
|
ReleaseSysCache(tup);
|
||||||
|
@ -2148,7 +2254,7 @@ AlterTypeOwner(List *names, Oid newOwnerId)
|
||||||
* free-standing composite type, and not a table's underlying type. We
|
* free-standing composite type, and not a table's underlying type. We
|
||||||
* want people to use ALTER TABLE not ALTER TYPE for that case.
|
* want people to use ALTER TABLE not ALTER TYPE for that case.
|
||||||
*/
|
*/
|
||||||
if (typTup->typtype == 'c' &&
|
if (typTup->typtype == TYPTYPE_COMPOSITE &&
|
||||||
get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
|
get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
|
@ -2325,11 +2431,12 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
|
||||||
|
|
||||||
/* Detect whether type is a composite type (but not a table rowtype) */
|
/* Detect whether type is a composite type (but not a table rowtype) */
|
||||||
isCompositeType =
|
isCompositeType =
|
||||||
(typform->typtype == 'c' &&
|
(typform->typtype == TYPTYPE_COMPOSITE &&
|
||||||
get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
|
get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
|
||||||
|
|
||||||
/* Enforce not-table-type if requested */
|
/* Enforce not-table-type if requested */
|
||||||
if (typform->typtype == 'c' && !isCompositeType && errorOnTableType)
|
if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
|
||||||
|
errorOnTableType)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
errmsg("%s is a table's row type",
|
errmsg("%s is a table's row type",
|
||||||
|
@ -2376,14 +2483,14 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* If it's a domain, it might have constraints */
|
/* If it's a domain, it might have constraints */
|
||||||
if (typform->typtype == 'd')
|
if (typform->typtype == TYPTYPE_DOMAIN)
|
||||||
AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
|
AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update dependency on schema, if any --- a table rowtype has not got
|
* Update dependency on schema, if any --- a table rowtype has not got
|
||||||
* one.
|
* one.
|
||||||
*/
|
*/
|
||||||
if (typform->typtype != 'c')
|
if (typform->typtype != TYPTYPE_COMPOSITE)
|
||||||
if (changeDependencyFor(TypeRelationId, typeOid,
|
if (changeDependencyFor(TypeRelationId, typeOid,
|
||||||
NamespaceRelationId, oldNspOid, nspOid) != 1)
|
NamespaceRelationId, oldNspOid, nspOid) != 1)
|
||||||
elog(ERROR, "failed to change schema dependency for type %s",
|
elog(ERROR, "failed to change schema dependency for type %s",
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.112 2007/03/13 00:33:40 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.113 2007/04/02 03:49:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -182,7 +182,7 @@ init_sql_fcache(FmgrInfo *finfo)
|
||||||
*/
|
*/
|
||||||
rettype = procedureStruct->prorettype;
|
rettype = procedureStruct->prorettype;
|
||||||
|
|
||||||
if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
|
if (IsPolymorphicType(rettype))
|
||||||
{
|
{
|
||||||
rettype = get_fn_expr_rettype(finfo);
|
rettype = get_fn_expr_rettype(finfo);
|
||||||
if (rettype == InvalidOid) /* this probably should not happen */
|
if (rettype == InvalidOid) /* this probably should not happen */
|
||||||
|
@ -218,7 +218,7 @@ init_sql_fcache(FmgrInfo *finfo)
|
||||||
{
|
{
|
||||||
Oid argtype = argOidVect[argnum];
|
Oid argtype = argOidVect[argnum];
|
||||||
|
|
||||||
if (argtype == ANYARRAYOID || argtype == ANYELEMENTOID)
|
if (IsPolymorphicType(argtype))
|
||||||
{
|
{
|
||||||
argtype = get_fn_expr_argtype(finfo, argnum);
|
argtype = get_fn_expr_argtype(finfo, argnum);
|
||||||
if (argtype == InvalidOid)
|
if (argtype == InvalidOid)
|
||||||
|
@ -845,9 +845,9 @@ ShutdownSQLFunction(Datum arg)
|
||||||
* to be sure that the user is returning the type he claims.
|
* to be sure that the user is returning the type he claims.
|
||||||
*
|
*
|
||||||
* For a polymorphic function the passed rettype must be the actual resolved
|
* For a polymorphic function the passed rettype must be the actual resolved
|
||||||
* output type of the function; we should never see ANYARRAY or ANYELEMENT
|
* output type of the function; we should never see ANYARRAY, ANYENUM or
|
||||||
* as rettype. (This means we can't check the type during function definition
|
* ANYELEMENT as rettype. (This means we can't check the type during function
|
||||||
* of a polymorphic function.)
|
* definition of a polymorphic function.)
|
||||||
*
|
*
|
||||||
* The return value is true if the function returns the entire tuple result
|
* The return value is true if the function returns the entire tuple result
|
||||||
* of its final SELECT, and false otherwise. Note that because we allow
|
* of its final SELECT, and false otherwise. Note that because we allow
|
||||||
|
@ -925,7 +925,9 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||||
|
|
||||||
fn_typtype = get_typtype(rettype);
|
fn_typtype = get_typtype(rettype);
|
||||||
|
|
||||||
if (fn_typtype == 'b' || fn_typtype == 'd')
|
if (fn_typtype == TYPTYPE_BASE ||
|
||||||
|
fn_typtype == TYPTYPE_DOMAIN ||
|
||||||
|
fn_typtype == TYPTYPE_ENUM)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* For base-type returns, the target list should have exactly one
|
* For base-type returns, the target list should have exactly one
|
||||||
|
@ -948,7 +950,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||||
errdetail("Actual return type is %s.",
|
errdetail("Actual return type is %s.",
|
||||||
format_type_be(restype))));
|
format_type_be(restype))));
|
||||||
}
|
}
|
||||||
else if (fn_typtype == 'c' || rettype == RECORDOID)
|
else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
|
||||||
{
|
{
|
||||||
/* Returns a rowtype */
|
/* Returns a rowtype */
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
|
@ -1053,13 +1055,13 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||||
/* Report that we are returning entire tuple result */
|
/* Report that we are returning entire tuple result */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
|
else if (IsPolymorphicType(rettype))
|
||||||
{
|
{
|
||||||
/* This should already have been caught ... */
|
/* This should already have been caught ... */
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||||
errmsg("cannot determine result data type"),
|
errmsg("cannot determine result data type"),
|
||||||
errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));
|
errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.151 2007/02/22 23:44:24 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.152 2007/04/02 03:49:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1363,8 +1363,8 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get actual datatypes of the inputs. These could be different from
|
* Get actual datatypes of the inputs. These could be different from
|
||||||
* the agg's declared input types, when the agg accepts ANY, ANYARRAY
|
* the agg's declared input types, when the agg accepts ANY or
|
||||||
* or ANYELEMENT.
|
* a polymorphic type.
|
||||||
*/
|
*/
|
||||||
i = 0;
|
i = 0;
|
||||||
foreach(lc, aggref->args)
|
foreach(lc, aggref->args)
|
||||||
|
@ -1421,7 +1421,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
||||||
|
|
||||||
/* resolve actual type of transition state, if polymorphic */
|
/* resolve actual type of transition state, if polymorphic */
|
||||||
aggtranstype = aggform->aggtranstype;
|
aggtranstype = aggform->aggtranstype;
|
||||||
if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
|
if (IsPolymorphicType(aggtranstype))
|
||||||
{
|
{
|
||||||
/* have to fetch the agg's declared input types... */
|
/* have to fetch the agg's declared input types... */
|
||||||
Oid *declaredArgTypes;
|
Oid *declaredArgTypes;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.372 2007/03/27 23:21:09 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.373 2007/04/02 03:49:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -2361,6 +2361,17 @@ _copyCompositeTypeStmt(CompositeTypeStmt *from)
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CreateEnumStmt *
|
||||||
|
_copyCreateEnumStmt(CreateEnumStmt *from)
|
||||||
|
{
|
||||||
|
CreateEnumStmt *newnode = makeNode(CreateEnumStmt);
|
||||||
|
|
||||||
|
COPY_NODE_FIELD(typename);
|
||||||
|
COPY_NODE_FIELD(vals);
|
||||||
|
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
static ViewStmt *
|
static ViewStmt *
|
||||||
_copyViewStmt(ViewStmt *from)
|
_copyViewStmt(ViewStmt *from)
|
||||||
{
|
{
|
||||||
|
@ -3312,6 +3323,9 @@ copyObject(void *from)
|
||||||
case T_CompositeTypeStmt:
|
case T_CompositeTypeStmt:
|
||||||
retval = _copyCompositeTypeStmt(from);
|
retval = _copyCompositeTypeStmt(from);
|
||||||
break;
|
break;
|
||||||
|
case T_CreateEnumStmt:
|
||||||
|
retval = _copyCreateEnumStmt(from);
|
||||||
|
break;
|
||||||
case T_ViewStmt:
|
case T_ViewStmt:
|
||||||
retval = _copyViewStmt(from);
|
retval = _copyViewStmt(from);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.303 2007/03/27 23:21:09 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.304 2007/04/02 03:49:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1186,6 +1186,15 @@ _equalCompositeTypeStmt(CompositeTypeStmt *a, CompositeTypeStmt *b)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_equalCreateEnumStmt(CreateEnumStmt *a, CreateEnumStmt *b)
|
||||||
|
{
|
||||||
|
COMPARE_NODE_FIELD(typename);
|
||||||
|
COMPARE_NODE_FIELD(vals);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
_equalViewStmt(ViewStmt *a, ViewStmt *b)
|
_equalViewStmt(ViewStmt *a, ViewStmt *b)
|
||||||
{
|
{
|
||||||
|
@ -2247,6 +2256,9 @@ equal(void *a, void *b)
|
||||||
case T_CompositeTypeStmt:
|
case T_CompositeTypeStmt:
|
||||||
retval = _equalCompositeTypeStmt(a, b);
|
retval = _equalCompositeTypeStmt(a, b);
|
||||||
break;
|
break;
|
||||||
|
case T_CreateEnumStmt:
|
||||||
|
retval = _equalCreateEnumStmt(a, b);
|
||||||
|
break;
|
||||||
case T_ViewStmt:
|
case T_ViewStmt:
|
||||||
retval = _equalViewStmt(a, b);
|
retval = _equalViewStmt(a, b);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.240 2007/03/27 23:21:09 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.241 2007/04/02 03:49:38 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
|
@ -435,7 +435,7 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts)
|
||||||
ReleaseSysCache(aggTuple);
|
ReleaseSysCache(aggTuple);
|
||||||
|
|
||||||
/* resolve actual type of transition state, if polymorphic */
|
/* resolve actual type of transition state, if polymorphic */
|
||||||
if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
|
if (IsPolymorphicType(aggtranstype))
|
||||||
{
|
{
|
||||||
/* have to fetch the agg's declared input types... */
|
/* have to fetch the agg's declared input types... */
|
||||||
Oid *declaredArgTypes;
|
Oid *declaredArgTypes;
|
||||||
|
@ -2907,8 +2907,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
|
||||||
funcform->pronargs * sizeof(Oid));
|
funcform->pronargs * sizeof(Oid));
|
||||||
for (i = 0; i < funcform->pronargs; i++)
|
for (i = 0; i < funcform->pronargs; i++)
|
||||||
{
|
{
|
||||||
if (argtypes[i] == ANYARRAYOID ||
|
if (IsPolymorphicType(argtypes[i]))
|
||||||
argtypes[i] == ANYELEMENTOID)
|
|
||||||
{
|
{
|
||||||
argtypes[i] = exprType((Node *) list_nth(args, i));
|
argtypes[i] = exprType((Node *) list_nth(args, i));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.584 2007/03/26 16:58:39 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.585 2007/04/02 03:49:38 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
|
@ -248,6 +248,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
|
||||||
TableFuncElementList opt_type_modifiers
|
TableFuncElementList opt_type_modifiers
|
||||||
prep_type_clause
|
prep_type_clause
|
||||||
execute_param_clause using_clause returning_clause
|
execute_param_clause using_clause returning_clause
|
||||||
|
enum_val_list
|
||||||
|
|
||||||
%type <range> OptTempTableName
|
%type <range> OptTempTableName
|
||||||
%type <into> into_clause create_as_target
|
%type <into> into_clause create_as_target
|
||||||
|
@ -383,7 +384,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
|
||||||
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS
|
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS
|
||||||
DESC DISABLE_P DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
|
DESC DISABLE_P DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
|
||||||
|
|
||||||
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
|
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT EXCLUDING
|
||||||
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
|
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
|
||||||
|
|
||||||
FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
|
FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
|
||||||
|
@ -2922,6 +2923,13 @@ DefineStmt:
|
||||||
n->coldeflist = $6;
|
n->coldeflist = $6;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
|
| CREATE TYPE_P any_name AS ENUM_P '(' enum_val_list ')'
|
||||||
|
{
|
||||||
|
CreateEnumStmt *n = makeNode(CreateEnumStmt);
|
||||||
|
n->typename = $3;
|
||||||
|
n->vals = $7;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
definition: '(' def_list ')' { $$ = $2; }
|
definition: '(' def_list ')' { $$ = $2; }
|
||||||
|
@ -2966,6 +2974,12 @@ old_aggr_elem: IDENT '=' def_arg
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
enum_val_list: Sconst
|
||||||
|
{ $$ = list_make1(makeString($1)); }
|
||||||
|
| enum_val_list ',' Sconst
|
||||||
|
{ $$ = lappend($1, makeString($3)); }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
|
@ -8760,6 +8774,7 @@ unreserved_keyword:
|
||||||
| ENABLE_P
|
| ENABLE_P
|
||||||
| ENCODING
|
| ENCODING
|
||||||
| ENCRYPTED
|
| ENCRYPTED
|
||||||
|
| ENUM_P
|
||||||
| ESCAPE
|
| ESCAPE
|
||||||
| EXCLUDING
|
| EXCLUDING
|
||||||
| EXCLUSIVE
|
| EXCLUSIVE
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.185 2007/03/19 23:38:29 wieck Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.186 2007/04/02 03:49:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -136,6 +136,7 @@ static const ScanKeyword ScanKeywords[] = {
|
||||||
{"encoding", ENCODING},
|
{"encoding", ENCODING},
|
||||||
{"encrypted", ENCRYPTED},
|
{"encrypted", ENCRYPTED},
|
||||||
{"end", END_P},
|
{"end", END_P},
|
||||||
|
{"enum", ENUM_P},
|
||||||
{"escape", ESCAPE},
|
{"escape", ESCAPE},
|
||||||
{"except", EXCEPT},
|
{"except", EXCEPT},
|
||||||
{"excluding", EXCLUDING},
|
{"excluding", EXCLUDING},
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.152 2007/03/27 23:21:10 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.153 2007/04/02 03:49:38 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -132,7 +132,8 @@ coerce_type(ParseState *pstate, Node *node,
|
||||||
}
|
}
|
||||||
if (targetTypeId == ANYOID ||
|
if (targetTypeId == ANYOID ||
|
||||||
targetTypeId == ANYELEMENTOID ||
|
targetTypeId == ANYELEMENTOID ||
|
||||||
(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID))
|
(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID) ||
|
||||||
|
(targetTypeId == ANYENUMOID && inputTypeId != UNKNOWNOID))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Assume can_coerce_type verified that implicit coercion is okay.
|
* Assume can_coerce_type verified that implicit coercion is okay.
|
||||||
|
@ -143,7 +144,8 @@ coerce_type(ParseState *pstate, Node *node,
|
||||||
* since an UNKNOWN value is still a perfectly valid Datum. However
|
* since an UNKNOWN value is still a perfectly valid Datum. However
|
||||||
* an UNKNOWN value is definitely *not* an array, and so we mustn't
|
* an UNKNOWN value is definitely *not* an array, and so we mustn't
|
||||||
* accept it for ANYARRAY. (Instead, we will call anyarray_in below,
|
* accept it for ANYARRAY. (Instead, we will call anyarray_in below,
|
||||||
* which will produce an error.)
|
* which will produce an error.) Likewise, UNKNOWN input is no good
|
||||||
|
* for ANYENUM.
|
||||||
*
|
*
|
||||||
* NB: we do NOT want a RelabelType here.
|
* NB: we do NOT want a RelabelType here.
|
||||||
*/
|
*/
|
||||||
|
@ -406,9 +408,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
|
||||||
if (targetTypeId == ANYOID)
|
if (targetTypeId == ANYOID)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* accept if target is ANYARRAY or ANYELEMENT, for now */
|
/* accept if target is polymorphic, for now */
|
||||||
if (targetTypeId == ANYARRAYOID ||
|
if (IsPolymorphicType(targetTypeId))
|
||||||
targetTypeId == ANYELEMENTOID)
|
|
||||||
{
|
{
|
||||||
have_generics = true; /* do more checking later */
|
have_generics = true; /* do more checking later */
|
||||||
continue;
|
continue;
|
||||||
|
@ -1048,6 +1049,9 @@ coerce_to_common_type(ParseState *pstate, Node *node,
|
||||||
* 3) If there are arguments of both ANYELEMENT and ANYARRAY, make sure
|
* 3) If there are arguments of both ANYELEMENT and ANYARRAY, make sure
|
||||||
* the actual ANYELEMENT datatype is in fact the element type for
|
* the actual ANYELEMENT datatype is in fact the element type for
|
||||||
* the actual ANYARRAY datatype.
|
* the actual ANYARRAY datatype.
|
||||||
|
* 4) ANYENUM is treated the same as ANYELEMENT except that if it is used
|
||||||
|
* (alone or in combination with plain ANYELEMENT), we add the extra
|
||||||
|
* condition that the ANYELEMENT type must be an enum.
|
||||||
*
|
*
|
||||||
* If we have UNKNOWN input (ie, an untyped literal) for any ANYELEMENT
|
* If we have UNKNOWN input (ie, an untyped literal) for any ANYELEMENT
|
||||||
* or ANYARRAY argument, assume it is okay.
|
* or ANYARRAY argument, assume it is okay.
|
||||||
|
@ -1070,6 +1074,7 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
||||||
Oid array_typeid = InvalidOid;
|
Oid array_typeid = InvalidOid;
|
||||||
Oid array_typelem;
|
Oid array_typelem;
|
||||||
bool have_anyelement = false;
|
bool have_anyelement = false;
|
||||||
|
bool have_anyenum = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Loop through the arguments to see if we have any that are ANYARRAY or
|
* Loop through the arguments to see if we have any that are ANYARRAY or
|
||||||
|
@ -1079,9 +1084,12 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
||||||
{
|
{
|
||||||
Oid actual_type = actual_arg_types[j];
|
Oid actual_type = actual_arg_types[j];
|
||||||
|
|
||||||
if (declared_arg_types[j] == ANYELEMENTOID)
|
if (declared_arg_types[j] == ANYELEMENTOID ||
|
||||||
|
declared_arg_types[j] == ANYENUMOID)
|
||||||
{
|
{
|
||||||
have_anyelement = true;
|
have_anyelement = true;
|
||||||
|
if (declared_arg_types[j] == ANYENUMOID)
|
||||||
|
have_anyenum = true;
|
||||||
if (actual_type == UNKNOWNOID)
|
if (actual_type == UNKNOWNOID)
|
||||||
continue;
|
continue;
|
||||||
if (OidIsValid(elem_typeid) && actual_type != elem_typeid)
|
if (OidIsValid(elem_typeid) && actual_type != elem_typeid)
|
||||||
|
@ -1127,6 +1135,13 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (have_anyenum)
|
||||||
|
{
|
||||||
|
/* require the element type to be an enum */
|
||||||
|
if (!type_is_enum(elem_typeid))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Looks valid */
|
/* Looks valid */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1136,18 +1151,18 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
||||||
* Make sure a polymorphic function is legally callable, and
|
* Make sure a polymorphic function is legally callable, and
|
||||||
* deduce actual argument and result types.
|
* deduce actual argument and result types.
|
||||||
*
|
*
|
||||||
* If ANYARRAY or ANYELEMENT is used for a function's arguments or
|
* If ANYARRAY, ANYELEMENT, or ANYENUM is used for a function's arguments or
|
||||||
* return type, we make sure the actual data types are consistent with
|
* return type, we make sure the actual data types are consistent with
|
||||||
* each other. The argument consistency rules are shown above for
|
* each other. The argument consistency rules are shown above for
|
||||||
* check_generic_type_consistency().
|
* check_generic_type_consistency().
|
||||||
*
|
*
|
||||||
* If we have UNKNOWN input (ie, an untyped literal) for any ANYELEMENT
|
* If we have UNKNOWN input (ie, an untyped literal) for any polymorphic
|
||||||
* or ANYARRAY argument, we attempt to deduce the actual type it should
|
* argument, we attempt to deduce the actual type it should have. If
|
||||||
* have. If successful, we alter that position of declared_arg_types[]
|
* successful, we alter that position of declared_arg_types[] so that
|
||||||
* so that make_fn_arguments will coerce the literal to the right thing.
|
* make_fn_arguments will coerce the literal to the right thing.
|
||||||
*
|
*
|
||||||
* Rules are applied to the function's return type (possibly altering it)
|
* Rules are applied to the function's return type (possibly altering it)
|
||||||
* if it is declared ANYARRAY or ANYELEMENT:
|
* if it is declared as a polymorphic type:
|
||||||
*
|
*
|
||||||
* 1) If return type is ANYARRAY, and any argument is ANYARRAY, use the
|
* 1) If return type is ANYARRAY, and any argument is ANYARRAY, use the
|
||||||
* argument's actual type as the function's return type.
|
* argument's actual type as the function's return type.
|
||||||
|
@ -1167,6 +1182,9 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
||||||
* 6) If return type is ANYELEMENT, no argument is ANYARRAY or ANYELEMENT,
|
* 6) If return type is ANYELEMENT, no argument is ANYARRAY or ANYELEMENT,
|
||||||
* generate an ERROR. This condition is prevented by CREATE FUNCTION
|
* generate an ERROR. This condition is prevented by CREATE FUNCTION
|
||||||
* and is therefore not expected here.
|
* and is therefore not expected here.
|
||||||
|
* 7) ANYENUM is treated the same as ANYELEMENT except that if it is used
|
||||||
|
* (alone or in combination with plain ANYELEMENT), we add the extra
|
||||||
|
* condition that the ANYELEMENT type must be an enum.
|
||||||
*/
|
*/
|
||||||
Oid
|
Oid
|
||||||
enforce_generic_type_consistency(Oid *actual_arg_types,
|
enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||||
|
@ -1180,7 +1198,9 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||||
Oid elem_typeid = InvalidOid;
|
Oid elem_typeid = InvalidOid;
|
||||||
Oid array_typeid = InvalidOid;
|
Oid array_typeid = InvalidOid;
|
||||||
Oid array_typelem;
|
Oid array_typelem;
|
||||||
bool have_anyelement = (rettype == ANYELEMENTOID);
|
bool have_anyelement = (rettype == ANYELEMENTOID ||
|
||||||
|
rettype == ANYENUMOID);
|
||||||
|
bool have_anyenum = (rettype == ANYENUMOID);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Loop through the arguments to see if we have any that are ANYARRAY or
|
* Loop through the arguments to see if we have any that are ANYARRAY or
|
||||||
|
@ -1190,9 +1210,12 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||||
{
|
{
|
||||||
Oid actual_type = actual_arg_types[j];
|
Oid actual_type = actual_arg_types[j];
|
||||||
|
|
||||||
if (declared_arg_types[j] == ANYELEMENTOID)
|
if (declared_arg_types[j] == ANYELEMENTOID ||
|
||||||
|
declared_arg_types[j] == ANYENUMOID)
|
||||||
{
|
{
|
||||||
have_generics = have_anyelement = true;
|
have_generics = have_anyelement = true;
|
||||||
|
if (declared_arg_types[j] == ANYENUMOID)
|
||||||
|
have_anyenum = true;
|
||||||
if (actual_type == UNKNOWNOID)
|
if (actual_type == UNKNOWNOID)
|
||||||
{
|
{
|
||||||
have_unknowns = true;
|
have_unknowns = true;
|
||||||
|
@ -1227,8 +1250,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fast Track: if none of the arguments are ANYARRAY or ANYELEMENT, return
|
* Fast Track: if none of the arguments are polymorphic, return the
|
||||||
* the unmodified rettype.
|
* unmodified rettype. We assume it can't be polymorphic either.
|
||||||
*/
|
*/
|
||||||
if (!have_generics)
|
if (!have_generics)
|
||||||
return rettype;
|
return rettype;
|
||||||
|
@ -1274,7 +1297,17 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||||
/* Only way to get here is if all the generic args are UNKNOWN */
|
/* Only way to get here is if all the generic args are UNKNOWN */
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
errmsg("could not determine anyarray/anyelement type because input has type \"unknown\"")));
|
errmsg("could not determine polymorphic type because input has type \"unknown\"")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (have_anyenum)
|
||||||
|
{
|
||||||
|
/* require the element type to be an enum */
|
||||||
|
if (!type_is_enum(elem_typeid))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
|
errmsg("type matched to anyenum is not an enum type: %s",
|
||||||
|
format_type_be(elem_typeid))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1289,7 +1322,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||||
if (actual_type != UNKNOWNOID)
|
if (actual_type != UNKNOWNOID)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (declared_arg_types[j] == ANYELEMENTOID)
|
if (declared_arg_types[j] == ANYELEMENTOID ||
|
||||||
|
declared_arg_types[j] == ANYENUMOID)
|
||||||
declared_arg_types[j] = elem_typeid;
|
declared_arg_types[j] = elem_typeid;
|
||||||
else if (declared_arg_types[j] == ANYARRAYOID)
|
else if (declared_arg_types[j] == ANYARRAYOID)
|
||||||
{
|
{
|
||||||
|
@ -1307,7 +1341,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we return ANYARRAYOID use the appropriate argument type */
|
/* if we return ANYARRAY use the appropriate argument type */
|
||||||
if (rettype == ANYARRAYOID)
|
if (rettype == ANYARRAYOID)
|
||||||
{
|
{
|
||||||
if (!OidIsValid(array_typeid))
|
if (!OidIsValid(array_typeid))
|
||||||
|
@ -1322,8 +1356,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||||
return array_typeid;
|
return array_typeid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we return ANYELEMENTOID use the appropriate argument type */
|
/* if we return ANYELEMENT use the appropriate argument type */
|
||||||
if (rettype == ANYELEMENTOID)
|
if (rettype == ANYELEMENTOID || rettype == ANYENUMOID)
|
||||||
return elem_typeid;
|
return elem_typeid;
|
||||||
|
|
||||||
/* we don't return a generic type; send back the original return type */
|
/* we don't return a generic type; send back the original return type */
|
||||||
|
@ -1333,7 +1367,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||||
/*
|
/*
|
||||||
* resolve_generic_type()
|
* resolve_generic_type()
|
||||||
* Deduce an individual actual datatype on the assumption that
|
* Deduce an individual actual datatype on the assumption that
|
||||||
* the rules for ANYARRAY/ANYELEMENT are being followed.
|
* the rules for polymorphic types are being followed.
|
||||||
*
|
*
|
||||||
* declared_type is the declared datatype we want to resolve.
|
* declared_type is the declared datatype we want to resolve.
|
||||||
* context_actual_type is the actual input datatype to some argument
|
* context_actual_type is the actual input datatype to some argument
|
||||||
|
@ -1362,7 +1396,8 @@ resolve_generic_type(Oid declared_type,
|
||||||
format_type_be(context_actual_type))));
|
format_type_be(context_actual_type))));
|
||||||
return context_actual_type;
|
return context_actual_type;
|
||||||
}
|
}
|
||||||
else if (context_declared_type == ANYELEMENTOID)
|
else if (context_declared_type == ANYELEMENTOID ||
|
||||||
|
context_declared_type == ANYENUMOID)
|
||||||
{
|
{
|
||||||
/* Use the array type corresponding to actual type */
|
/* Use the array type corresponding to actual type */
|
||||||
Oid array_typeid = get_array_type(context_actual_type);
|
Oid array_typeid = get_array_type(context_actual_type);
|
||||||
|
@ -1375,7 +1410,7 @@ resolve_generic_type(Oid declared_type,
|
||||||
return array_typeid;
|
return array_typeid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (declared_type == ANYELEMENTOID)
|
else if (declared_type == ANYELEMENTOID || declared_type == ANYENUMOID)
|
||||||
{
|
{
|
||||||
if (context_declared_type == ANYARRAYOID)
|
if (context_declared_type == ANYARRAYOID)
|
||||||
{
|
{
|
||||||
|
@ -1389,7 +1424,8 @@ resolve_generic_type(Oid declared_type,
|
||||||
format_type_be(context_actual_type))));
|
format_type_be(context_actual_type))));
|
||||||
return array_typelem;
|
return array_typelem;
|
||||||
}
|
}
|
||||||
else if (context_declared_type == ANYELEMENTOID)
|
else if (context_declared_type == ANYELEMENTOID ||
|
||||||
|
context_declared_type == ANYENUMOID)
|
||||||
{
|
{
|
||||||
/* Use the actual type; it doesn't matter if array or not */
|
/* Use the actual type; it doesn't matter if array or not */
|
||||||
return context_actual_type;
|
return context_actual_type;
|
||||||
|
@ -1402,7 +1438,7 @@ resolve_generic_type(Oid declared_type,
|
||||||
}
|
}
|
||||||
/* If we get here, declared_type is polymorphic and context isn't */
|
/* If we get here, declared_type is polymorphic and context isn't */
|
||||||
/* NB: this is a calling-code logic error, not a user error */
|
/* NB: this is a calling-code logic error, not a user error */
|
||||||
elog(ERROR, "could not determine ANYARRAY/ANYELEMENT type because context isn't polymorphic");
|
elog(ERROR, "could not determine polymorphic type because context isn't polymorphic");
|
||||||
return InvalidOid; /* keep compiler quiet */
|
return InvalidOid; /* keep compiler quiet */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1502,6 +1538,7 @@ TypeCategory(Oid inType)
|
||||||
case (INTERNALOID):
|
case (INTERNALOID):
|
||||||
case (OPAQUEOID):
|
case (OPAQUEOID):
|
||||||
case (ANYELEMENTOID):
|
case (ANYELEMENTOID):
|
||||||
|
case (ANYENUMOID):
|
||||||
result = GENERIC_TYPE;
|
result = GENERIC_TYPE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1647,6 +1684,11 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
|
||||||
if (get_element_type(srctype) != InvalidOid)
|
if (get_element_type(srctype) != InvalidOid)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
/* Also accept any enum type as coercible to ANYENUM */
|
||||||
|
if (targettype == ANYENUMOID)
|
||||||
|
if (type_is_enum(srctype))
|
||||||
|
return true;
|
||||||
|
|
||||||
/* Else look in pg_cast */
|
/* Else look in pg_cast */
|
||||||
tuple = SearchSysCache(CASTSOURCETARGET,
|
tuple = SearchSysCache(CASTSOURCETARGET,
|
||||||
ObjectIdGetDatum(srctype),
|
ObjectIdGetDatum(srctype),
|
||||||
|
@ -1777,6 +1819,22 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we still haven't found a possibility, check for enums,
|
||||||
|
* and retry looking for a cast to or from ANYENUM. But don't
|
||||||
|
* mistakenly conclude that ANYENUM-to-some-enum-type is a
|
||||||
|
* trivial cast.
|
||||||
|
*/
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
if (type_is_enum(sourceTypeId))
|
||||||
|
result = find_coercion_pathway(targetTypeId, ANYENUMOID,
|
||||||
|
ccontext, funcid, arrayCoerce);
|
||||||
|
else if (sourceTypeId != ANYENUMOID && type_is_enum(targetTypeId))
|
||||||
|
result = find_coercion_pathway(ANYENUMOID, sourceTypeId,
|
||||||
|
ccontext, funcid, arrayCoerce);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -1813,7 +1871,7 @@ find_typmod_coercion_function(Oid typeId,
|
||||||
/* Check for a varlena array type (and not a domain) */
|
/* Check for a varlena array type (and not a domain) */
|
||||||
if (typeForm->typelem != InvalidOid &&
|
if (typeForm->typelem != InvalidOid &&
|
||||||
typeForm->typlen == -1 &&
|
typeForm->typlen == -1 &&
|
||||||
typeForm->typtype != 'd')
|
typeForm->typtype != TYPTYPE_DOMAIN)
|
||||||
{
|
{
|
||||||
/* Yes, switch our attention to the element type */
|
/* Yes, switch our attention to the element type */
|
||||||
typeId = typeForm->typelem;
|
typeId = typeForm->typelem;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.215 2007/03/27 23:21:10 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.216 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1627,7 +1627,7 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
|
||||||
break;
|
break;
|
||||||
case RTE_FUNCTION:
|
case RTE_FUNCTION:
|
||||||
toid = exprType(rte->funcexpr);
|
toid = exprType(rte->funcexpr);
|
||||||
if (toid == RECORDOID || get_typtype(toid) == 'c')
|
if (type_is_rowtype(toid))
|
||||||
{
|
{
|
||||||
/* func returns composite; same as relation case */
|
/* func returns composite; same as relation case */
|
||||||
result = (Node *) makeVar(vnum,
|
result = (Node *) makeVar(vnum,
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.94 2007/02/01 19:10:27 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.95 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -886,8 +886,8 @@ make_scalar_array_op(ParseState *pstate, List *opname,
|
||||||
declared_arg_types[1] = opform->oprright;
|
declared_arg_types[1] = opform->oprright;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* enforce consistency with ANYARRAY and ANYELEMENT argument and return
|
* enforce consistency with polymorphic argument and return types,
|
||||||
* types, possibly adjusting return type or declared_arg_types (which will
|
* possibly adjusting return type or declared_arg_types (which will
|
||||||
* be used as the cast destination by make_fn_arguments)
|
* be used as the cast destination by make_fn_arguments)
|
||||||
*/
|
*/
|
||||||
rettype = enforce_generic_type_consistency(actual_arg_types,
|
rettype = enforce_generic_type_consistency(actual_arg_types,
|
||||||
|
@ -911,15 +911,25 @@ make_scalar_array_op(ParseState *pstate, List *opname,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now switch back to the array type on the right, arranging for any
|
* Now switch back to the array type on the right, arranging for any
|
||||||
* needed cast to be applied.
|
* needed cast to be applied. Beware of polymorphic operators here;
|
||||||
|
* enforce_generic_type_consistency may or may not have replaced a
|
||||||
|
* polymorphic type with a real one.
|
||||||
*/
|
*/
|
||||||
res_atypeId = get_array_type(declared_arg_types[1]);
|
if (IsPolymorphicType(declared_arg_types[1]))
|
||||||
if (!OidIsValid(res_atypeId))
|
{
|
||||||
ereport(ERROR,
|
/* assume the actual array type is OK */
|
||||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
res_atypeId = atypeId;
|
||||||
errmsg("could not find array type for data type %s",
|
}
|
||||||
format_type_be(declared_arg_types[1])),
|
else
|
||||||
parser_errposition(pstate, location)));
|
{
|
||||||
|
res_atypeId = get_array_type(declared_arg_types[1]);
|
||||||
|
if (!OidIsValid(res_atypeId))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||||
|
errmsg("could not find array type for data type %s",
|
||||||
|
format_type_be(declared_arg_types[1])),
|
||||||
|
parser_errposition(pstate, location)));
|
||||||
|
}
|
||||||
actual_arg_types[1] = atypeId;
|
actual_arg_types[1] = atypeId;
|
||||||
declared_arg_types[1] = res_atypeId;
|
declared_arg_types[1] = res_atypeId;
|
||||||
|
|
||||||
|
@ -986,8 +996,8 @@ make_op_expr(ParseState *pstate, Operator op,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* enforce consistency with ANYARRAY and ANYELEMENT argument and return
|
* enforce consistency with polymorphic argument and return types,
|
||||||
* types, possibly adjusting return type or declared_arg_types (which will
|
* possibly adjusting return type or declared_arg_types (which will
|
||||||
* be used as the cast destination by make_fn_arguments)
|
* be used as the cast destination by make_fn_arguments)
|
||||||
*/
|
*/
|
||||||
rettype = enforce_generic_type_consistency(actual_arg_types,
|
rettype = enforce_generic_type_consistency(actual_arg_types,
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.87 2007/01/05 22:19:34 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.88 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -398,16 +398,6 @@ typeByVal(Type t)
|
||||||
return typ->typbyval;
|
return typ->typbyval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* given type (as type struct), return the value of its 'typtype' attribute.*/
|
|
||||||
char
|
|
||||||
typeTypType(Type t)
|
|
||||||
{
|
|
||||||
Form_pg_type typ;
|
|
||||||
|
|
||||||
typ = (Form_pg_type) GETSTRUCT(t);
|
|
||||||
return typ->typtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* given type (as type struct), return the name of type */
|
/* given type (as type struct), return the name of type */
|
||||||
char *
|
char *
|
||||||
typeTypeName(Type t)
|
typeTypeName(Type t)
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.275 2007/03/26 16:58:39 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.276 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -337,6 +337,7 @@ check_xact_readonly(Node *parsetree)
|
||||||
case T_CreateTableSpaceStmt:
|
case T_CreateTableSpaceStmt:
|
||||||
case T_CreateTrigStmt:
|
case T_CreateTrigStmt:
|
||||||
case T_CompositeTypeStmt:
|
case T_CompositeTypeStmt:
|
||||||
|
case T_CreateEnumStmt:
|
||||||
case T_ViewStmt:
|
case T_ViewStmt:
|
||||||
case T_DropCastStmt:
|
case T_DropCastStmt:
|
||||||
case T_DropStmt:
|
case T_DropStmt:
|
||||||
|
@ -779,6 +780,10 @@ ProcessUtility(Node *parsetree,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_CreateEnumStmt: /* CREATE TYPE (enum) */
|
||||||
|
DefineEnum((CreateEnumStmt *) parsetree);
|
||||||
|
break;
|
||||||
|
|
||||||
case T_ViewStmt: /* CREATE VIEW */
|
case T_ViewStmt: /* CREATE VIEW */
|
||||||
DefineView((ViewStmt *) parsetree, queryString);
|
DefineView((ViewStmt *) parsetree, queryString);
|
||||||
break;
|
break;
|
||||||
|
@ -1640,6 +1645,10 @@ CreateCommandTag(Node *parsetree)
|
||||||
tag = "CREATE TYPE";
|
tag = "CREATE TYPE";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_CreateEnumStmt:
|
||||||
|
tag = "CREATE TYPE";
|
||||||
|
break;
|
||||||
|
|
||||||
case T_ViewStmt:
|
case T_ViewStmt:
|
||||||
tag = "CREATE VIEW";
|
tag = "CREATE VIEW";
|
||||||
break;
|
break;
|
||||||
|
@ -2075,6 +2084,10 @@ GetCommandLogLevel(Node *parsetree)
|
||||||
lev = LOGSTMT_DDL;
|
lev = LOGSTMT_DDL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_CreateEnumStmt:
|
||||||
|
lev = LOGSTMT_DDL;
|
||||||
|
break;
|
||||||
|
|
||||||
case T_ViewStmt:
|
case T_ViewStmt:
|
||||||
lev = LOGSTMT_DDL;
|
lev = LOGSTMT_DDL;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
# Makefile for utils/adt
|
# Makefile for utils/adt
|
||||||
#
|
#
|
||||||
# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.63 2007/01/28 16:16:52 neilc Exp $
|
# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.64 2007/04/02 03:49:39 tgl Exp $
|
||||||
#
|
#
|
||||||
|
|
||||||
subdir = src/backend/utils/adt
|
subdir = src/backend/utils/adt
|
||||||
|
@ -17,7 +17,7 @@ endif
|
||||||
|
|
||||||
OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
|
OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
|
||||||
cash.o char.o date.o datetime.o datum.o domains.o \
|
cash.o char.o date.o datetime.o datum.o domains.o \
|
||||||
float.o format_type.o \
|
enum.o float.o format_type.o \
|
||||||
geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o \
|
geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o \
|
||||||
misc.o nabstime.o name.o not_in.o numeric.o numutils.o \
|
misc.o nabstime.o name.o not_in.o numeric.o numutils.o \
|
||||||
oid.o oracle_compat.o pseudotypes.o rowtypes.o \
|
oid.o oracle_compat.o pseudotypes.o rowtypes.o \
|
||||||
|
|
|
@ -0,0 +1,409 @@
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* enum.c
|
||||||
|
* I/O functions, operators, aggregates etc for enum types
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006-2007, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* IDENTIFICATION
|
||||||
|
* $PostgreSQL: pgsql/src/backend/utils/adt/enum.c,v 1.1 2007/04/02 03:49:39 tgl Exp $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "catalog/pg_enum.h"
|
||||||
|
#include "fmgr.h"
|
||||||
|
#include "utils/array.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
|
static Oid cstring_enum(char *name, Oid enumtypoid);
|
||||||
|
static char *enum_cstring(Oid enumval);
|
||||||
|
static ArrayType *enum_range_internal(Oid enumtypoid, Oid lower, Oid upper);
|
||||||
|
static int enum_elem_cmp(const void *left, const void *right);
|
||||||
|
|
||||||
|
|
||||||
|
/* Basic I/O support */
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_in(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
char *name = PG_GETARG_CSTRING(0);
|
||||||
|
Oid enumtypoid = PG_GETARG_OID(1);
|
||||||
|
|
||||||
|
PG_RETURN_OID(cstring_enum(name, enumtypoid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* guts of enum_in and text-to-enum */
|
||||||
|
static Oid
|
||||||
|
cstring_enum(char *name, Oid enumtypoid)
|
||||||
|
{
|
||||||
|
HeapTuple tup;
|
||||||
|
Oid enumoid;
|
||||||
|
|
||||||
|
tup = SearchSysCache(ENUMTYPOIDNAME,
|
||||||
|
ObjectIdGetDatum(enumtypoid),
|
||||||
|
CStringGetDatum(name),
|
||||||
|
0, 0);
|
||||||
|
if (tup == NULL)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
|
errmsg("invalid input value for enum %s: \"%s\"",
|
||||||
|
format_type_be(enumtypoid),
|
||||||
|
name)));
|
||||||
|
|
||||||
|
enumoid = HeapTupleGetOid(tup);
|
||||||
|
|
||||||
|
ReleaseSysCache(tup);
|
||||||
|
return enumoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_out(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid enumoid = PG_GETARG_OID(0);
|
||||||
|
|
||||||
|
PG_RETURN_CSTRING(enum_cstring(enumoid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* guts of enum_out and enum-to-text */
|
||||||
|
static char *
|
||||||
|
enum_cstring(Oid enumval)
|
||||||
|
{
|
||||||
|
HeapTuple tup;
|
||||||
|
Form_pg_enum en;
|
||||||
|
char *label;
|
||||||
|
|
||||||
|
tup = SearchSysCache(ENUMOID,
|
||||||
|
ObjectIdGetDatum(enumval),
|
||||||
|
0, 0, 0);
|
||||||
|
if (tup == NULL)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
|
||||||
|
errmsg("invalid internal value for enum: %u",
|
||||||
|
enumval)));
|
||||||
|
en = (Form_pg_enum) GETSTRUCT(tup);
|
||||||
|
|
||||||
|
label = pstrdup(NameStr(en->enumlabel));
|
||||||
|
|
||||||
|
ReleaseSysCache(tup);
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comparison functions and related */
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_lt(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid a = PG_GETARG_OID(0);
|
||||||
|
Oid b = PG_GETARG_OID(1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(a < b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_le(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid a = PG_GETARG_OID(0);
|
||||||
|
Oid b = PG_GETARG_OID(1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(a <= b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_eq(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid a = PG_GETARG_OID(0);
|
||||||
|
Oid b = PG_GETARG_OID(1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_ne(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid a = PG_GETARG_OID(0);
|
||||||
|
Oid b = PG_GETARG_OID(1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(a != b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_ge(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid a = PG_GETARG_OID(0);
|
||||||
|
Oid b = PG_GETARG_OID(1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(a >= b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_gt(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid a = PG_GETARG_OID(0);
|
||||||
|
Oid b = PG_GETARG_OID(1);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(a > b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_smaller(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid a = PG_GETARG_OID(0);
|
||||||
|
Oid b = PG_GETARG_OID(1);
|
||||||
|
|
||||||
|
PG_RETURN_OID(a <= b ? a : b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_larger(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid a = PG_GETARG_OID(0);
|
||||||
|
Oid b = PG_GETARG_OID(1);
|
||||||
|
|
||||||
|
PG_RETURN_OID(a >= b ? a : b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_cmp(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid a = PG_GETARG_OID(0);
|
||||||
|
Oid b = PG_GETARG_OID(1);
|
||||||
|
|
||||||
|
if (a > b)
|
||||||
|
PG_RETURN_INT32(1);
|
||||||
|
else if (a == b)
|
||||||
|
PG_RETURN_INT32(0);
|
||||||
|
else
|
||||||
|
PG_RETURN_INT32(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Casts between text and enum */
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_text(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid enumval = PG_GETARG_OID(0);
|
||||||
|
text *result;
|
||||||
|
char *cstr;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
cstr = enum_cstring(enumval);
|
||||||
|
len = strlen(cstr);
|
||||||
|
result = (text *) palloc(VARHDRSZ + len);
|
||||||
|
SET_VARSIZE(result, VARHDRSZ + len);
|
||||||
|
memcpy(VARDATA(result), cstr, len);
|
||||||
|
pfree(cstr);
|
||||||
|
PG_RETURN_TEXT_P(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
text_enum(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
text *textval = PG_GETARG_TEXT_P(0);
|
||||||
|
Oid enumtypoid;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We rely on being able to get the specific enum type from the calling
|
||||||
|
* expression tree.
|
||||||
|
*/
|
||||||
|
enumtypoid = get_fn_expr_rettype(fcinfo->flinfo);
|
||||||
|
if (enumtypoid == InvalidOid)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("could not determine actual enum type")));
|
||||||
|
|
||||||
|
str = DatumGetCString(DirectFunctionCall1(textout,
|
||||||
|
PointerGetDatum(textval)));
|
||||||
|
PG_RETURN_OID(cstring_enum(str, enumtypoid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enum programming support functions */
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_first(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid enumtypoid;
|
||||||
|
Oid min = InvalidOid;
|
||||||
|
CatCList *list;
|
||||||
|
int num, i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We rely on being able to get the specific enum type from the calling
|
||||||
|
* expression tree. Notice that the actual value of the argument isn't
|
||||||
|
* examined at all; in particular it might be NULL.
|
||||||
|
*/
|
||||||
|
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
||||||
|
if (enumtypoid == InvalidOid)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("could not determine actual enum type")));
|
||||||
|
|
||||||
|
list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
|
||||||
|
ObjectIdGetDatum(enumtypoid),
|
||||||
|
0, 0, 0);
|
||||||
|
num = list->n_members;
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
Oid valoid = HeapTupleHeaderGetOid(list->members[i]->tuple.t_data);
|
||||||
|
if (!OidIsValid(min) || valoid < min)
|
||||||
|
min = valoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseCatCacheList(list);
|
||||||
|
|
||||||
|
if (!OidIsValid(min)) /* should not happen */
|
||||||
|
elog(ERROR, "no values found for enum %s",
|
||||||
|
format_type_be(enumtypoid));
|
||||||
|
|
||||||
|
PG_RETURN_OID(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datum
|
||||||
|
enum_last(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid enumtypoid;
|
||||||
|
Oid max = InvalidOid;
|
||||||
|
CatCList *list;
|
||||||
|
int num, i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We rely on being able to get the specific enum type from the calling
|
||||||
|
* expression tree. Notice that the actual value of the argument isn't
|
||||||
|
* examined at all; in particular it might be NULL.
|
||||||
|
*/
|
||||||
|
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
||||||
|
if (enumtypoid == InvalidOid)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("could not determine actual enum type")));
|
||||||
|
|
||||||
|
list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
|
||||||
|
ObjectIdGetDatum(enumtypoid),
|
||||||
|
0, 0, 0);
|
||||||
|
num = list->n_members;
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
Oid valoid = HeapTupleHeaderGetOid(list->members[i]->tuple.t_data);
|
||||||
|
if(!OidIsValid(max) || valoid > max)
|
||||||
|
max = valoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseCatCacheList(list);
|
||||||
|
|
||||||
|
if (!OidIsValid(max)) /* should not happen */
|
||||||
|
elog(ERROR, "no values found for enum %s",
|
||||||
|
format_type_be(enumtypoid));
|
||||||
|
|
||||||
|
PG_RETURN_OID(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2-argument variant of enum_range */
|
||||||
|
Datum
|
||||||
|
enum_range_bounds(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid lower;
|
||||||
|
Oid upper;
|
||||||
|
Oid enumtypoid;
|
||||||
|
|
||||||
|
if (PG_ARGISNULL(0))
|
||||||
|
lower = InvalidOid;
|
||||||
|
else
|
||||||
|
lower = PG_GETARG_OID(0);
|
||||||
|
if (PG_ARGISNULL(1))
|
||||||
|
upper = InvalidOid;
|
||||||
|
else
|
||||||
|
upper = PG_GETARG_OID(1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We rely on being able to get the specific enum type from the calling
|
||||||
|
* expression tree. The generic type mechanism should have ensured that
|
||||||
|
* both are of the same type.
|
||||||
|
*/
|
||||||
|
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
||||||
|
if (enumtypoid == InvalidOid)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("could not determine actual enum type")));
|
||||||
|
|
||||||
|
PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid, lower, upper));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 1-argument variant of enum_range */
|
||||||
|
Datum
|
||||||
|
enum_range_all(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid enumtypoid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We rely on being able to get the specific enum type from the calling
|
||||||
|
* expression tree. Notice that the actual value of the argument isn't
|
||||||
|
* examined at all; in particular it might be NULL.
|
||||||
|
*/
|
||||||
|
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
||||||
|
if (enumtypoid == InvalidOid)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("could not determine actual enum type")));
|
||||||
|
|
||||||
|
PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid,
|
||||||
|
InvalidOid, InvalidOid));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ArrayType *
|
||||||
|
enum_range_internal(Oid enumtypoid, Oid lower, Oid upper)
|
||||||
|
{
|
||||||
|
ArrayType *result;
|
||||||
|
CatCList *list;
|
||||||
|
int total, i, j;
|
||||||
|
Datum *elems;
|
||||||
|
|
||||||
|
list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
|
||||||
|
ObjectIdGetDatum(enumtypoid),
|
||||||
|
0, 0, 0);
|
||||||
|
total = list->n_members;
|
||||||
|
|
||||||
|
elems = (Datum *) palloc(total * sizeof(Datum));
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
for (i = 0; i < total; i++)
|
||||||
|
{
|
||||||
|
Oid val = HeapTupleGetOid(&(list->members[i]->tuple));
|
||||||
|
|
||||||
|
if ((!OidIsValid(lower) || lower <= val) &&
|
||||||
|
(!OidIsValid(upper) || val <= upper))
|
||||||
|
elems[j++] = ObjectIdGetDatum(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shouldn't need the cache anymore */
|
||||||
|
ReleaseCatCacheList(list);
|
||||||
|
|
||||||
|
/* sort results into OID order */
|
||||||
|
qsort(elems, j, sizeof(Datum), enum_elem_cmp);
|
||||||
|
|
||||||
|
/* note this hardwires some details about the representation of Oid */
|
||||||
|
result = construct_array(elems, j, enumtypoid, sizeof(Oid), true, 'i');
|
||||||
|
|
||||||
|
pfree(elems);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qsort comparison function for Datums that are OIDs */
|
||||||
|
static int
|
||||||
|
enum_elem_cmp(const void *left, const void *right)
|
||||||
|
{
|
||||||
|
Oid l = DatumGetObjectId(*((const Datum *) left));
|
||||||
|
Oid r = DatumGetObjectId(*((const Datum *) right));
|
||||||
|
|
||||||
|
if (l < r)
|
||||||
|
return -1;
|
||||||
|
if (l > r)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.46 2007/01/05 22:19:40 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.47 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -148,7 +148,7 @@ format_type_internal(Oid type_oid, int32 typemod,
|
||||||
|
|
||||||
if (array_base_type != InvalidOid &&
|
if (array_base_type != InvalidOid &&
|
||||||
typeform->typstorage != 'p' &&
|
typeform->typstorage != 'p' &&
|
||||||
typeform->typtype != 'd')
|
typeform->typtype != TYPTYPE_DOMAIN)
|
||||||
{
|
{
|
||||||
/* Switch our attention to the array element type */
|
/* Switch our attention to the array element type */
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.18 2007/01/05 22:19:41 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.19 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -163,6 +163,31 @@ anyarray_send(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* anyenum_in - input routine for pseudo-type ANYENUM.
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
anyenum_in(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("cannot accept a value of type anyenum")));
|
||||||
|
|
||||||
|
PG_RETURN_VOID(); /* keep compiler quiet */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* anyenum_out - output routine for pseudo-type ANYENUM.
|
||||||
|
*
|
||||||
|
* We may as well allow this, since enum_out will in fact work.
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
anyenum_out(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
return enum_out(fcinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* void_in - input routine for pseudo-type VOID.
|
* void_in - input routine for pseudo-type VOID.
|
||||||
*
|
*
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.38 2007/04/01 09:00:25 petere Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.39 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -2648,7 +2648,7 @@ map_sql_type_to_xml_name(Oid typeoid, int typmod)
|
||||||
Form_pg_type typtuple = (Form_pg_type) GETSTRUCT(tuple);
|
Form_pg_type typtuple = (Form_pg_type) GETSTRUCT(tuple);
|
||||||
|
|
||||||
appendStringInfoString(&result,
|
appendStringInfoString(&result,
|
||||||
map_multipart_sql_identifier_to_xml_name((typtuple->typtype == 'd') ? "Domain" : "UDT",
|
map_multipart_sql_identifier_to_xml_name((typtuple->typtype == TYPTYPE_DOMAIN) ? "Domain" : "UDT",
|
||||||
get_database_name(MyDatabaseId),
|
get_database_name(MyDatabaseId),
|
||||||
get_namespace_name(typtuple->typnamespace),
|
get_namespace_name(typtuple->typnamespace),
|
||||||
NameStr(typtuple->typname)));
|
NameStr(typtuple->typname)));
|
||||||
|
@ -2877,7 +2877,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (get_typtype(typeoid) == 'd')
|
if (get_typtype(typeoid) == TYPTYPE_DOMAIN)
|
||||||
{
|
{
|
||||||
Oid base_typeoid;
|
Oid base_typeoid;
|
||||||
int32 base_typmod = -1;
|
int32 base_typmod = -1;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.150 2007/03/19 16:30:31 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.151 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Eventually, the index information should go through here, too.
|
* Eventually, the index information should go through here, too.
|
||||||
|
@ -1770,7 +1770,7 @@ getTypeIOParam(HeapTuple typeTuple)
|
||||||
* own type OID as parameter. (As of 8.2, domains must get their own OID
|
* own type OID as parameter. (As of 8.2, domains must get their own OID
|
||||||
* even if their base type is an array.)
|
* even if their base type is an array.)
|
||||||
*/
|
*/
|
||||||
if (typeStruct->typtype == 'b' && OidIsValid(typeStruct->typelem))
|
if (typeStruct->typtype == TYPTYPE_BASE && OidIsValid(typeStruct->typelem))
|
||||||
return typeStruct->typelem;
|
return typeStruct->typelem;
|
||||||
else
|
else
|
||||||
return HeapTupleGetOid(typeTuple);
|
return HeapTupleGetOid(typeTuple);
|
||||||
|
@ -2022,7 +2022,7 @@ getBaseTypeAndTypmod(Oid typid, int32 *typmod)
|
||||||
if (!HeapTupleIsValid(tup))
|
if (!HeapTupleIsValid(tup))
|
||||||
elog(ERROR, "cache lookup failed for type %u", typid);
|
elog(ERROR, "cache lookup failed for type %u", typid);
|
||||||
typTup = (Form_pg_type) GETSTRUCT(tup);
|
typTup = (Form_pg_type) GETSTRUCT(tup);
|
||||||
if (typTup->typtype != 'd')
|
if (typTup->typtype != TYPTYPE_DOMAIN)
|
||||||
{
|
{
|
||||||
/* Not a domain, so done */
|
/* Not a domain, so done */
|
||||||
ReleaseSysCache(tup);
|
ReleaseSysCache(tup);
|
||||||
|
@ -2128,7 +2128,17 @@ get_typtype(Oid typid)
|
||||||
bool
|
bool
|
||||||
type_is_rowtype(Oid typid)
|
type_is_rowtype(Oid typid)
|
||||||
{
|
{
|
||||||
return (typid == RECORDOID || get_typtype(typid) == 'c');
|
return (typid == RECORDOID || get_typtype(typid) == TYPTYPE_COMPOSITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* type_is_enum
|
||||||
|
* Returns true if the given type is an enum type.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
type_is_enum(Oid typid)
|
||||||
|
{
|
||||||
|
return (get_typtype(typid) == TYPTYPE_ENUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.111 2007/02/14 01:58:57 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.112 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* These routines allow the parser/planner/executor to perform
|
* These routines allow the parser/planner/executor to perform
|
||||||
|
@ -31,6 +31,7 @@
|
||||||
#include "catalog/pg_constraint.h"
|
#include "catalog/pg_constraint.h"
|
||||||
#include "catalog/pg_conversion.h"
|
#include "catalog/pg_conversion.h"
|
||||||
#include "catalog/pg_database.h"
|
#include "catalog/pg_database.h"
|
||||||
|
#include "catalog/pg_enum.h"
|
||||||
#include "catalog/pg_language.h"
|
#include "catalog/pg_language.h"
|
||||||
#include "catalog/pg_namespace.h"
|
#include "catalog/pg_namespace.h"
|
||||||
#include "catalog/pg_opclass.h"
|
#include "catalog/pg_opclass.h"
|
||||||
|
@ -335,6 +336,30 @@ static const struct cachedesc cacheinfo[] = {
|
||||||
},
|
},
|
||||||
4
|
4
|
||||||
},
|
},
|
||||||
|
{EnumRelationId, /* ENUMOID */
|
||||||
|
EnumOidIndexId,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
{
|
||||||
|
ObjectIdAttributeNumber,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
256
|
||||||
|
},
|
||||||
|
{EnumRelationId, /* ENUMTYPOIDNAME */
|
||||||
|
EnumTypIdLabelIndexId,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
Anum_pg_enum_enumtypid,
|
||||||
|
Anum_pg_enum_enumlabel,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
256
|
||||||
|
},
|
||||||
{IndexRelationId, /* INDEXRELID */
|
{IndexRelationId, /* INDEXRELID */
|
||||||
IndexRelidIndexId,
|
IndexRelidIndexId,
|
||||||
Anum_pg_index_indrelid,
|
Anum_pg_index_indrelid,
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.24 2007/01/05 22:19:43 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.25 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -275,7 +275,7 @@ lookup_type_cache(Oid type_id, int flags)
|
||||||
*/
|
*/
|
||||||
if ((flags & TYPECACHE_TUPDESC) &&
|
if ((flags & TYPECACHE_TUPDESC) &&
|
||||||
typentry->tupDesc == NULL &&
|
typentry->tupDesc == NULL &&
|
||||||
typentry->typtype == 'c')
|
typentry->typtype == TYPTYPE_COMPOSITE)
|
||||||
{
|
{
|
||||||
Relation rel;
|
Relation rel;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
|
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.33 2007/02/01 19:10:28 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.34 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -193,8 +193,8 @@ shutdown_MultiFuncCall(Datum arg)
|
||||||
* only when we couldn't resolve the actual rowtype for lack of information.
|
* only when we couldn't resolve the actual rowtype for lack of information.
|
||||||
*
|
*
|
||||||
* The other hard case that this handles is resolution of polymorphism.
|
* The other hard case that this handles is resolution of polymorphism.
|
||||||
* We will never return ANYELEMENT or ANYARRAY, either as a scalar result
|
* We will never return ANYELEMENT, ANYARRAY or ANYENUM, either as a scalar
|
||||||
* type or as a component of a rowtype.
|
* result type or as a component of a rowtype.
|
||||||
*
|
*
|
||||||
* This function is relatively expensive --- in a function returning set,
|
* This function is relatively expensive --- in a function returning set,
|
||||||
* try to call it only the first time through.
|
* try to call it only the first time through.
|
||||||
|
@ -338,7 +338,7 @@ internal_get_result_type(Oid funcid,
|
||||||
/*
|
/*
|
||||||
* If scalar polymorphic result, try to resolve it.
|
* If scalar polymorphic result, try to resolve it.
|
||||||
*/
|
*/
|
||||||
if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
|
if (IsPolymorphicType(rettype))
|
||||||
{
|
{
|
||||||
Oid newrettype = exprType(call_expr);
|
Oid newrettype = exprType(call_expr);
|
||||||
|
|
||||||
|
@ -389,8 +389,8 @@ internal_get_result_type(Oid funcid,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given the result tuple descriptor for a function with OUT parameters,
|
* Given the result tuple descriptor for a function with OUT parameters,
|
||||||
* replace any polymorphic columns (ANYELEMENT/ANYARRAY) with correct data
|
* replace any polymorphic columns (ANYELEMENT/ANYARRAY/ANYENUM) with correct
|
||||||
* types deduced from the input arguments. Returns TRUE if able to deduce
|
* data types deduced from the input arguments. Returns TRUE if able to deduce
|
||||||
* all types, FALSE if not.
|
* all types, FALSE if not.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
|
@ -401,6 +401,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
|
||||||
int nargs = declared_args->dim1;
|
int nargs = declared_args->dim1;
|
||||||
bool have_anyelement_result = false;
|
bool have_anyelement_result = false;
|
||||||
bool have_anyarray_result = false;
|
bool have_anyarray_result = false;
|
||||||
|
bool have_anyenum = false;
|
||||||
Oid anyelement_type = InvalidOid;
|
Oid anyelement_type = InvalidOid;
|
||||||
Oid anyarray_type = InvalidOid;
|
Oid anyarray_type = InvalidOid;
|
||||||
int i;
|
int i;
|
||||||
|
@ -416,6 +417,10 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
|
||||||
case ANYARRAYOID:
|
case ANYARRAYOID:
|
||||||
have_anyarray_result = true;
|
have_anyarray_result = true;
|
||||||
break;
|
break;
|
||||||
|
case ANYENUMOID:
|
||||||
|
have_anyelement_result = true;
|
||||||
|
have_anyenum = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -435,6 +440,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
|
||||||
switch (declared_args->values[i])
|
switch (declared_args->values[i])
|
||||||
{
|
{
|
||||||
case ANYELEMENTOID:
|
case ANYELEMENTOID:
|
||||||
|
case ANYENUMOID:
|
||||||
if (!OidIsValid(anyelement_type))
|
if (!OidIsValid(anyelement_type))
|
||||||
anyelement_type = get_call_expr_argtype(call_expr, i);
|
anyelement_type = get_call_expr_argtype(call_expr, i);
|
||||||
break;
|
break;
|
||||||
|
@ -461,12 +467,17 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
|
||||||
anyelement_type,
|
anyelement_type,
|
||||||
ANYELEMENTOID);
|
ANYELEMENTOID);
|
||||||
|
|
||||||
|
/* Check for enum if needed */
|
||||||
|
if (have_anyenum && !type_is_enum(anyelement_type))
|
||||||
|
return false;
|
||||||
|
|
||||||
/* And finally replace the tuple column types as needed */
|
/* And finally replace the tuple column types as needed */
|
||||||
for (i = 0; i < natts; i++)
|
for (i = 0; i < natts; i++)
|
||||||
{
|
{
|
||||||
switch (tupdesc->attrs[i]->atttypid)
|
switch (tupdesc->attrs[i]->atttypid)
|
||||||
{
|
{
|
||||||
case ANYELEMENTOID:
|
case ANYELEMENTOID:
|
||||||
|
case ANYENUMOID:
|
||||||
TupleDescInitEntry(tupdesc, i + 1,
|
TupleDescInitEntry(tupdesc, i + 1,
|
||||||
NameStr(tupdesc->attrs[i]->attname),
|
NameStr(tupdesc->attrs[i]->attname),
|
||||||
anyelement_type,
|
anyelement_type,
|
||||||
|
@ -490,8 +501,8 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given the declared argument types and modes for a function,
|
* Given the declared argument types and modes for a function,
|
||||||
* replace any polymorphic types (ANYELEMENT/ANYARRAY) with correct data
|
* replace any polymorphic types (ANYELEMENT/ANYARRAY/ANYENUM) with correct
|
||||||
* types deduced from the input arguments. Returns TRUE if able to deduce
|
* data types deduced from the input arguments. Returns TRUE if able to deduce
|
||||||
* all types, FALSE if not. This is the same logic as
|
* all types, FALSE if not. This is the same logic as
|
||||||
* resolve_polymorphic_tupdesc, but with a different argument representation.
|
* resolve_polymorphic_tupdesc, but with a different argument representation.
|
||||||
*
|
*
|
||||||
|
@ -517,6 +528,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
|
||||||
switch (argtypes[i])
|
switch (argtypes[i])
|
||||||
{
|
{
|
||||||
case ANYELEMENTOID:
|
case ANYELEMENTOID:
|
||||||
|
case ANYENUMOID:
|
||||||
if (argmode == PROARGMODE_OUT)
|
if (argmode == PROARGMODE_OUT)
|
||||||
have_anyelement_result = true;
|
have_anyelement_result = true;
|
||||||
else
|
else
|
||||||
|
@ -571,12 +583,15 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
|
||||||
anyelement_type,
|
anyelement_type,
|
||||||
ANYELEMENTOID);
|
ANYELEMENTOID);
|
||||||
|
|
||||||
|
/* XXX do we need to enforce ANYENUM here? I think not */
|
||||||
|
|
||||||
/* And finally replace the output column types as needed */
|
/* And finally replace the output column types as needed */
|
||||||
for (i = 0; i < numargs; i++)
|
for (i = 0; i < numargs; i++)
|
||||||
{
|
{
|
||||||
switch (argtypes[i])
|
switch (argtypes[i])
|
||||||
{
|
{
|
||||||
case ANYELEMENTOID:
|
case ANYELEMENTOID:
|
||||||
|
case ANYENUMOID:
|
||||||
argtypes[i] = anyelement_type;
|
argtypes[i] = anyelement_type;
|
||||||
break;
|
break;
|
||||||
case ANYARRAYOID:
|
case ANYARRAYOID:
|
||||||
|
@ -603,12 +618,13 @@ get_type_func_class(Oid typid)
|
||||||
{
|
{
|
||||||
switch (get_typtype(typid))
|
switch (get_typtype(typid))
|
||||||
{
|
{
|
||||||
case 'c':
|
case TYPTYPE_COMPOSITE:
|
||||||
return TYPEFUNC_COMPOSITE;
|
return TYPEFUNC_COMPOSITE;
|
||||||
case 'b':
|
case TYPTYPE_BASE:
|
||||||
case 'd':
|
case TYPTYPE_DOMAIN:
|
||||||
|
case TYPTYPE_ENUM:
|
||||||
return TYPEFUNC_SCALAR;
|
return TYPEFUNC_SCALAR;
|
||||||
case 'p':
|
case TYPTYPE_PSEUDO:
|
||||||
if (typid == RECORDOID)
|
if (typid == RECORDOID)
|
||||||
return TYPEFUNC_RECORD;
|
return TYPEFUNC_RECORD;
|
||||||
|
|
||||||
|
@ -840,7 +856,7 @@ get_func_result_name(Oid functionId)
|
||||||
* Given a pg_proc row for a function, return a tuple descriptor for the
|
* Given a pg_proc row for a function, return a tuple descriptor for the
|
||||||
* result rowtype, or NULL if the function does not have OUT parameters.
|
* result rowtype, or NULL if the function does not have OUT parameters.
|
||||||
*
|
*
|
||||||
* Note that this does not handle resolution of ANYELEMENT/ANYARRAY types;
|
* Note that this does not handle resolution of polymorphic types;
|
||||||
* that is deliberate.
|
* that is deliberate.
|
||||||
*/
|
*/
|
||||||
TupleDesc
|
TupleDesc
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
* by PostgreSQL
|
* by PostgreSQL
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.465 2007/03/26 16:58:39 tgl Exp $
|
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.466 2007/04/02 03:49:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -137,6 +137,7 @@ static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
|
||||||
static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
|
static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
|
||||||
static void dumpType(Archive *fout, TypeInfo *tinfo);
|
static void dumpType(Archive *fout, TypeInfo *tinfo);
|
||||||
static void dumpBaseType(Archive *fout, TypeInfo *tinfo);
|
static void dumpBaseType(Archive *fout, TypeInfo *tinfo);
|
||||||
|
static void dumpEnumType(Archive *fout, TypeInfo *tinfo);
|
||||||
static void dumpDomain(Archive *fout, TypeInfo *tinfo);
|
static void dumpDomain(Archive *fout, TypeInfo *tinfo);
|
||||||
static void dumpCompositeType(Archive *fout, TypeInfo *tinfo);
|
static void dumpCompositeType(Archive *fout, TypeInfo *tinfo);
|
||||||
static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
|
static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
|
||||||
|
@ -2085,7 +2086,7 @@ getTypes(int *numTypes)
|
||||||
*/
|
*/
|
||||||
tinfo[i].nDomChecks = 0;
|
tinfo[i].nDomChecks = 0;
|
||||||
tinfo[i].domChecks = NULL;
|
tinfo[i].domChecks = NULL;
|
||||||
if (tinfo[i].dobj.dump && tinfo[i].typtype == 'd')
|
if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_DOMAIN)
|
||||||
getDomainConstraints(&(tinfo[i]));
|
getDomainConstraints(&(tinfo[i]));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2097,7 +2098,7 @@ getTypes(int *numTypes)
|
||||||
* 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
|
||||||
* pg_depend entries for the type, which we don't want.
|
* pg_depend entries for the type, which we don't want.
|
||||||
*/
|
*/
|
||||||
if (tinfo[i].dobj.dump && tinfo[i].typtype == 'b')
|
if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_BASE)
|
||||||
{
|
{
|
||||||
stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
|
stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
|
||||||
stinfo->dobj.objType = DO_SHELL_TYPE;
|
stinfo->dobj.objType = DO_SHELL_TYPE;
|
||||||
|
@ -5119,12 +5120,91 @@ dumpType(Archive *fout, TypeInfo *tinfo)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Dump out in proper style */
|
/* Dump out in proper style */
|
||||||
if (tinfo->typtype == 'b')
|
if (tinfo->typtype == TYPTYPE_BASE)
|
||||||
dumpBaseType(fout, tinfo);
|
dumpBaseType(fout, tinfo);
|
||||||
else if (tinfo->typtype == 'd')
|
else if (tinfo->typtype == TYPTYPE_DOMAIN)
|
||||||
dumpDomain(fout, tinfo);
|
dumpDomain(fout, tinfo);
|
||||||
else if (tinfo->typtype == 'c')
|
else if (tinfo->typtype == TYPTYPE_COMPOSITE)
|
||||||
dumpCompositeType(fout, tinfo);
|
dumpCompositeType(fout, tinfo);
|
||||||
|
else if (tinfo->typtype == TYPTYPE_ENUM)
|
||||||
|
dumpEnumType(fout, tinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dumpEnumType
|
||||||
|
* writes out to fout the queries to recreate a user-defined enum type
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dumpEnumType(Archive *fout, TypeInfo *tinfo)
|
||||||
|
{
|
||||||
|
PQExpBuffer q = createPQExpBuffer();
|
||||||
|
PQExpBuffer delq = createPQExpBuffer();
|
||||||
|
PQExpBuffer query = createPQExpBuffer();
|
||||||
|
PGresult *res;
|
||||||
|
int num, i;
|
||||||
|
char *label;
|
||||||
|
|
||||||
|
/* Set proper schema search path so regproc references list correctly */
|
||||||
|
selectSourceSchema(tinfo->dobj.namespace->dobj.name);
|
||||||
|
|
||||||
|
appendPQExpBuffer(query, "SELECT enumlabel FROM pg_catalog.pg_enum "
|
||||||
|
"WHERE enumtypid = '%u'"
|
||||||
|
"ORDER BY oid",
|
||||||
|
tinfo->dobj.catId.oid);
|
||||||
|
|
||||||
|
res = PQexec(g_conn, query->data);
|
||||||
|
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
|
||||||
|
|
||||||
|
num = PQntuples(res);
|
||||||
|
/* should be at least 1 value */
|
||||||
|
if (num == 0)
|
||||||
|
{
|
||||||
|
write_msg(NULL, "No rows found for enum");
|
||||||
|
exit_nicely();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DROP must be fully qualified in case same name appears in pg_catalog.
|
||||||
|
* CASCADE shouldn't be required here as for normal types since the
|
||||||
|
* I/O functions are generic and do not get dropped.
|
||||||
|
*/
|
||||||
|
appendPQExpBuffer(delq, "DROP TYPE %s.",
|
||||||
|
fmtId(tinfo->dobj.namespace->dobj.name));
|
||||||
|
appendPQExpBuffer(delq, "%s;\n",
|
||||||
|
fmtId(tinfo->dobj.name));
|
||||||
|
appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (\n",
|
||||||
|
fmtId(tinfo->dobj.name));
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
label = PQgetvalue(res, i, 0);
|
||||||
|
if (i > 0)
|
||||||
|
appendPQExpBuffer(q, ",\n");
|
||||||
|
appendPQExpBuffer(q, " ");
|
||||||
|
appendStringLiteralAH(q, label, fout);
|
||||||
|
}
|
||||||
|
appendPQExpBuffer(q, "\n);\n");
|
||||||
|
|
||||||
|
ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
|
||||||
|
tinfo->dobj.name,
|
||||||
|
tinfo->dobj.namespace->dobj.name,
|
||||||
|
NULL,
|
||||||
|
tinfo->rolname, false,
|
||||||
|
"TYPE", q->data, delq->data, NULL,
|
||||||
|
tinfo->dobj.dependencies, tinfo->dobj.nDeps,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
|
/* Dump Type Comments */
|
||||||
|
resetPQExpBuffer(q);
|
||||||
|
|
||||||
|
appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
|
||||||
|
dumpComment(fout, q->data,
|
||||||
|
tinfo->dobj.namespace->dobj.name, tinfo->rolname,
|
||||||
|
tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
|
||||||
|
|
||||||
|
PQclear(res);
|
||||||
|
destroyPQExpBuffer(q);
|
||||||
|
destroyPQExpBuffer(delq);
|
||||||
|
destroyPQExpBuffer(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/access/hash.h,v 1.76 2007/01/30 01:33:36 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/access/hash.h,v 1.77 2007/04/02 03:49:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* modeled after Margo Seltzer's hash implementation for unix.
|
* modeled after Margo Seltzer's hash implementation for unix.
|
||||||
|
@ -258,6 +258,7 @@ extern Datum hashint2(PG_FUNCTION_ARGS);
|
||||||
extern Datum hashint4(PG_FUNCTION_ARGS);
|
extern Datum hashint4(PG_FUNCTION_ARGS);
|
||||||
extern Datum hashint8(PG_FUNCTION_ARGS);
|
extern Datum hashint8(PG_FUNCTION_ARGS);
|
||||||
extern Datum hashoid(PG_FUNCTION_ARGS);
|
extern Datum hashoid(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum hashenum(PG_FUNCTION_ARGS);
|
||||||
extern Datum hashfloat4(PG_FUNCTION_ARGS);
|
extern Datum hashfloat4(PG_FUNCTION_ARGS);
|
||||||
extern Datum hashfloat8(PG_FUNCTION_ARGS);
|
extern Datum hashfloat8(PG_FUNCTION_ARGS);
|
||||||
extern Datum hashoidvector(PG_FUNCTION_ARGS);
|
extern Datum hashoidvector(PG_FUNCTION_ARGS);
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.398 2007/04/01 09:56:02 petere Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.399 2007/04/02 03:49:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -53,6 +53,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200704011
|
#define CATALOG_VERSION_NO 200704012
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.98 2007/02/14 01:58:58 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.99 2007/04/02 03:49:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -146,6 +146,11 @@ DECLARE_UNIQUE_INDEX(pg_description_o_c_o_index, 2675, on pg_description using b
|
||||||
DECLARE_UNIQUE_INDEX(pg_shdescription_o_c_index, 2397, on pg_shdescription using btree(objoid oid_ops, classoid oid_ops));
|
DECLARE_UNIQUE_INDEX(pg_shdescription_o_c_index, 2397, on pg_shdescription using btree(objoid oid_ops, classoid oid_ops));
|
||||||
#define SharedDescriptionObjIndexId 2397
|
#define SharedDescriptionObjIndexId 2397
|
||||||
|
|
||||||
|
DECLARE_UNIQUE_INDEX(pg_enum_oid_index, 3502, on pg_enum using btree(oid oid_ops));
|
||||||
|
#define EnumOidIndexId 3502
|
||||||
|
DECLARE_UNIQUE_INDEX(pg_enum_typid_label_index, 3503, on pg_enum using btree(enumtypid oid_ops, enumlabel name_ops));
|
||||||
|
#define EnumTypIdLabelIndexId 3503
|
||||||
|
|
||||||
/* This following index is not used for a cache and is not unique */
|
/* This following index is not used for a cache and is not unique */
|
||||||
DECLARE_INDEX(pg_index_indrelid_index, 2678, on pg_index using btree(indrelid oid_ops));
|
DECLARE_INDEX(pg_index_indrelid_index, 2678, on pg_index using btree(indrelid oid_ops));
|
||||||
#define IndexIndrelidIndexId 2678
|
#define IndexIndrelidIndexId 2678
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_aggregate.h,v 1.61 2007/02/17 00:55:57 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_aggregate.h,v 1.62 2007/04/02 03:49:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
@ -118,6 +118,7 @@ DATA(insert ( 2130 numeric_larger - 1756 1700 _null_ ));
|
||||||
DATA(insert ( 2050 array_larger - 1073 2277 _null_ ));
|
DATA(insert ( 2050 array_larger - 1073 2277 _null_ ));
|
||||||
DATA(insert ( 2244 bpchar_larger - 1060 1042 _null_ ));
|
DATA(insert ( 2244 bpchar_larger - 1060 1042 _null_ ));
|
||||||
DATA(insert ( 2797 tidlarger - 2800 27 _null_ ));
|
DATA(insert ( 2797 tidlarger - 2800 27 _null_ ));
|
||||||
|
DATA(insert ( 3526 enum_larger - 3519 3500 _null_ ));
|
||||||
|
|
||||||
/* min */
|
/* min */
|
||||||
DATA(insert ( 2131 int8smaller - 412 20 _null_ ));
|
DATA(insert ( 2131 int8smaller - 412 20 _null_ ));
|
||||||
|
@ -139,6 +140,7 @@ DATA(insert ( 2146 numeric_smaller - 1754 1700 _null_ ));
|
||||||
DATA(insert ( 2051 array_smaller - 1072 2277 _null_ ));
|
DATA(insert ( 2051 array_smaller - 1072 2277 _null_ ));
|
||||||
DATA(insert ( 2245 bpchar_smaller - 1058 1042 _null_ ));
|
DATA(insert ( 2245 bpchar_smaller - 1058 1042 _null_ ));
|
||||||
DATA(insert ( 2798 tidsmaller - 2799 27 _null_ ));
|
DATA(insert ( 2798 tidsmaller - 2799 27 _null_ ));
|
||||||
|
DATA(insert ( 3527 enum_smaller - 3518 3500 _null_ ));
|
||||||
|
|
||||||
/* count */
|
/* count */
|
||||||
DATA(insert ( 2147 int8inc_any - 0 20 "0" ));
|
DATA(insert ( 2147 int8inc_any - 0 20 "0" ));
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_amop.h,v 1.79 2007/02/06 02:59:12 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_amop.h,v 1.80 2007/04/02 03:49:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
@ -636,4 +636,18 @@ DATA(insert ( 2745 2277 2277 2 f 2751 2742 ));
|
||||||
DATA(insert ( 2745 2277 2277 3 t 2752 2742 ));
|
DATA(insert ( 2745 2277 2277 3 t 2752 2742 ));
|
||||||
DATA(insert ( 2745 2277 2277 4 t 1070 2742 ));
|
DATA(insert ( 2745 2277 2277 4 t 1070 2742 ));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* btree enum_ops
|
||||||
|
*/
|
||||||
|
DATA(insert ( 3522 3500 3500 1 f 3518 403 ));
|
||||||
|
DATA(insert ( 3522 3500 3500 2 f 3520 403 ));
|
||||||
|
DATA(insert ( 3522 3500 3500 3 f 3516 403 ));
|
||||||
|
DATA(insert ( 3522 3500 3500 4 f 3521 403 ));
|
||||||
|
DATA(insert ( 3522 3500 3500 5 f 3519 403 ));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hash enum_ops
|
||||||
|
*/
|
||||||
|
DATA(insert ( 3523 3500 3500 1 f 3516 405 ));
|
||||||
|
|
||||||
#endif /* PG_AMOP_H */
|
#endif /* PG_AMOP_H */
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.63 2007/01/28 16:16:52 neilc Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_amproc.h,v 1.64 2007/04/02 03:49:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
@ -128,6 +128,7 @@ DATA(insert ( 2233 703 703 1 380 ));
|
||||||
DATA(insert ( 2234 704 704 1 381 ));
|
DATA(insert ( 2234 704 704 1 381 ));
|
||||||
DATA(insert ( 2789 27 27 1 2794 ));
|
DATA(insert ( 2789 27 27 1 2794 ));
|
||||||
DATA(insert ( 2968 2950 2950 1 2960 ));
|
DATA(insert ( 2968 2950 2950 1 2960 ));
|
||||||
|
DATA(insert ( 3522 3500 3500 1 3514 ));
|
||||||
|
|
||||||
|
|
||||||
/* hash */
|
/* hash */
|
||||||
|
@ -162,6 +163,7 @@ DATA(insert ( 2231 1042 1042 1 456 ));
|
||||||
DATA(insert ( 2232 19 19 1 455 ));
|
DATA(insert ( 2232 19 19 1 455 ));
|
||||||
DATA(insert ( 2235 1033 1033 1 329 ));
|
DATA(insert ( 2235 1033 1033 1 329 ));
|
||||||
DATA(insert ( 2969 2950 2950 1 2963 ));
|
DATA(insert ( 2969 2950 2950 1 2963 ));
|
||||||
|
DATA(insert ( 3523 3500 3500 1 3515 ));
|
||||||
|
|
||||||
|
|
||||||
/* gist */
|
/* gist */
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
|
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.31 2007/02/03 14:06:55 petere Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.32 2007/04/02 03:49:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
@ -403,4 +403,10 @@ DATA(insert ( 2950 25 2965 a ));
|
||||||
DATA(insert ( 1043 2950 2964 a ));
|
DATA(insert ( 1043 2950 2964 a ));
|
||||||
DATA(insert ( 2950 1043 2965 a ));
|
DATA(insert ( 2950 1043 2965 a ));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enums
|
||||||
|
*/
|
||||||
|
DATA(insert ( 3500 25 3532 e ));
|
||||||
|
DATA(insert ( 25 3500 3533 e ));
|
||||||
|
|
||||||
#endif /* PG_CAST_H */
|
#endif /* PG_CAST_H */
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* pg_enum.h
|
||||||
|
* definition of the system "enum" relation (pg_enum)
|
||||||
|
* along with the relation's initial contents.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006-2007, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
* $PostgreSQL: pgsql/src/include/catalog/pg_enum.h,v 1.1 2007/04/02 03:49:40 tgl Exp $
|
||||||
|
*
|
||||||
|
* NOTES
|
||||||
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
* information from the DATA() statements.
|
||||||
|
*
|
||||||
|
* XXX do NOT break up DATA() statements into multiple lines!
|
||||||
|
* the scripts are not as smart as you might think...
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#ifndef PG_ENUM_H
|
||||||
|
#define PG_ENUM_H
|
||||||
|
|
||||||
|
#include "nodes/pg_list.h"
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* postgres.h contains the system type definitions and the
|
||||||
|
* CATALOG(), BKI_BOOTSTRAP and DATA() sugar words so this file
|
||||||
|
* can be read by both genbki.sh and the C compiler.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* pg_enum definition. cpp turns this into
|
||||||
|
* typedef struct FormData_pg_enum
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
#define EnumRelationId 3501
|
||||||
|
|
||||||
|
CATALOG(pg_enum,3501)
|
||||||
|
{
|
||||||
|
Oid enumtypid; /* OID of owning enum type */
|
||||||
|
NameData enumlabel; /* text representation of enum value */
|
||||||
|
} FormData_pg_enum;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* Form_pg_enum corresponds to a pointer to a tuple with
|
||||||
|
* the format of pg_enum relation.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
typedef FormData_pg_enum *Form_pg_enum;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* compiler constants for pg_enum
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
#define Natts_pg_enum 2
|
||||||
|
#define Anum_pg_enum_enumtypid 1
|
||||||
|
#define Anum_pg_enum_enumlabel 2
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* pg_enum has no initial contents
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* prototypes for functions in pg_enum.c
|
||||||
|
*/
|
||||||
|
extern void EnumValuesCreate(Oid enumTypeOid, List *vals);
|
||||||
|
extern void EnumValuesDelete(Oid enumTypeOid);
|
||||||
|
|
||||||
|
#endif /* PG_ENUM_H */
|
|
@ -28,7 +28,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.74 2007/01/28 16:16:52 neilc Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_opclass.h,v 1.75 2007/04/02 03:49:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
@ -200,7 +200,9 @@ DATA(insert ( 2742 _timestamp_ops PGNSP PGUID 2745 1115 t 1114 ));
|
||||||
DATA(insert ( 2742 _money_ops PGNSP PGUID 2745 791 t 790 ));
|
DATA(insert ( 2742 _money_ops PGNSP PGUID 2745 791 t 790 ));
|
||||||
DATA(insert ( 2742 _reltime_ops PGNSP PGUID 2745 1024 t 703 ));
|
DATA(insert ( 2742 _reltime_ops PGNSP PGUID 2745 1024 t 703 ));
|
||||||
DATA(insert ( 2742 _tinterval_ops PGNSP PGUID 2745 1025 t 704 ));
|
DATA(insert ( 2742 _tinterval_ops PGNSP PGUID 2745 1025 t 704 ));
|
||||||
DATA(insert ( 403 uuid_ops PGNSP PGUID 2968 2950 t 0 ));
|
DATA(insert ( 403 uuid_ops PGNSP PGUID 2968 2950 t 0 ));
|
||||||
DATA(insert ( 405 uuid_ops PGNSP PGUID 2969 2950 t 0 ));
|
DATA(insert ( 405 uuid_ops PGNSP PGUID 2969 2950 t 0 ));
|
||||||
|
DATA(insert ( 403 enum_ops PGNSP PGUID 3522 3500 t 0 ));
|
||||||
|
DATA(insert ( 405 enum_ops PGNSP PGUID 3523 3500 t 0 ));
|
||||||
|
|
||||||
#endif /* PG_OPCLASS_H */
|
#endif /* PG_OPCLASS_H */
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.150 2007/02/06 02:59:12 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.151 2007/04/02 03:49:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
@ -903,6 +903,14 @@ DATA(insert OID = 2975 ( ">" PGNSP PGUID b f f 2950 2950 16 2974 2976 uuid_g
|
||||||
DATA(insert OID = 2976 ( "<=" PGNSP PGUID b f f 2950 2950 16 2977 2975 uuid_le scalarltsel scalarltjoinsel ));
|
DATA(insert OID = 2976 ( "<=" PGNSP PGUID b f f 2950 2950 16 2977 2975 uuid_le scalarltsel scalarltjoinsel ));
|
||||||
DATA(insert OID = 2977 ( ">=" PGNSP PGUID b f f 2950 2950 16 2976 2974 uuid_ge scalargtsel scalargtjoinsel ));
|
DATA(insert OID = 2977 ( ">=" PGNSP PGUID b f f 2950 2950 16 2976 2974 uuid_ge scalargtsel scalargtjoinsel ));
|
||||||
|
|
||||||
|
/* enum operators */
|
||||||
|
DATA(insert OID = 3516 ( "=" PGNSP PGUID b t t 3500 3500 16 3516 3517 enum_eq eqsel eqjoinsel ));
|
||||||
|
DATA(insert OID = 3517 ( "<>" PGNSP PGUID b f f 3500 3500 16 3517 3516 enum_ne neqsel neqjoinsel ));
|
||||||
|
DATA(insert OID = 3518 ( "<" PGNSP PGUID b f f 3500 3500 16 3519 3521 enum_lt scalarltsel scalarltjoinsel ));
|
||||||
|
DATA(insert OID = 3519 ( ">" PGNSP PGUID b f f 3500 3500 16 3518 3520 enum_gt scalargtsel scalargtjoinsel ));
|
||||||
|
DATA(insert OID = 3520 ( "<=" PGNSP PGUID b f f 3500 3500 16 3521 3519 enum_le scalarltsel scalarltjoinsel ));
|
||||||
|
DATA(insert OID = 3521 ( ">=" PGNSP PGUID b f f 3500 3500 16 3520 3518 enum_ge scalargtsel scalargtjoinsel ));
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* function prototypes
|
* function prototypes
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_opfamily.h,v 1.3 2007/01/28 16:16:52 neilc Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_opfamily.h,v 1.4 2007/04/02 03:49:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
@ -136,6 +136,8 @@ DATA(insert OID = 2595 ( 783 circle_ops PGNSP PGUID ));
|
||||||
DATA(insert OID = 2745 ( 2742 array_ops PGNSP PGUID ));
|
DATA(insert OID = 2745 ( 2742 array_ops PGNSP PGUID ));
|
||||||
DATA(insert OID = 2968 ( 403 uuid_ops PGNSP PGUID ));
|
DATA(insert OID = 2968 ( 403 uuid_ops PGNSP PGUID ));
|
||||||
DATA(insert OID = 2969 ( 405 uuid_ops PGNSP PGUID ));
|
DATA(insert OID = 2969 ( 405 uuid_ops PGNSP PGUID ));
|
||||||
|
DATA(insert OID = 3522 ( 403 enum_ops PGNSP PGUID ));
|
||||||
|
DATA(insert OID = 3523 ( 405 enum_ops PGNSP PGUID ));
|
||||||
|
|
||||||
|
|
||||||
#endif /* PG_OPFAMILY_H */
|
#endif /* PG_OPFAMILY_H */
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.453 2007/04/01 09:00:25 petere Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.454 2007/04/02 03:49:40 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The script catalog/genbki.sh reads this file and generates .bki
|
* The script catalog/genbki.sh reads this file and generates .bki
|
||||||
|
@ -4149,6 +4149,46 @@ DESCR("convert text to uuid");
|
||||||
DATA(insert OID = 2965 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "2950" _null_ _null_ _null_ uuid_text - _null_ ));
|
DATA(insert OID = 2965 ( text PGNSP PGUID 12 1 0 f f t f i 1 25 "2950" _null_ _null_ _null_ uuid_text - _null_ ));
|
||||||
DESCR("convert uuid to text");
|
DESCR("convert uuid to text");
|
||||||
|
|
||||||
|
/* enum related procs */
|
||||||
|
DATA(insert OID = 3504 ( anyenum_in PGNSP PGUID 12 1 0 f f t f i 1 3500 "2275" _null_ _null_ _null_ anyenum_in - _null_ ));
|
||||||
|
DESCR("I/O");
|
||||||
|
DATA(insert OID = 3505 ( anyenum_out PGNSP PGUID 12 1 0 f f t f s 1 2275 "3500" _null_ _null_ _null_ anyenum_out - _null_ ));
|
||||||
|
DESCR("I/O");
|
||||||
|
DATA(insert OID = 3506 ( enum_in PGNSP PGUID 12 1 0 f f t f s 2 3500 "2275 26" _null_ _null_ _null_ enum_in - _null_ ));
|
||||||
|
DESCR("I/O");
|
||||||
|
DATA(insert OID = 3507 ( enum_out PGNSP PGUID 12 1 0 f f t f s 1 2275 "3500" _null_ _null_ _null_ enum_out - _null_ ));
|
||||||
|
DESCR("I/O");
|
||||||
|
DATA(insert OID = 3508 ( enum_eq PGNSP PGUID 12 1 0 f f t f i 2 16 "3500 3500" _null_ _null_ _null_ enum_eq - _null_ ));
|
||||||
|
DESCR("equal");
|
||||||
|
DATA(insert OID = 3509 ( enum_ne PGNSP PGUID 12 1 0 f f t f i 2 16 "3500 3500" _null_ _null_ _null_ enum_ne - _null_ ));
|
||||||
|
DESCR("not equal");
|
||||||
|
DATA(insert OID = 3510 ( enum_lt PGNSP PGUID 12 1 0 f f t f i 2 16 "3500 3500" _null_ _null_ _null_ enum_lt - _null_ ));
|
||||||
|
DESCR("less-than");
|
||||||
|
DATA(insert OID = 3511 ( enum_gt PGNSP PGUID 12 1 0 f f t f i 2 16 "3500 3500" _null_ _null_ _null_ enum_gt - _null_ ));
|
||||||
|
DESCR("greater-than");
|
||||||
|
DATA(insert OID = 3512 ( enum_le PGNSP PGUID 12 1 0 f f t f i 2 16 "3500 3500" _null_ _null_ _null_ enum_le - _null_ ));
|
||||||
|
DESCR("less-than-or-equal");
|
||||||
|
DATA(insert OID = 3513 ( enum_ge PGNSP PGUID 12 1 0 f f t f i 2 16 "3500 3500" _null_ _null_ _null_ enum_ge - _null_ ));
|
||||||
|
DESCR("greater-than-or-equal");
|
||||||
|
DATA(insert OID = 3514 ( enum_cmp PGNSP PGUID 12 1 0 f f t f i 2 23 "3500 3500" _null_ _null_ _null_ enum_cmp - _null_ ));
|
||||||
|
DESCR("btree-less-equal-greater");
|
||||||
|
DATA(insert OID = 3515 ( hashenum PGNSP PGUID 12 1 0 f f t f i 1 23 "3500" _null_ _null_ _null_ hashenum - _null_ ));
|
||||||
|
DESCR("hash");
|
||||||
|
DATA(insert OID = 3524 ( enum_smaller PGNSP PGUID 12 1 0 f f t f i 2 3500 "3500 3500" _null_ _null_ _null_ enum_smaller - _null_ ));
|
||||||
|
DESCR("smaller of two");
|
||||||
|
DATA(insert OID = 3525 ( enum_larger PGNSP PGUID 12 1 0 f f t f i 2 3500 "3500 3500" _null_ _null_ _null_ enum_larger - _null_ ));
|
||||||
|
DESCR("larger of two");
|
||||||
|
DATA(insert OID = 3526 ( max PGNSP PGUID 12 1 0 t f f f i 1 3500 "3500" _null_ _null_ _null_ aggregate_dummy - _null_ ));
|
||||||
|
DATA(insert OID = 3527 ( min PGNSP PGUID 12 1 0 t f f f i 1 3500 "3500" _null_ _null_ _null_ aggregate_dummy - _null_ ));
|
||||||
|
DATA(insert OID = 3528 ( enum_first PGNSP PGUID 12 1 0 f f f f s 1 3500 "3500" _null_ _null_ _null_ enum_first - _null_ ));
|
||||||
|
DATA(insert OID = 3529 ( enum_last PGNSP PGUID 12 1 0 f f f f s 1 3500 "3500" _null_ _null_ _null_ enum_last - _null_ ));
|
||||||
|
DATA(insert OID = 3530 ( enum_range PGNSP PGUID 12 1 0 f f f f s 2 2277 "3500 3500" _null_ _null_ _null_ enum_range_bounds - _null_ ));
|
||||||
|
DATA(insert OID = 3531 ( enum_range PGNSP PGUID 12 1 0 f f f f s 1 2277 "3500" _null_ _null_ _null_ enum_range_all - _null_ ));
|
||||||
|
DATA(insert OID = 3532 ( text PGNSP PGUID 12 1 0 f f t f s 1 25 "3500" _null_ _null_ _null_ enum_text - _null_ ));
|
||||||
|
DESCR("convert enum to text");
|
||||||
|
DATA(insert OID = 3533 ( enum PGNSP PGUID 12 1 0 f f t f s 1 3500 "25" _null_ _null_ _null_ text_enum - _null_ ));
|
||||||
|
DESCR("convert text to enum");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Symbolic values for provolatile column: these indicate whether the result
|
* Symbolic values for provolatile column: these indicate whether the result
|
||||||
* of a function is dependent *only* on the values of its explicit arguments,
|
* of a function is dependent *only* on the values of its explicit arguments,
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.180 2007/01/28 16:16:54 neilc Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.181 2007/04/02 03:49:41 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
@ -66,8 +66,9 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP
|
||||||
bool typbyval;
|
bool typbyval;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* typtype is 'b' for a basic type, 'c' for a complex type (ie a table's
|
* typtype is 'b' for a base type, 'c' for a composite type (e.g.,
|
||||||
* rowtype), 'd' for a domain type, or 'p' for a pseudo type.
|
* a table's rowtype), 'd' for a domain type, 'e' for an enum type,
|
||||||
|
* or 'p' for a pseudo-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.
|
||||||
*/
|
*/
|
||||||
|
@ -531,6 +532,11 @@ DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b t \054 0 2205 array_in
|
||||||
DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b t \054 0 2206 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
|
DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b t \054 0 2206 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
|
||||||
#define REGTYPEARRAYOID 2211
|
#define REGTYPEARRAYOID 2211
|
||||||
|
|
||||||
|
/* uuid */
|
||||||
|
DATA(insert OID = 2950 ( uuid PGNSP PGUID 16 f b t \054 0 0 uuid_in uuid_out uuid_recv uuid_send - - - c p f 0 -1 0 _null_ _null_ ));
|
||||||
|
DESCR("UUID datatype");
|
||||||
|
DATA(insert OID = 2951 ( _uuid PGNSP PGUID -1 f b t \054 0 2950 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pseudo-types
|
* pseudo-types
|
||||||
*
|
*
|
||||||
|
@ -560,11 +566,24 @@ DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p t \054 0 0 opaque_in opaque
|
||||||
#define OPAQUEOID 2282
|
#define OPAQUEOID 2282
|
||||||
DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p t \054 0 0 anyelement_in anyelement_out - - - - - i p f 0 -1 0 _null_ _null_ ));
|
DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p t \054 0 0 anyelement_in anyelement_out - - - - - i p f 0 -1 0 _null_ _null_ ));
|
||||||
#define ANYELEMENTOID 2283
|
#define ANYELEMENTOID 2283
|
||||||
|
DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p t \054 0 0 anyenum_in anyenum_out - - - - - i p f 0 -1 0 _null_ _null_ ));
|
||||||
|
#define ANYENUMOID 3500
|
||||||
|
|
||||||
/* uuid */
|
|
||||||
DATA(insert OID = 2950 ( uuid PGNSP PGUID 16 f b t \054 0 0 uuid_in uuid_out uuid_recv uuid_send - - - c p f 0 -1 0 _null_ _null_ ));
|
/*
|
||||||
DESCR("UUID datatype");
|
* macros
|
||||||
DATA(insert OID = 2951 ( _uuid PGNSP PGUID -1 f b t \054 0 2950 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
|
*/
|
||||||
|
#define TYPTYPE_BASE 'b' /* base type (ordinary scalar type) */
|
||||||
|
#define TYPTYPE_COMPOSITE 'c' /* composite (e.g., table's rowtype) */
|
||||||
|
#define TYPTYPE_DOMAIN 'd' /* domain over another type */
|
||||||
|
#define TYPTYPE_ENUM 'e' /* enumerated type */
|
||||||
|
#define TYPTYPE_PSEUDO 'p' /* pseudo-type */
|
||||||
|
|
||||||
|
/* Is a type OID a polymorphic pseudotype? (Beware of multiple evaluation) */
|
||||||
|
#define IsPolymorphicType(typid) \
|
||||||
|
((typid) == ANYELEMENTOID || \
|
||||||
|
(typid) == ANYARRAYOID || \
|
||||||
|
(typid) == ANYENUMOID)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* prototypes for functions in pg_type.c
|
* prototypes for functions in pg_type.c
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.17 2007/01/05 22:19:54 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/commands/typecmds.h,v 1.18 2007/04/02 03:49:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -24,6 +24,7 @@ extern void RemoveType(List *names, DropBehavior behavior, bool missing_ok);
|
||||||
extern void RemoveTypeById(Oid typeOid);
|
extern void RemoveTypeById(Oid typeOid);
|
||||||
extern void DefineDomain(CreateDomainStmt *stmt);
|
extern void DefineDomain(CreateDomainStmt *stmt);
|
||||||
extern void RemoveDomain(List *names, DropBehavior behavior, bool missing_ok);
|
extern void RemoveDomain(List *names, DropBehavior behavior, bool missing_ok);
|
||||||
|
extern void DefineEnum(CreateEnumStmt *stmt);
|
||||||
extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist);
|
extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist);
|
||||||
|
|
||||||
extern void AlterDomainDefault(List *names, Node *defaultRaw);
|
extern void AlterDomainDefault(List *names, Node *defaultRaw);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.197 2007/03/27 23:21:12 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.198 2007/04/02 03:49:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -307,6 +307,7 @@ typedef enum NodeTag
|
||||||
T_DropOwnedStmt,
|
T_DropOwnedStmt,
|
||||||
T_ReassignOwnedStmt,
|
T_ReassignOwnedStmt,
|
||||||
T_CompositeTypeStmt,
|
T_CompositeTypeStmt,
|
||||||
|
T_CreateEnumStmt,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TAGS FOR PARSE TREE NODES (parsenodes.h)
|
* TAGS FOR PARSE TREE NODES (parsenodes.h)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.343 2007/03/19 23:38:32 wieck Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.344 2007/04/02 03:49:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -1706,6 +1706,17 @@ typedef struct CompositeTypeStmt
|
||||||
List *coldeflist; /* list of ColumnDef nodes */
|
List *coldeflist; /* list of ColumnDef nodes */
|
||||||
} CompositeTypeStmt;
|
} CompositeTypeStmt;
|
||||||
|
|
||||||
|
/* ----------------------
|
||||||
|
* Create Type Statement, enum types
|
||||||
|
* ----------------------
|
||||||
|
*/
|
||||||
|
typedef struct CreateEnumStmt
|
||||||
|
{
|
||||||
|
NodeTag type;
|
||||||
|
List *typename; /* qualified name (list of Value strings) */
|
||||||
|
List *vals; /* enum values (list of Value strings) */
|
||||||
|
} CreateEnumStmt;
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------
|
/* ----------------------
|
||||||
* Create View Statement
|
* Create View Statement
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/parser/parse_type.h,v 1.35 2007/01/05 22:19:57 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/parser/parse_type.h,v 1.36 2007/04/02 03:49:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -33,7 +33,6 @@ extern Type typeidType(Oid id);
|
||||||
extern Oid typeTypeId(Type tp);
|
extern Oid typeTypeId(Type tp);
|
||||||
extern int16 typeLen(Type t);
|
extern int16 typeLen(Type t);
|
||||||
extern bool typeByVal(Type t);
|
extern bool typeByVal(Type t);
|
||||||
extern char typeTypType(Type t);
|
|
||||||
extern char *typeTypeName(Type t);
|
extern char *typeTypeName(Type t);
|
||||||
extern Oid typeTypeRelid(Type typ);
|
extern Oid typeTypeRelid(Type typ);
|
||||||
extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod);
|
extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.290 2007/03/20 05:45:00 neilc Exp $
|
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.291 2007/04/02 03:49:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -103,6 +103,25 @@ extern Datum char_text(PG_FUNCTION_ARGS);
|
||||||
extern Datum domain_in(PG_FUNCTION_ARGS);
|
extern Datum domain_in(PG_FUNCTION_ARGS);
|
||||||
extern Datum domain_recv(PG_FUNCTION_ARGS);
|
extern Datum domain_recv(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
|
/* enum.c */
|
||||||
|
extern Datum enum_in(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_out(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_lt(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_le(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_eq(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_ne(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_ge(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_gt(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_cmp(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_text(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum text_enum(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_smaller(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_larger(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_first(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_last(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_range_bounds(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum enum_range_all(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
/* int.c */
|
/* int.c */
|
||||||
extern Datum int2in(PG_FUNCTION_ARGS);
|
extern Datum int2in(PG_FUNCTION_ARGS);
|
||||||
extern Datum int2out(PG_FUNCTION_ARGS);
|
extern Datum int2out(PG_FUNCTION_ARGS);
|
||||||
|
@ -450,6 +469,8 @@ extern Datum anyarray_in(PG_FUNCTION_ARGS);
|
||||||
extern Datum anyarray_out(PG_FUNCTION_ARGS);
|
extern Datum anyarray_out(PG_FUNCTION_ARGS);
|
||||||
extern Datum anyarray_recv(PG_FUNCTION_ARGS);
|
extern Datum anyarray_recv(PG_FUNCTION_ARGS);
|
||||||
extern Datum anyarray_send(PG_FUNCTION_ARGS);
|
extern Datum anyarray_send(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum anyenum_in(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum anyenum_out(PG_FUNCTION_ARGS);
|
||||||
extern Datum void_in(PG_FUNCTION_ARGS);
|
extern Datum void_in(PG_FUNCTION_ARGS);
|
||||||
extern Datum void_out(PG_FUNCTION_ARGS);
|
extern Datum void_out(PG_FUNCTION_ARGS);
|
||||||
extern Datum trigger_in(PG_FUNCTION_ARGS);
|
extern Datum trigger_in(PG_FUNCTION_ARGS);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.117 2007/02/14 01:58:58 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.118 2007/04/02 03:49:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -105,6 +105,7 @@ extern char get_typstorage(Oid typid);
|
||||||
extern Node *get_typdefault(Oid typid);
|
extern Node *get_typdefault(Oid typid);
|
||||||
extern char get_typtype(Oid typid);
|
extern char get_typtype(Oid typid);
|
||||||
extern bool type_is_rowtype(Oid typid);
|
extern bool type_is_rowtype(Oid typid);
|
||||||
|
extern bool type_is_enum(Oid typid);
|
||||||
extern Oid get_typ_typrelid(Oid typid);
|
extern Oid get_typ_typrelid(Oid typid);
|
||||||
extern Oid get_element_type(Oid typid);
|
extern Oid get_element_type(Oid typid);
|
||||||
extern Oid get_array_type(Oid typid);
|
extern Oid get_array_type(Oid typid);
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.68 2007/02/14 01:58:58 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.69 2007/04/02 03:49:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -48,23 +48,25 @@
|
||||||
#define CONSTROID 17
|
#define CONSTROID 17
|
||||||
#define CONVOID 18
|
#define CONVOID 18
|
||||||
#define DATABASEOID 19
|
#define DATABASEOID 19
|
||||||
#define INDEXRELID 20
|
#define ENUMOID 20
|
||||||
#define LANGNAME 21
|
#define ENUMTYPOIDNAME 21
|
||||||
#define LANGOID 22
|
#define INDEXRELID 22
|
||||||
#define NAMESPACENAME 23
|
#define LANGNAME 23
|
||||||
#define NAMESPACEOID 24
|
#define LANGOID 24
|
||||||
#define OPERNAMENSP 25
|
#define NAMESPACENAME 25
|
||||||
#define OPEROID 26
|
#define NAMESPACEOID 26
|
||||||
#define OPFAMILYAMNAMENSP 27
|
#define OPERNAMENSP 27
|
||||||
#define OPFAMILYOID 28
|
#define OPEROID 28
|
||||||
#define PROCNAMEARGSNSP 29
|
#define OPFAMILYAMNAMENSP 29
|
||||||
#define PROCOID 30
|
#define OPFAMILYOID 30
|
||||||
#define RELNAMENSP 31
|
#define PROCNAMEARGSNSP 31
|
||||||
#define RELOID 32
|
#define PROCOID 32
|
||||||
#define RULERELNAME 33
|
#define RELNAMENSP 33
|
||||||
#define STATRELATT 34
|
#define RELOID 34
|
||||||
#define TYPENAMENSP 35
|
#define RULERELNAME 35
|
||||||
#define TYPEOID 36
|
#define STATRELATT 36
|
||||||
|
#define TYPENAMENSP 37
|
||||||
|
#define TYPEOID 38
|
||||||
|
|
||||||
extern void InitCatalogCache(void);
|
extern void InitCatalogCache(void);
|
||||||
extern void InitCatalogCachePhase2(void);
|
extern void InitCatalogCachePhase2(void);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* plperl.c - perl as a procedural language for PostgreSQL
|
* plperl.c - perl as a procedural language for PostgreSQL
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.127 2007/02/09 03:35:34 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.128 2007/04/02 03:49:41 tgl Exp $
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
|
@ -843,7 +843,7 @@ plperl_validator(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/* Disallow pseudotype result */
|
/* Disallow pseudotype result */
|
||||||
/* except for TRIGGER, RECORD, or VOID */
|
/* except for TRIGGER, RECORD, or VOID */
|
||||||
if (functyptype == 'p')
|
if (functyptype == TYPTYPE_PSEUDO)
|
||||||
{
|
{
|
||||||
/* we assume OPAQUE with no arguments means a trigger */
|
/* we assume OPAQUE with no arguments means a trigger */
|
||||||
if (proc->prorettype == TRIGGEROID ||
|
if (proc->prorettype == TRIGGEROID ||
|
||||||
|
@ -862,7 +862,7 @@ plperl_validator(PG_FUNCTION_ARGS)
|
||||||
&argtypes, &argnames, &argmodes);
|
&argtypes, &argnames, &argmodes);
|
||||||
for (i = 0; i < numargs; i++)
|
for (i = 0; i < numargs; i++)
|
||||||
{
|
{
|
||||||
if (get_typtype(argtypes[i]) == 'p')
|
if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("plperl functions cannot take type %s",
|
errmsg("plperl functions cannot take type %s",
|
||||||
|
@ -1525,7 +1525,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
|
||||||
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
||||||
|
|
||||||
/* Disallow pseudotype result, except VOID or RECORD */
|
/* Disallow pseudotype result, except VOID or RECORD */
|
||||||
if (typeStruct->typtype == 'p')
|
if (typeStruct->typtype == TYPTYPE_PSEUDO)
|
||||||
{
|
{
|
||||||
if (procStruct->prorettype == VOIDOID ||
|
if (procStruct->prorettype == VOIDOID ||
|
||||||
procStruct->prorettype == RECORDOID)
|
procStruct->prorettype == RECORDOID)
|
||||||
|
@ -1552,8 +1552,8 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
|
||||||
|
|
||||||
prodesc->result_oid = procStruct->prorettype;
|
prodesc->result_oid = procStruct->prorettype;
|
||||||
prodesc->fn_retisset = procStruct->proretset;
|
prodesc->fn_retisset = procStruct->proretset;
|
||||||
prodesc->fn_retistuple = (typeStruct->typtype == 'c' ||
|
prodesc->fn_retistuple = (procStruct->prorettype == RECORDOID ||
|
||||||
procStruct->prorettype == RECORDOID);
|
typeStruct->typtype == TYPTYPE_COMPOSITE);
|
||||||
|
|
||||||
prodesc->fn_retisarray =
|
prodesc->fn_retisarray =
|
||||||
(typeStruct->typlen == -1 && typeStruct->typelem);
|
(typeStruct->typlen == -1 && typeStruct->typelem);
|
||||||
|
@ -1586,7 +1586,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
|
||||||
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
||||||
|
|
||||||
/* Disallow pseudotype argument */
|
/* Disallow pseudotype argument */
|
||||||
if (typeStruct->typtype == 'p')
|
if (typeStruct->typtype == TYPTYPE_PSEUDO)
|
||||||
{
|
{
|
||||||
free(prodesc->proname);
|
free(prodesc->proname);
|
||||||
free(prodesc);
|
free(prodesc);
|
||||||
|
@ -1596,7 +1596,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
|
||||||
format_type_be(procStruct->proargtypes.values[i]))));
|
format_type_be(procStruct->proargtypes.values[i]))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeStruct->typtype == 'c')
|
if (typeStruct->typtype == TYPTYPE_COMPOSITE)
|
||||||
prodesc->arg_is_rowtype[i] = true;
|
prodesc->arg_is_rowtype[i] = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.113 2007/02/09 03:35:34 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.114 2007/04/02 03:49:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -406,7 +406,7 @@ do_compile(FunctionCallInfo fcinfo,
|
||||||
argdtype = plpgsql_build_datatype(argtypeid, -1);
|
argdtype = plpgsql_build_datatype(argtypeid, -1);
|
||||||
|
|
||||||
/* Disallow pseudotype argument */
|
/* Disallow pseudotype argument */
|
||||||
/* (note we already replaced ANYARRAY/ANYELEMENT) */
|
/* (note we already replaced polymorphic types) */
|
||||||
/* (build_variable would do this, but wrong message) */
|
/* (build_variable would do this, but wrong message) */
|
||||||
if (argdtype->ttype != PLPGSQL_TTYPE_SCALAR &&
|
if (argdtype->ttype != PLPGSQL_TTYPE_SCALAR &&
|
||||||
argdtype->ttype != PLPGSQL_TTYPE_ROW)
|
argdtype->ttype != PLPGSQL_TTYPE_ROW)
|
||||||
|
@ -474,7 +474,7 @@ do_compile(FunctionCallInfo fcinfo,
|
||||||
* the info available.
|
* the info available.
|
||||||
*/
|
*/
|
||||||
rettypeid = procStruct->prorettype;
|
rettypeid = procStruct->prorettype;
|
||||||
if (rettypeid == ANYARRAYOID || rettypeid == ANYELEMENTOID)
|
if (IsPolymorphicType(rettypeid))
|
||||||
{
|
{
|
||||||
if (forValidator)
|
if (forValidator)
|
||||||
{
|
{
|
||||||
|
@ -482,6 +482,7 @@ do_compile(FunctionCallInfo fcinfo,
|
||||||
rettypeid = INT4ARRAYOID;
|
rettypeid = INT4ARRAYOID;
|
||||||
else
|
else
|
||||||
rettypeid = INT4OID;
|
rettypeid = INT4OID;
|
||||||
|
/* XXX what could we use for ANYENUM? */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -512,8 +513,8 @@ do_compile(FunctionCallInfo fcinfo,
|
||||||
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
||||||
|
|
||||||
/* Disallow pseudotype result, except VOID or RECORD */
|
/* Disallow pseudotype result, except VOID or RECORD */
|
||||||
/* (note we already replaced ANYARRAY/ANYELEMENT) */
|
/* (note we already replaced polymorphic types) */
|
||||||
if (typeStruct->typtype == 'p')
|
if (typeStruct->typtype == TYPTYPE_PSEUDO)
|
||||||
{
|
{
|
||||||
if (rettypeid == VOIDOID ||
|
if (rettypeid == VOIDOID ||
|
||||||
rettypeid == RECORDOID)
|
rettypeid == RECORDOID)
|
||||||
|
@ -544,8 +545,7 @@ do_compile(FunctionCallInfo fcinfo,
|
||||||
* types, and not when the return is specified through an
|
* types, and not when the return is specified through an
|
||||||
* output parameter.
|
* output parameter.
|
||||||
*/
|
*/
|
||||||
if ((procStruct->prorettype == ANYARRAYOID ||
|
if (IsPolymorphicType(procStruct->prorettype) &&
|
||||||
procStruct->prorettype == ANYELEMENTOID) &&
|
|
||||||
num_out_args == 0)
|
num_out_args == 0)
|
||||||
{
|
{
|
||||||
(void) plpgsql_build_variable("$0", 0,
|
(void) plpgsql_build_variable("$0", 0,
|
||||||
|
@ -1785,15 +1785,16 @@ build_datatype(HeapTuple typeTup, int32 typmod)
|
||||||
typ->typoid = HeapTupleGetOid(typeTup);
|
typ->typoid = HeapTupleGetOid(typeTup);
|
||||||
switch (typeStruct->typtype)
|
switch (typeStruct->typtype)
|
||||||
{
|
{
|
||||||
case 'b': /* base type */
|
case TYPTYPE_BASE:
|
||||||
case 'd': /* domain */
|
case TYPTYPE_DOMAIN:
|
||||||
|
case TYPTYPE_ENUM:
|
||||||
typ->ttype = PLPGSQL_TTYPE_SCALAR;
|
typ->ttype = PLPGSQL_TTYPE_SCALAR;
|
||||||
break;
|
break;
|
||||||
case 'c': /* composite, ie, rowtype */
|
case TYPTYPE_COMPOSITE:
|
||||||
Assert(OidIsValid(typeStruct->typrelid));
|
Assert(OidIsValid(typeStruct->typrelid));
|
||||||
typ->ttype = PLPGSQL_TTYPE_ROW;
|
typ->ttype = PLPGSQL_TTYPE_ROW;
|
||||||
break;
|
break;
|
||||||
case 'p': /* pseudo */
|
case TYPTYPE_PSEUDO:
|
||||||
if (typ->typoid == RECORDOID)
|
if (typ->typoid == RECORDOID)
|
||||||
typ->ttype = PLPGSQL_TTYPE_REC;
|
typ->ttype = PLPGSQL_TTYPE_REC;
|
||||||
else
|
else
|
||||||
|
@ -2026,6 +2027,7 @@ plpgsql_resolve_polymorphic_argtypes(int numargs,
|
||||||
switch (argtypes[i])
|
switch (argtypes[i])
|
||||||
{
|
{
|
||||||
case ANYELEMENTOID:
|
case ANYELEMENTOID:
|
||||||
|
case ANYENUMOID: /* XXX dubious */
|
||||||
argtypes[i] = INT4OID;
|
argtypes[i] = INT4OID;
|
||||||
break;
|
break;
|
||||||
case ANYARRAYOID:
|
case ANYARRAYOID:
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.192 2007/03/27 23:21:12 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.193 2007/04/02 03:49:42 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -3294,8 +3294,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
|
||||||
PLpgSQL_row *row = (PLpgSQL_row *) target;
|
PLpgSQL_row *row = (PLpgSQL_row *) target;
|
||||||
|
|
||||||
/* Source must be of RECORD or composite type */
|
/* Source must be of RECORD or composite type */
|
||||||
if (!(valtype == RECORDOID ||
|
if (!type_is_rowtype(valtype))
|
||||||
get_typtype(valtype) == 'c'))
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
errmsg("cannot assign non-composite value to a row variable")));
|
errmsg("cannot assign non-composite value to a row variable")));
|
||||||
|
@ -3337,8 +3336,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
|
||||||
PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
|
PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
|
||||||
|
|
||||||
/* Source must be of RECORD or composite type */
|
/* Source must be of RECORD or composite type */
|
||||||
if (!(valtype == RECORDOID ||
|
if (!type_is_rowtype(valtype))
|
||||||
get_typtype(valtype) == 'c'))
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
errmsg("cannot assign non-composite value to a record variable")));
|
errmsg("cannot assign non-composite value to a record variable")));
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.36 2007/01/30 22:05:13 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.37 2007/04/02 03:49:42 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -147,8 +147,8 @@ plpgsql_validator(PG_FUNCTION_ARGS)
|
||||||
functyptype = get_typtype(proc->prorettype);
|
functyptype = get_typtype(proc->prorettype);
|
||||||
|
|
||||||
/* Disallow pseudotype result */
|
/* Disallow pseudotype result */
|
||||||
/* except for TRIGGER, RECORD, VOID, ANYARRAY, or ANYELEMENT */
|
/* except for TRIGGER, RECORD, VOID, or polymorphic */
|
||||||
if (functyptype == 'p')
|
if (functyptype == TYPTYPE_PSEUDO)
|
||||||
{
|
{
|
||||||
/* we assume OPAQUE with no arguments means a trigger */
|
/* we assume OPAQUE with no arguments means a trigger */
|
||||||
if (proc->prorettype == TRIGGEROID ||
|
if (proc->prorettype == TRIGGEROID ||
|
||||||
|
@ -156,8 +156,7 @@ plpgsql_validator(PG_FUNCTION_ARGS)
|
||||||
istrigger = true;
|
istrigger = true;
|
||||||
else if (proc->prorettype != RECORDOID &&
|
else if (proc->prorettype != RECORDOID &&
|
||||||
proc->prorettype != VOIDOID &&
|
proc->prorettype != VOIDOID &&
|
||||||
proc->prorettype != ANYARRAYOID &&
|
!IsPolymorphicType(proc->prorettype))
|
||||||
proc->prorettype != ANYELEMENTOID)
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("plpgsql functions cannot return type %s",
|
errmsg("plpgsql functions cannot return type %s",
|
||||||
|
@ -165,15 +164,14 @@ plpgsql_validator(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disallow pseudotypes in arguments (either IN or OUT) */
|
/* Disallow pseudotypes in arguments (either IN or OUT) */
|
||||||
/* except for ANYARRAY or ANYELEMENT */
|
/* except for polymorphic */
|
||||||
numargs = get_func_arg_info(tuple,
|
numargs = get_func_arg_info(tuple,
|
||||||
&argtypes, &argnames, &argmodes);
|
&argtypes, &argnames, &argmodes);
|
||||||
for (i = 0; i < numargs; i++)
|
for (i = 0; i < numargs; i++)
|
||||||
{
|
{
|
||||||
if (get_typtype(argtypes[i]) == 'p')
|
if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
|
||||||
{
|
{
|
||||||
if (argtypes[i] != ANYARRAYOID &&
|
if (!IsPolymorphicType(argtypes[i]))
|
||||||
argtypes[i] != ANYELEMENTOID)
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("plpgsql functions cannot take type %s",
|
errmsg("plpgsql functions cannot take type %s",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* plpython.c - python as a procedural language for PostgreSQL
|
* plpython.c - python as a procedural language for PostgreSQL
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.96 2007/02/21 03:27:32 adunstan Exp $
|
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.97 2007/04/02 03:49:42 tgl Exp $
|
||||||
*
|
*
|
||||||
*********************************************************************
|
*********************************************************************
|
||||||
*/
|
*/
|
||||||
|
@ -1185,7 +1185,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
|
||||||
rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
|
rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
|
||||||
|
|
||||||
/* Disallow pseudotype result, except for void */
|
/* Disallow pseudotype result, except for void */
|
||||||
if (rvTypeStruct->typtype == 'p' &&
|
if (rvTypeStruct->typtype == TYPTYPE_PSEUDO &&
|
||||||
procStruct->prorettype != VOIDOID)
|
procStruct->prorettype != VOIDOID)
|
||||||
{
|
{
|
||||||
if (procStruct->prorettype == TRIGGEROID)
|
if (procStruct->prorettype == TRIGGEROID)
|
||||||
|
@ -1199,7 +1199,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
|
||||||
format_type_be(procStruct->prorettype))));
|
format_type_be(procStruct->prorettype))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rvTypeStruct->typtype == 'c')
|
if (rvTypeStruct->typtype == TYPTYPE_COMPOSITE)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Tuple: set up later, during first call to
|
* Tuple: set up later, during first call to
|
||||||
|
@ -1258,13 +1258,13 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
|
||||||
argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
|
argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
|
||||||
|
|
||||||
/* Disallow pseudotype argument */
|
/* Disallow pseudotype argument */
|
||||||
if (argTypeStruct->typtype == 'p')
|
if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("plpython functions cannot take type %s",
|
errmsg("plpython functions cannot take type %s",
|
||||||
format_type_be(procStruct->proargtypes.values[i]))));
|
format_type_be(procStruct->proargtypes.values[i]))));
|
||||||
|
|
||||||
if (argTypeStruct->typtype != 'c')
|
if (argTypeStruct->typtype != TYPTYPE_COMPOSITE)
|
||||||
PLy_input_datum_func(&(proc->args[i]),
|
PLy_input_datum_func(&(proc->args[i]),
|
||||||
procStruct->proargtypes.values[i],
|
procStruct->proargtypes.values[i],
|
||||||
argTypeTup);
|
argTypeTup);
|
||||||
|
@ -2338,7 +2338,7 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
|
||||||
|
|
||||||
plan->types[i] = typeId;
|
plan->types[i] = typeId;
|
||||||
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
||||||
if (typeStruct->typtype != 'c')
|
if (typeStruct->typtype != TYPTYPE_COMPOSITE)
|
||||||
PLy_output_datum_func(&plan->args[i], typeTup);
|
PLy_output_datum_func(&plan->args[i], typeTup);
|
||||||
else
|
else
|
||||||
elog(ERROR, "tuples not handled in plpy.prepare, yet.");
|
elog(ERROR, "tuples not handled in plpy.prepare, yet.");
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* pltcl.c - PostgreSQL support for Tcl as
|
* pltcl.c - PostgreSQL support for Tcl as
|
||||||
* procedural language (PL)
|
* procedural language (PL)
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.111 2007/02/21 03:27:32 adunstan Exp $
|
* $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.112 2007/04/02 03:49:42 tgl Exp $
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
|
@ -1051,7 +1051,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid)
|
||||||
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
||||||
|
|
||||||
/* Disallow pseudotype result, except VOID */
|
/* Disallow pseudotype result, except VOID */
|
||||||
if (typeStruct->typtype == 'p')
|
if (typeStruct->typtype == TYPTYPE_PSEUDO)
|
||||||
{
|
{
|
||||||
if (procStruct->prorettype == VOIDOID)
|
if (procStruct->prorettype == VOIDOID)
|
||||||
/* okay */ ;
|
/* okay */ ;
|
||||||
|
@ -1074,7 +1074,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeStruct->typtype == 'c')
|
if (typeStruct->typtype == TYPTYPE_COMPOSITE)
|
||||||
{
|
{
|
||||||
free(prodesc->proname);
|
free(prodesc->proname);
|
||||||
free(prodesc);
|
free(prodesc);
|
||||||
|
@ -1112,7 +1112,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid)
|
||||||
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
|
||||||
|
|
||||||
/* Disallow pseudotype argument */
|
/* Disallow pseudotype argument */
|
||||||
if (typeStruct->typtype == 'p')
|
if (typeStruct->typtype == TYPTYPE_PSEUDO)
|
||||||
{
|
{
|
||||||
free(prodesc->proname);
|
free(prodesc->proname);
|
||||||
free(prodesc);
|
free(prodesc);
|
||||||
|
@ -1122,7 +1122,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid)
|
||||||
format_type_be(procStruct->proargtypes.values[i]))));
|
format_type_be(procStruct->proargtypes.values[i]))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeStruct->typtype == 'c')
|
if (typeStruct->typtype == TYPTYPE_COMPOSITE)
|
||||||
{
|
{
|
||||||
prodesc->arg_is_rowtype[i] = true;
|
prodesc->arg_is_rowtype[i] = true;
|
||||||
snprintf(buf, sizeof(buf), "__PLTcl_Tup_%d", i + 1);
|
snprintf(buf, sizeof(buf), "__PLTcl_Tup_%d", i + 1);
|
||||||
|
|
|
@ -0,0 +1,407 @@
|
||||||
|
--
|
||||||
|
-- Enum tests
|
||||||
|
--
|
||||||
|
CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
|
||||||
|
--
|
||||||
|
-- Did it create the right number of rows?
|
||||||
|
--
|
||||||
|
SELECT COUNT(*) FROM pg_enum WHERE enumtypid = 'rainbow'::regtype;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
6
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- I/O functions
|
||||||
|
--
|
||||||
|
SELECT 'red'::rainbow;
|
||||||
|
rainbow
|
||||||
|
---------
|
||||||
|
red
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT 'mauve'::rainbow;
|
||||||
|
ERROR: invalid input value for enum rainbow: "mauve"
|
||||||
|
--
|
||||||
|
-- Basic table creation, row selection
|
||||||
|
--
|
||||||
|
CREATE TABLE enumtest (col rainbow);
|
||||||
|
INSERT INTO enumtest values ('red'), ('orange'), ('yellow'), ('green');
|
||||||
|
COPY enumtest FROM stdin;
|
||||||
|
SELECT * FROM enumtest;
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
red
|
||||||
|
orange
|
||||||
|
yellow
|
||||||
|
green
|
||||||
|
blue
|
||||||
|
purple
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Operators, no index
|
||||||
|
--
|
||||||
|
SELECT * FROM enumtest WHERE col = 'orange';
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
orange
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM enumtest WHERE col <> 'orange' ORDER BY col;
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
red
|
||||||
|
yellow
|
||||||
|
green
|
||||||
|
blue
|
||||||
|
purple
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
SELECT * FROM enumtest WHERE col > 'yellow' ORDER BY col;
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
green
|
||||||
|
blue
|
||||||
|
purple
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
SELECT * FROM enumtest WHERE col >= 'yellow' ORDER BY col;
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
yellow
|
||||||
|
green
|
||||||
|
blue
|
||||||
|
purple
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
SELECT * FROM enumtest WHERE col < 'green' ORDER BY col;
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
red
|
||||||
|
orange
|
||||||
|
yellow
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
SELECT * FROM enumtest WHERE col <= 'green' ORDER BY col;
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
red
|
||||||
|
orange
|
||||||
|
yellow
|
||||||
|
green
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Cast to/from text
|
||||||
|
--
|
||||||
|
SELECT 'red'::rainbow::text || 'hithere';
|
||||||
|
?column?
|
||||||
|
------------
|
||||||
|
redhithere
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT 'red'::text::rainbow = 'red'::rainbow;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Aggregates
|
||||||
|
--
|
||||||
|
SELECT min(col) FROM enumtest;
|
||||||
|
min
|
||||||
|
-----
|
||||||
|
red
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT max(col) FROM enumtest;
|
||||||
|
max
|
||||||
|
--------
|
||||||
|
purple
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT max(col) FROM enumtest WHERE col < 'green';
|
||||||
|
max
|
||||||
|
--------
|
||||||
|
yellow
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Index tests, force use of index
|
||||||
|
--
|
||||||
|
SET enable_seqscan = off;
|
||||||
|
SET enable_bitmapscan = off;
|
||||||
|
--
|
||||||
|
-- Btree index / opclass with the various operators
|
||||||
|
--
|
||||||
|
CREATE UNIQUE INDEX enumtest_btree ON enumtest USING btree (col);
|
||||||
|
SELECT * FROM enumtest WHERE col = 'orange';
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
orange
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM enumtest WHERE col <> 'orange' ORDER BY col;
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
red
|
||||||
|
yellow
|
||||||
|
green
|
||||||
|
blue
|
||||||
|
purple
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
SELECT * FROM enumtest WHERE col > 'yellow' ORDER BY col;
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
green
|
||||||
|
blue
|
||||||
|
purple
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
SELECT * FROM enumtest WHERE col >= 'yellow' ORDER BY col;
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
yellow
|
||||||
|
green
|
||||||
|
blue
|
||||||
|
purple
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
SELECT * FROM enumtest WHERE col < 'green' ORDER BY col;
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
red
|
||||||
|
orange
|
||||||
|
yellow
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
SELECT * FROM enumtest WHERE col <= 'green' ORDER BY col;
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
red
|
||||||
|
orange
|
||||||
|
yellow
|
||||||
|
green
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
SELECT min(col) FROM enumtest;
|
||||||
|
min
|
||||||
|
-----
|
||||||
|
red
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT max(col) FROM enumtest;
|
||||||
|
max
|
||||||
|
--------
|
||||||
|
purple
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT max(col) FROM enumtest WHERE col < 'green';
|
||||||
|
max
|
||||||
|
--------
|
||||||
|
yellow
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP INDEX enumtest_btree;
|
||||||
|
--
|
||||||
|
-- Hash index / opclass with the = operator
|
||||||
|
--
|
||||||
|
CREATE INDEX enumtest_hash ON enumtest USING hash (col);
|
||||||
|
SELECT * FROM enumtest WHERE col = 'orange';
|
||||||
|
col
|
||||||
|
--------
|
||||||
|
orange
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP INDEX enumtest_hash;
|
||||||
|
--
|
||||||
|
-- End index tests
|
||||||
|
--
|
||||||
|
RESET enable_seqscan;
|
||||||
|
RESET enable_bitmapscan;
|
||||||
|
--
|
||||||
|
-- Domains over enums
|
||||||
|
--
|
||||||
|
CREATE DOMAIN rgb AS rainbow CHECK (VALUE IN ('red', 'green', 'blue'));
|
||||||
|
SELECT 'red'::rgb;
|
||||||
|
rgb
|
||||||
|
-----
|
||||||
|
red
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT 'purple'::rgb;
|
||||||
|
ERROR: value for domain rgb violates check constraint "rgb_check"
|
||||||
|
SELECT 'purple'::rainbow::rgb;
|
||||||
|
ERROR: value for domain rgb violates check constraint "rgb_check"
|
||||||
|
DROP DOMAIN rgb;
|
||||||
|
--
|
||||||
|
-- Arrays
|
||||||
|
--
|
||||||
|
SELECT '{red,green,blue}'::rainbow[];
|
||||||
|
rainbow
|
||||||
|
------------------
|
||||||
|
{red,green,blue}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT ('{red,green,blue}'::rainbow[])[2];
|
||||||
|
rainbow
|
||||||
|
---------
|
||||||
|
green
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT 'red' = ANY ('{red,green,blue}'::rainbow[]);
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT 'yellow' = ANY ('{red,green,blue}'::rainbow[]);
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT 'red' = ALL ('{red,green,blue}'::rainbow[]);
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT 'red' = ALL ('{red,red}'::rainbow[]);
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Support functions
|
||||||
|
--
|
||||||
|
SELECT enum_first(NULL::rainbow);
|
||||||
|
enum_first
|
||||||
|
------------
|
||||||
|
red
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT enum_last('green'::rainbow);
|
||||||
|
enum_last
|
||||||
|
-----------
|
||||||
|
purple
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT enum_range(NULL::rainbow);
|
||||||
|
enum_range
|
||||||
|
---------------------------------------
|
||||||
|
{red,orange,yellow,green,blue,purple}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT enum_range('orange'::rainbow, 'green'::rainbow);
|
||||||
|
enum_range
|
||||||
|
-----------------------
|
||||||
|
{orange,yellow,green}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT enum_range(NULL, 'green'::rainbow);
|
||||||
|
enum_range
|
||||||
|
---------------------------
|
||||||
|
{red,orange,yellow,green}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT enum_range('orange'::rainbow, NULL);
|
||||||
|
enum_range
|
||||||
|
-----------------------------------
|
||||||
|
{orange,yellow,green,blue,purple}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT enum_range(NULL::rainbow, NULL);
|
||||||
|
enum_range
|
||||||
|
---------------------------------------
|
||||||
|
{red,orange,yellow,green,blue,purple}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- User functions, can't test perl/python etc here since may not be compiled.
|
||||||
|
--
|
||||||
|
CREATE FUNCTION echo_me(anyenum) RETURNS text AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN $1::text || 'omg';
|
||||||
|
END
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
SELECT echo_me('red'::rainbow);
|
||||||
|
echo_me
|
||||||
|
---------
|
||||||
|
redomg
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Concrete function should override generic one
|
||||||
|
--
|
||||||
|
CREATE FUNCTION echo_me(rainbow) RETURNS text AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN $1::text || 'wtf';
|
||||||
|
END
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
SELECT echo_me('red'::rainbow);
|
||||||
|
echo_me
|
||||||
|
---------
|
||||||
|
redwtf
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- If we drop the original generic one, we don't have to qualify the type
|
||||||
|
-- anymore, since there's only one match
|
||||||
|
--
|
||||||
|
DROP FUNCTION echo_me(anyenum);
|
||||||
|
SELECT echo_me('red');
|
||||||
|
echo_me
|
||||||
|
---------
|
||||||
|
redwtf
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP FUNCTION echo_me(rainbow);
|
||||||
|
--
|
||||||
|
-- RI triggers on enum types
|
||||||
|
--
|
||||||
|
CREATE TABLE enumtest_parent (id rainbow PRIMARY KEY);
|
||||||
|
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "enumtest_parent_pkey" for table "enumtest_parent"
|
||||||
|
CREATE TABLE enumtest_child (parent rainbow REFERENCES enumtest_parent);
|
||||||
|
INSERT INTO enumtest_parent VALUES ('red');
|
||||||
|
INSERT INTO enumtest_child VALUES ('red');
|
||||||
|
INSERT INTO enumtest_child VALUES ('blue'); -- fail
|
||||||
|
ERROR: insert or update on table "enumtest_child" violates foreign key constraint "enumtest_child_parent_fkey"
|
||||||
|
DETAIL: Key (parent)=(blue) is not present in table "enumtest_parent".
|
||||||
|
DELETE FROM enumtest_parent; -- fail
|
||||||
|
ERROR: update or delete on table "enumtest_parent" violates foreign key constraint "enumtest_child_parent_fkey" on table "enumtest_child"
|
||||||
|
DETAIL: Key (id)=(red) is still referenced from table "enumtest_child".
|
||||||
|
--
|
||||||
|
-- cross-type RI should fail
|
||||||
|
--
|
||||||
|
CREATE TYPE bogus AS ENUM('good', 'bad', 'ugly');
|
||||||
|
CREATE TABLE enumtest_bogus_child(parent bogus REFERENCES enumtest_parent);
|
||||||
|
ERROR: foreign key constraint "enumtest_bogus_child_parent_fkey" cannot be implemented
|
||||||
|
DETAIL: Key columns "parent" and "id" are of incompatible types: bogus and rainbow.
|
||||||
|
DROP TYPE bogus;
|
||||||
|
--
|
||||||
|
-- Cleanup
|
||||||
|
--
|
||||||
|
DROP TABLE enumtest_child;
|
||||||
|
DROP TABLE enumtest_parent;
|
||||||
|
DROP TABLE enumtest;
|
||||||
|
DROP TYPE rainbow;
|
||||||
|
--
|
||||||
|
-- Verify properly cleaned up
|
||||||
|
--
|
||||||
|
SELECT COUNT(*) FROM pg_type WHERE typname = 'rainbow';
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM pg_enum WHERE NOT EXISTS
|
||||||
|
(SELECT 1 FROM pg_type WHERE pg_type.oid = enumtypid);
|
||||||
|
enumtypid | enumlabel
|
||||||
|
-----------+-----------
|
||||||
|
(0 rows)
|
||||||
|
|
|
@ -80,7 +80,7 @@ CREATE AGGREGATE myaggp01a(*) (SFUNC = stfnp, STYPE = int4[],
|
||||||
CREATE AGGREGATE myaggp02a(*) (SFUNC = stfnp, STYPE = anyarray,
|
CREATE AGGREGATE myaggp02a(*) (SFUNC = stfnp, STYPE = anyarray,
|
||||||
FINALFUNC = ffp, INITCOND = '{}');
|
FINALFUNC = ffp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- N P
|
-- N P
|
||||||
-- should CREATE
|
-- should CREATE
|
||||||
CREATE AGGREGATE myaggp03a(*) (SFUNC = stfp, STYPE = int4[],
|
CREATE AGGREGATE myaggp03a(*) (SFUNC = stfp, STYPE = int4[],
|
||||||
|
@ -92,11 +92,11 @@ CREATE AGGREGATE myaggp03b(*) (SFUNC = stfp, STYPE = int4[],
|
||||||
CREATE AGGREGATE myaggp04a(*) (SFUNC = stfp, STYPE = anyarray,
|
CREATE AGGREGATE myaggp04a(*) (SFUNC = stfp, STYPE = anyarray,
|
||||||
FINALFUNC = ffp, INITCOND = '{}');
|
FINALFUNC = ffp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
CREATE AGGREGATE myaggp04b(*) (SFUNC = stfp, STYPE = anyarray,
|
CREATE AGGREGATE myaggp04b(*) (SFUNC = stfp, STYPE = anyarray,
|
||||||
INITCOND = '{}');
|
INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- Case2 (R = P) && ((B = P) || (B = N))
|
-- Case2 (R = P) && ((B = P) || (B = N))
|
||||||
-- -------------------------------------
|
-- -------------------------------------
|
||||||
-- S tf1 B tf2
|
-- S tf1 B tf2
|
||||||
|
@ -151,13 +151,13 @@ ERROR: function tfp(integer[], anyelement) does not exist
|
||||||
CREATE AGGREGATE myaggp13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
|
CREATE AGGREGATE myaggp13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
|
||||||
FINALFUNC = ffp, INITCOND = '{}');
|
FINALFUNC = ffp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- P N N P
|
-- P N N P
|
||||||
-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
|
-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
|
||||||
CREATE AGGREGATE myaggp14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
|
CREATE AGGREGATE myaggp14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
|
||||||
FINALFUNC = ffp, INITCOND = '{}');
|
FINALFUNC = ffp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- P N P N
|
-- P N P N
|
||||||
-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
|
-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
|
||||||
CREATE AGGREGATE myaggp15a(BASETYPE = anyelement, SFUNC = tfnp,
|
CREATE AGGREGATE myaggp15a(BASETYPE = anyelement, SFUNC = tfnp,
|
||||||
|
@ -173,21 +173,21 @@ ERROR: function tf2p(anyarray, anyelement) does not exist
|
||||||
CREATE AGGREGATE myaggp17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
|
CREATE AGGREGATE myaggp17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
|
||||||
FINALFUNC = ffp, INITCOND = '{}');
|
FINALFUNC = ffp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
CREATE AGGREGATE myaggp17b(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
|
CREATE AGGREGATE myaggp17b(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
|
||||||
INITCOND = '{}');
|
INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- P P N P
|
-- P P N P
|
||||||
-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
|
-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
|
||||||
CREATE AGGREGATE myaggp18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
|
CREATE AGGREGATE myaggp18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
|
||||||
FINALFUNC = ffp, INITCOND = '{}');
|
FINALFUNC = ffp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
CREATE AGGREGATE myaggp18b(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
|
CREATE AGGREGATE myaggp18b(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
|
||||||
INITCOND = '{}');
|
INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- P P P N
|
-- P P P N
|
||||||
-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
|
-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
|
||||||
CREATE AGGREGATE myaggp19a(BASETYPE = anyelement, SFUNC = tf1p,
|
CREATE AGGREGATE myaggp19a(BASETYPE = anyelement, SFUNC = tf1p,
|
||||||
|
@ -217,11 +217,11 @@ CREATE AGGREGATE myaggn01b(*) (SFUNC = stfnp, STYPE = int4[],
|
||||||
CREATE AGGREGATE myaggn02a(*) (SFUNC = stfnp, STYPE = anyarray,
|
CREATE AGGREGATE myaggn02a(*) (SFUNC = stfnp, STYPE = anyarray,
|
||||||
FINALFUNC = ffnp, INITCOND = '{}');
|
FINALFUNC = ffnp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
CREATE AGGREGATE myaggn02b(*) (SFUNC = stfnp, STYPE = anyarray,
|
CREATE AGGREGATE myaggn02b(*) (SFUNC = stfnp, STYPE = anyarray,
|
||||||
INITCOND = '{}');
|
INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- N P
|
-- N P
|
||||||
-- should CREATE
|
-- should CREATE
|
||||||
CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[],
|
CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[],
|
||||||
|
@ -231,7 +231,7 @@ CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[],
|
||||||
CREATE AGGREGATE myaggn04a(*) (SFUNC = stfp, STYPE = anyarray,
|
CREATE AGGREGATE myaggn04a(*) (SFUNC = stfp, STYPE = anyarray,
|
||||||
FINALFUNC = ffnp, INITCOND = '{}');
|
FINALFUNC = ffnp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- Case4 (R = N) && ((B = P) || (B = N))
|
-- Case4 (R = N) && ((B = P) || (B = N))
|
||||||
-- -------------------------------------
|
-- -------------------------------------
|
||||||
-- S tf1 B tf2
|
-- S tf1 B tf2
|
||||||
|
@ -285,21 +285,21 @@ ERROR: function tfp(integer[], anyelement) does not exist
|
||||||
CREATE AGGREGATE myaggn13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
|
CREATE AGGREGATE myaggn13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
|
||||||
FINALFUNC = ffnp, INITCOND = '{}');
|
FINALFUNC = ffnp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
CREATE AGGREGATE myaggn13b(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
|
CREATE AGGREGATE myaggn13b(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
|
||||||
INITCOND = '{}');
|
INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- P N N P
|
-- P N N P
|
||||||
-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
|
-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
|
||||||
CREATE AGGREGATE myaggn14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
|
CREATE AGGREGATE myaggn14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
|
||||||
FINALFUNC = ffnp, INITCOND = '{}');
|
FINALFUNC = ffnp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
CREATE AGGREGATE myaggn14b(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
|
CREATE AGGREGATE myaggn14b(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
|
||||||
INITCOND = '{}');
|
INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- P N P N
|
-- P N P N
|
||||||
-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
|
-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
|
||||||
CREATE AGGREGATE myaggn15a(BASETYPE = anyelement, SFUNC = tfnp,
|
CREATE AGGREGATE myaggn15a(BASETYPE = anyelement, SFUNC = tfnp,
|
||||||
|
@ -321,13 +321,13 @@ ERROR: function tf2p(anyarray, anyelement) does not exist
|
||||||
CREATE AGGREGATE myaggn17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
|
CREATE AGGREGATE myaggn17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
|
||||||
FINALFUNC = ffnp, INITCOND = '{}');
|
FINALFUNC = ffnp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- P P N P
|
-- P P N P
|
||||||
-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
|
-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
|
||||||
CREATE AGGREGATE myaggn18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
|
CREATE AGGREGATE myaggn18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
|
||||||
FINALFUNC = ffnp, INITCOND = '{}');
|
FINALFUNC = ffnp, INITCOND = '{}');
|
||||||
ERROR: cannot determine transition data type
|
ERROR: cannot determine transition data type
|
||||||
DETAIL: An aggregate using "anyarray" or "anyelement" as transition type must have at least one argument of either type.
|
DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument.
|
||||||
-- P P P N
|
-- P P P N
|
||||||
-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
|
-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
|
||||||
CREATE AGGREGATE myaggn19a(BASETYPE = anyelement, SFUNC = tf1p,
|
CREATE AGGREGATE myaggn19a(BASETYPE = anyelement, SFUNC = tf1p,
|
||||||
|
|
|
@ -500,7 +500,7 @@ SELECT dup(22);
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT dup('xyz'); -- fails
|
SELECT dup('xyz'); -- fails
|
||||||
ERROR: could not determine anyarray/anyelement type because input has type "unknown"
|
ERROR: could not determine polymorphic type because input has type "unknown"
|
||||||
SELECT dup('xyz'::text);
|
SELECT dup('xyz'::text);
|
||||||
dup
|
dup
|
||||||
-------------------
|
-------------------
|
||||||
|
@ -527,4 +527,4 @@ DROP FUNCTION dup(anyelement);
|
||||||
CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray)
|
CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray)
|
||||||
AS 'select $1, array[$1,$1]' LANGUAGE sql;
|
AS 'select $1, array[$1,$1]' LANGUAGE sql;
|
||||||
ERROR: cannot determine result data type
|
ERROR: cannot determine result data type
|
||||||
DETAIL: A function returning "anyarray" or "anyelement" must have at least one argument of either type.
|
DETAIL: A function returning a polymorphic type must have at least one polymorphic argument.
|
||||||
|
|
|
@ -97,6 +97,7 @@ SELECT relname, relhasindex
|
||||||
pg_database | t
|
pg_database | t
|
||||||
pg_depend | t
|
pg_depend | t
|
||||||
pg_description | t
|
pg_description | t
|
||||||
|
pg_enum | t
|
||||||
pg_index | t
|
pg_index | t
|
||||||
pg_inherits | t
|
pg_inherits | t
|
||||||
pg_language | t
|
pg_language | t
|
||||||
|
@ -141,7 +142,7 @@ SELECT relname, relhasindex
|
||||||
timetz_tbl | f
|
timetz_tbl | f
|
||||||
tinterval_tbl | f
|
tinterval_tbl | f
|
||||||
varchar_tbl | f
|
varchar_tbl | f
|
||||||
(130 rows)
|
(131 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- another sanity check: every system catalog that has OIDs should have
|
-- another sanity check: every system catalog that has OIDs should have
|
||||||
|
|
|
@ -17,7 +17,7 @@ SELECT p1.oid, p1.typname
|
||||||
FROM pg_type as p1
|
FROM pg_type as p1
|
||||||
WHERE p1.typnamespace = 0 OR
|
WHERE p1.typnamespace = 0 OR
|
||||||
(p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
|
(p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
|
||||||
(p1.typtype not in ('b', 'c', 'd', 'p')) OR
|
(p1.typtype not in ('b', 'c', 'd', 'e', 'p')) OR
|
||||||
NOT p1.typisdefined OR
|
NOT p1.typisdefined OR
|
||||||
(p1.typalign not in ('c', 's', 'i', 'd')) OR
|
(p1.typalign not in ('c', 's', 'i', 'd')) OR
|
||||||
(p1.typstorage not in ('p', 'x', 'e', 'm'));
|
(p1.typstorage not in ('p', 'x', 'e', 'm'));
|
||||||
|
@ -55,11 +55,11 @@ WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR
|
||||||
-----+---------
|
-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
-- Look for basic types that don't have an array type.
|
-- Look for basic or enum types that don't have an array type.
|
||||||
-- NOTE: as of 8.0, this check finds smgr and unknown.
|
-- NOTE: as of 8.0, this check finds 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') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS
|
WHERE p1.typtype in ('b','e') 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);
|
p2.typelem = p1.oid);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# ----------
|
# ----------
|
||||||
# The first group of parallel test
|
# The first group of parallel test
|
||||||
# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.41 2007/03/19 16:44:41 tgl Exp $
|
# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.42 2007/04/02 03:49:42 tgl Exp $
|
||||||
# ----------
|
# ----------
|
||||||
test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric uuid
|
test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric uuid enum
|
||||||
|
|
||||||
# Depends on things setup during char, varchar and text
|
# Depends on things setup during char, varchar and text
|
||||||
test: strings
|
test: strings
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.38 2007/03/13 00:33:44 tgl Exp $
|
# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.39 2007/04/02 03:49:42 tgl Exp $
|
||||||
# This should probably be in an order similar to parallel_schedule.
|
# This should probably be in an order similar to parallel_schedule.
|
||||||
test: boolean
|
test: boolean
|
||||||
test: char
|
test: char
|
||||||
|
@ -14,6 +14,7 @@ test: float8
|
||||||
test: bit
|
test: bit
|
||||||
test: numeric
|
test: numeric
|
||||||
test: uuid
|
test: uuid
|
||||||
|
test: enum
|
||||||
test: strings
|
test: strings
|
||||||
test: numerology
|
test: numerology
|
||||||
test: point
|
test: point
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
--
|
||||||
|
-- Enum tests
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Did it create the right number of rows?
|
||||||
|
--
|
||||||
|
SELECT COUNT(*) FROM pg_enum WHERE enumtypid = 'rainbow'::regtype;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- I/O functions
|
||||||
|
--
|
||||||
|
SELECT 'red'::rainbow;
|
||||||
|
SELECT 'mauve'::rainbow;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Basic table creation, row selection
|
||||||
|
--
|
||||||
|
CREATE TABLE enumtest (col rainbow);
|
||||||
|
INSERT INTO enumtest values ('red'), ('orange'), ('yellow'), ('green');
|
||||||
|
COPY enumtest FROM stdin;
|
||||||
|
blue
|
||||||
|
purple
|
||||||
|
\.
|
||||||
|
SELECT * FROM enumtest;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Operators, no index
|
||||||
|
--
|
||||||
|
SELECT * FROM enumtest WHERE col = 'orange';
|
||||||
|
SELECT * FROM enumtest WHERE col <> 'orange' ORDER BY col;
|
||||||
|
SELECT * FROM enumtest WHERE col > 'yellow' ORDER BY col;
|
||||||
|
SELECT * FROM enumtest WHERE col >= 'yellow' ORDER BY col;
|
||||||
|
SELECT * FROM enumtest WHERE col < 'green' ORDER BY col;
|
||||||
|
SELECT * FROM enumtest WHERE col <= 'green' ORDER BY col;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Cast to/from text
|
||||||
|
--
|
||||||
|
SELECT 'red'::rainbow::text || 'hithere';
|
||||||
|
SELECT 'red'::text::rainbow = 'red'::rainbow;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Aggregates
|
||||||
|
--
|
||||||
|
SELECT min(col) FROM enumtest;
|
||||||
|
SELECT max(col) FROM enumtest;
|
||||||
|
SELECT max(col) FROM enumtest WHERE col < 'green';
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Index tests, force use of index
|
||||||
|
--
|
||||||
|
SET enable_seqscan = off;
|
||||||
|
SET enable_bitmapscan = off;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Btree index / opclass with the various operators
|
||||||
|
--
|
||||||
|
CREATE UNIQUE INDEX enumtest_btree ON enumtest USING btree (col);
|
||||||
|
SELECT * FROM enumtest WHERE col = 'orange';
|
||||||
|
SELECT * FROM enumtest WHERE col <> 'orange' ORDER BY col;
|
||||||
|
SELECT * FROM enumtest WHERE col > 'yellow' ORDER BY col;
|
||||||
|
SELECT * FROM enumtest WHERE col >= 'yellow' ORDER BY col;
|
||||||
|
SELECT * FROM enumtest WHERE col < 'green' ORDER BY col;
|
||||||
|
SELECT * FROM enumtest WHERE col <= 'green' ORDER BY col;
|
||||||
|
SELECT min(col) FROM enumtest;
|
||||||
|
SELECT max(col) FROM enumtest;
|
||||||
|
SELECT max(col) FROM enumtest WHERE col < 'green';
|
||||||
|
DROP INDEX enumtest_btree;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Hash index / opclass with the = operator
|
||||||
|
--
|
||||||
|
CREATE INDEX enumtest_hash ON enumtest USING hash (col);
|
||||||
|
SELECT * FROM enumtest WHERE col = 'orange';
|
||||||
|
DROP INDEX enumtest_hash;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- End index tests
|
||||||
|
--
|
||||||
|
RESET enable_seqscan;
|
||||||
|
RESET enable_bitmapscan;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Domains over enums
|
||||||
|
--
|
||||||
|
CREATE DOMAIN rgb AS rainbow CHECK (VALUE IN ('red', 'green', 'blue'));
|
||||||
|
SELECT 'red'::rgb;
|
||||||
|
SELECT 'purple'::rgb;
|
||||||
|
SELECT 'purple'::rainbow::rgb;
|
||||||
|
DROP DOMAIN rgb;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Arrays
|
||||||
|
--
|
||||||
|
SELECT '{red,green,blue}'::rainbow[];
|
||||||
|
SELECT ('{red,green,blue}'::rainbow[])[2];
|
||||||
|
SELECT 'red' = ANY ('{red,green,blue}'::rainbow[]);
|
||||||
|
SELECT 'yellow' = ANY ('{red,green,blue}'::rainbow[]);
|
||||||
|
SELECT 'red' = ALL ('{red,green,blue}'::rainbow[]);
|
||||||
|
SELECT 'red' = ALL ('{red,red}'::rainbow[]);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Support functions
|
||||||
|
--
|
||||||
|
SELECT enum_first(NULL::rainbow);
|
||||||
|
SELECT enum_last('green'::rainbow);
|
||||||
|
SELECT enum_range(NULL::rainbow);
|
||||||
|
SELECT enum_range('orange'::rainbow, 'green'::rainbow);
|
||||||
|
SELECT enum_range(NULL, 'green'::rainbow);
|
||||||
|
SELECT enum_range('orange'::rainbow, NULL);
|
||||||
|
SELECT enum_range(NULL::rainbow, NULL);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- User functions, can't test perl/python etc here since may not be compiled.
|
||||||
|
--
|
||||||
|
CREATE FUNCTION echo_me(anyenum) RETURNS text AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN $1::text || 'omg';
|
||||||
|
END
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
SELECT echo_me('red'::rainbow);
|
||||||
|
--
|
||||||
|
-- Concrete function should override generic one
|
||||||
|
--
|
||||||
|
CREATE FUNCTION echo_me(rainbow) RETURNS text AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN $1::text || 'wtf';
|
||||||
|
END
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
SELECT echo_me('red'::rainbow);
|
||||||
|
--
|
||||||
|
-- If we drop the original generic one, we don't have to qualify the type
|
||||||
|
-- anymore, since there's only one match
|
||||||
|
--
|
||||||
|
DROP FUNCTION echo_me(anyenum);
|
||||||
|
SELECT echo_me('red');
|
||||||
|
DROP FUNCTION echo_me(rainbow);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- RI triggers on enum types
|
||||||
|
--
|
||||||
|
CREATE TABLE enumtest_parent (id rainbow PRIMARY KEY);
|
||||||
|
CREATE TABLE enumtest_child (parent rainbow REFERENCES enumtest_parent);
|
||||||
|
INSERT INTO enumtest_parent VALUES ('red');
|
||||||
|
INSERT INTO enumtest_child VALUES ('red');
|
||||||
|
INSERT INTO enumtest_child VALUES ('blue'); -- fail
|
||||||
|
DELETE FROM enumtest_parent; -- fail
|
||||||
|
--
|
||||||
|
-- cross-type RI should fail
|
||||||
|
--
|
||||||
|
CREATE TYPE bogus AS ENUM('good', 'bad', 'ugly');
|
||||||
|
CREATE TABLE enumtest_bogus_child(parent bogus REFERENCES enumtest_parent);
|
||||||
|
DROP TYPE bogus;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Cleanup
|
||||||
|
--
|
||||||
|
DROP TABLE enumtest_child;
|
||||||
|
DROP TABLE enumtest_parent;
|
||||||
|
DROP TABLE enumtest;
|
||||||
|
DROP TYPE rainbow;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Verify properly cleaned up
|
||||||
|
--
|
||||||
|
SELECT COUNT(*) FROM pg_type WHERE typname = 'rainbow';
|
||||||
|
SELECT * FROM pg_enum WHERE NOT EXISTS
|
||||||
|
(SELECT 1 FROM pg_type WHERE pg_type.oid = enumtypid);
|
|
@ -20,7 +20,7 @@ SELECT p1.oid, p1.typname
|
||||||
FROM pg_type as p1
|
FROM pg_type as p1
|
||||||
WHERE p1.typnamespace = 0 OR
|
WHERE p1.typnamespace = 0 OR
|
||||||
(p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
|
(p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
|
||||||
(p1.typtype not in ('b', 'c', 'd', 'p')) OR
|
(p1.typtype not in ('b', 'c', 'd', 'e', 'p')) OR
|
||||||
NOT p1.typisdefined OR
|
NOT p1.typisdefined OR
|
||||||
(p1.typalign not in ('c', 's', 'i', 'd')) OR
|
(p1.typalign not in ('c', 's', 'i', 'd')) OR
|
||||||
(p1.typstorage not in ('p', 'x', 'e', 'm'));
|
(p1.typstorage not in ('p', 'x', 'e', 'm'));
|
||||||
|
@ -49,12 +49,12 @@ 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 types that don't have an array type.
|
-- Look for basic or enum types that don't have an array type.
|
||||||
-- NOTE: as of 8.0, this check finds smgr and unknown.
|
-- NOTE: as of 8.0, this check finds 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') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS
|
WHERE p1.typtype in ('b','e') 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);
|
p2.typelem = p1.oid);
|
||||||
|
|
Loading…
Reference in New Issue