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:
Tom Lane 2007-04-02 03:49:42 +00:00
parent a482a3e58b
commit 57690c6803
74 changed files with 2398 additions and 332 deletions

View File

@ -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
-->
@ -128,6 +128,11 @@
<entry>descriptions or comments on database objects</entry>
</row>
<row>
<entry><link linkend="catalog-pg-enum"><structname>pg_enum</structname></link></entry>
<entry>enum label and value definitions</entry>
</row>
<row>
<entry><link linkend="catalog-pg-index"><structname>pg_index</structname></link></entry>
<entry>additional index information</entry>
@ -1425,11 +1430,7 @@
in which the source and target types are the same, if the associated
function takes more than one argument. Such entries represent
<quote>length coercion functions</> that coerce values of the type
to be legal for a particular type modifier value. Note however that
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.
to be legal for a particular type modifier value.
</para>
<para>
@ -2413,6 +2414,55 @@
</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">
<title><structname>pg_index</structname></title>
@ -4395,11 +4445,13 @@
<entry><type>char</type></entry>
<entry></entry>
<entry>
<structfield>typtype</structfield> is <literal>b</literal> for
a base type, <literal>c</literal> for a composite type (e.g., a
table's row type), <literal>d</literal> for a domain, or
<literal>p</literal> for a pseudo-type. See also
<structfield>typrelid</structfield> and
<structfield>typtype</structfield> is
<literal>b</literal> for a base type,
<literal>c</literal> for a composite type (e.g., a table's row type),
<literal>d</literal> for a domain,
<literal>e</literal> for an enum type,
or <literal>p</literal> for a pseudo-type.
See also <structfield>typrelid</structfield> and
<structfield>typbasetype</structfield>
</entry>
</row>

View File

@ -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">
<title id="datatype-title">Data Types</title>
@ -2424,6 +2424,161 @@ SELECT * FROM test1 WHERE a;
</para>
</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">
<title>Geometric Types</title>
@ -3278,6 +3433,10 @@ SELECT * FROM pg_attribute
<primary>anyelement</primary>
</indexterm>
<indexterm zone="datatype-pseudo">
<primary>anyenum</primary>
</indexterm>
<indexterm zone="datatype-pseudo">
<primary>void</primary>
</indexterm>
@ -3343,6 +3502,13 @@ SELECT * FROM pg_attribute
(see <xref linkend="extend-types-polymorphic">).</entry>
</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>
<entry><type>cstring</></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
only <type>void</> and <type>record</> as a result type (plus
<type>trigger</> when the function is used as a trigger). Some also
support polymorphic functions using the types <type>anyarray</> and
<type>anyelement</>.
support polymorphic functions using the types <type>anyarray</>,
<type>anyelement</> and <type>anyenum</>.
</para>
<para>

View File

@ -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">
<title>Extending <acronym>SQL</acronym></title>
@ -193,9 +193,10 @@
</indexterm>
<para>
Two pseudo-types of special interest are <type>anyelement</> and
<type>anyarray</>, which are collectively called <firstterm>polymorphic
types</>. Any function declared using these types is said to be
Three pseudo-types of special interest are <type>anyelement</>,
<type>anyarray</>, and <type>anyenum</>,
which are collectively called <firstterm>polymorphic types</>.
Any function declared using these types is said to be
a <firstterm>polymorphic function</>. A polymorphic function can
operate on many different data types, with the specific data type(s)
being determined by the data types actually passed to it in a particular
@ -215,6 +216,9 @@
<type>anyelement</type>, the actual array type in the
<type>anyarray</type> positions must be an array whose elements are
the same type appearing in the <type>anyelement</type> positions.
<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>
@ -234,7 +238,9 @@
implements subscripting as <literal>subscript(anyarray, integer)
returns anyelement</>. This declaration constrains the actual first
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>
</sect2>
</sect1>

View File

@ -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">
<title>Functions and Operators</title>
@ -6646,6 +6646,87 @@ SELECT pg_sleep(1.5);
</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">
<title>Geometric Functions and Operators</title>

View File

@ -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">
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
@ -210,7 +210,8 @@ $$ LANGUAGE plpgsql;
<para>
<application>PL/pgSQL</> functions can also be declared to accept
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
call, as discussed in <xref linkend="extend-types-polymorphic">.
An example is shown in <xref linkend="plpgsql-declaration-aliases">.
@ -698,8 +699,9 @@ $$ LANGUAGE plpgsql;
<para>
When the return type of a <application>PL/pgSQL</application>
function is declared as a polymorphic type (<type>anyelement</type>
or <type>anyarray</type>), a special parameter <literal>$0</literal>
function is declared as a polymorphic type (<type>anyelement</type>,
<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,
as deduced from the actual input types (see <xref
linkend="extend-types-polymorphic">).
@ -726,7 +728,7 @@ $$ LANGUAGE plpgsql;
<para>
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
parameters themselves serve the same purpose. For example:

View File

@ -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
-->
@ -23,6 +23,9 @@ PostgreSQL documentation
CREATE TYPE <replaceable class="parameter">name</replaceable> AS
( <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> (
INPUT = <replaceable class="parameter">input_function</replaceable>,
OUTPUT = <replaceable class="parameter">output_function</replaceable>
@ -77,11 +80,23 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
</para>
</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>
<title>Base Types</title>
<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
illustrated above, and most are optional. You must register
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>
<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
associated array type, whose name consists of the base type's
name prepended with an underscore. The parser understands this
@ -363,6 +378,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable>
</listitem>
</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>
<term><replaceable class="parameter">input_function</replaceable></term>
<listitem>
@ -567,6 +592,20 @@ $$ LANGUAGE SQL;
</programlisting>
</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>
This example creates the base data type <type>box</type> and then uses the
type in a table definition:

View File

@ -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">
<title>User-Defined Functions</title>
@ -717,8 +717,8 @@ SELECT name, listchildren(name) FROM nodes;
<para>
<acronym>SQL</acronym> functions can be declared to accept and
return the polymorphic types <type>anyelement</type> and
<type>anyarray</type>. See <xref
return the polymorphic types <type>anyelement</type>,
<type>anyarray</type>, and <type>anyenum</type>. See <xref
linkend="extend-types-polymorphic"> for a more detailed
explanation of polymorphic functions. Here is a polymorphic
function <function>make_array</function> that builds up an array
@ -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:
<screen>
<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>
</screen>
</para>
@ -769,7 +769,7 @@ CREATE FUNCTION invalid_func() RETURNS anyelement AS $$
SELECT 1;
$$ LANGUAGE SQL;
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>
</para>
@ -2831,7 +2831,7 @@ CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
<para>
C-language functions can be declared to accept and
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
of polymorphic functions. When function arguments or return types
are defined as polymorphic types, the function author cannot know

View File

@ -8,7 +8,7 @@
*
*
* 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
* 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)));
}
Datum
hashenum(PG_FUNCTION_ARGS)
{
PG_RETURN_UINT32(~((uint32) PG_GETARG_OID(0)));
}
Datum
hashfloat4(PG_FUNCTION_ARGS)
{

View File

@ -2,7 +2,7 @@
#
# 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
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_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_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_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_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
toasting.h indexing.h \

View File

@ -8,7 +8,7 @@
*
*
* 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
@ -412,7 +412,7 @@ CheckAttributeType(const char *attname, Oid atttypid)
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" has type \"unknown\"", attname),
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 */
if (atttypid != ANYARRAYOID || IsUnderPostmaster)
@ -718,7 +718,7 @@ AddNewRelationType(const char *typeName,
new_rel_oid, /* relation oid */
new_rel_kind, /* relation kind */
-1, /* internal size (varlena) */
'c', /* type-type (complex) */
TYPTYPE_COMPOSITE, /* type-type (composite) */
',', /* default array delimiter */
F_RECORD_IN, /* input procedure */
F_RECORD_OUT, /* output procedure */

View File

@ -8,7 +8,7 @@
*
*
* 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;
for (i = 0; i < numArgs; i++)
{
if (aggArgTypes[i] == ANYARRAYOID ||
aggArgTypes[i] == ANYELEMENTOID)
if (IsPolymorphicType(aggArgTypes[i]))
{
hasPolyArg = true;
break;
@ -92,12 +91,11 @@ AggregateCreate(const char *aggName,
* If transtype is polymorphic, must have polymorphic argument also; else
* we will have no way to deduce the actual transtype.
*/
if (!hasPolyArg &&
(aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID))
if (IsPolymorphicType(aggTransType) && !hasPolyArg)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
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 */
nargs_transfn = numArgs + 1;
@ -170,13 +168,12 @@ AggregateCreate(const char *aggName,
* that itself violates the rule against polymorphic result with no
* polymorphic input.)
*/
if (!hasPolyArg &&
(finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID))
if (IsPolymorphicType(finaltype) && !hasPolyArg)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot determine result data type"),
errdetail("An aggregate returning \"anyarray\" or \"anyelement\" "
"must have at least one argument of either type.")));
errdetail("An aggregate returning a polymorphic type "
"must have at least one polymorphic argument.")));
/* handle sortop, if supplied */
if (aggsortopName)
@ -329,8 +326,7 @@ lookup_agg_function(List *fnName,
*/
for (i = 0; i < nargs; i++)
{
if (input_types[i] != ANYARRAYOID &&
input_types[i] != ANYELEMENTOID)
if (!IsPolymorphicType(input_types[i]))
{
allPolyArgs = false;
break;
@ -351,8 +347,7 @@ lookup_agg_function(List *fnName,
*/
for (i = 0; i < nargs; i++)
{
if (true_oid_array[i] != ANYARRAYOID &&
true_oid_array[i] != ANYELEMENTOID &&
if (!IsPolymorphicType(true_oid_array[i]) &&
!IsBinaryCoercible(input_types[i], true_oid_array[i]))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),

View File

@ -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;
}

View File

@ -8,7 +8,7 @@
*
*
* 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
* input argument is ANYARRAY or ANYELEMENT. Also, do not allow return
* type INTERNAL unless at least one input argument is INTERNAL.
* Do not allow polymorphic return type unless at least one input argument
* is polymorphic. Also, do not allow return type INTERNAL unless at
* least one input argument is INTERNAL.
*/
for (i = 0; i < parameterCount; i++)
{
@ -147,6 +147,7 @@ ProcedureCreate(const char *procedureName,
{
case ANYARRAYOID:
case ANYELEMENTOID:
case ANYENUMOID:
genericInParam = true;
break;
case INTERNALOID:
@ -169,6 +170,7 @@ ProcedureCreate(const char *procedureName,
{
case ANYARRAYOID:
case ANYELEMENTOID:
case ANYENUMOID:
genericOutParam = true;
break;
case INTERNALOID:
@ -178,12 +180,12 @@ ProcedureCreate(const char *procedureName,
}
}
if ((returnType == ANYARRAYOID || returnType == ANYELEMENTOID ||
genericOutParam) && !genericInParam)
if ((IsPolymorphicType(returnType) || genericOutParam)
&& !genericInParam)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
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)
ereport(ERROR,
@ -533,26 +535,24 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
proc = (Form_pg_proc) GETSTRUCT(tuple);
/* Disallow pseudotype result */
/* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */
if (get_typtype(proc->prorettype) == 'p' &&
/* except for RECORD, VOID, or polymorphic */
if (get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
proc->prorettype != RECORDOID &&
proc->prorettype != VOIDOID &&
proc->prorettype != ANYARRAYOID &&
proc->prorettype != ANYELEMENTOID)
!IsPolymorphicType(proc->prorettype))
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SQL functions cannot return type %s",
format_type_be(proc->prorettype))));
/* Disallow pseudotypes in arguments */
/* except for ANYARRAY or ANYELEMENT */
/* except for polymorphic */
haspolyarg = false;
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 ||
proc->proargtypes.values[i] == ANYELEMENTOID)
if (IsPolymorphicType(proc->proargtypes.values[i]))
haspolyarg = true;
else
ereport(ERROR,

View File

@ -8,7 +8,7 @@
*
*
* 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
* 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.
*/
i = 0;
@ -85,7 +85,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */
values[i++] = BoolGetDatum(true); /* typbyval */
values[i++] = CharGetDatum('p'); /* typtype */
values[i++] = CharGetDatum(TYPTYPE_PSEUDO); /* typtype */
values[i++] = BoolGetDatum(false); /* typisdefined */
values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
@ -159,7 +159,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
Oid
TypeCreate(const char *typeName,
Oid typeNamespace,
Oid relationOid, /* only for 'c'atalog types */
Oid relationOid, /* only for composite types */
char relationKind, /* ditto */
int16 internalSize,
char typeType,
@ -243,7 +243,8 @@ TypeCreate(const char *typeName,
values[i++] = CharGetDatum(typeType); /* typtype */
values[i++] = BoolGetDatum(true); /* typisdefined */
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(inputProcedure); /* typinput */
values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */
@ -377,7 +378,7 @@ TypeCreate(const char *typeName,
void
GenerateTypeDependencies(Oid typeNamespace,
Oid typeObjectId,
Oid relationOid, /* only for 'c'atalog types */
Oid relationOid, /* only for composite types */
char relationKind, /* ditto */
Oid owner,
Oid inputProcedure,

View File

@ -9,7 +9,7 @@
*
*
* 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
* 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).
*/
transTypeId = typenameTypeId(NULL, transType);
if (get_typtype(transTypeId) == 'p' &&
transTypeId != ANYARRAYOID &&
transTypeId != ANYELEMENTOID)
if (get_typtype(transTypeId) == TYPTYPE_PSEUDO &&
!IsPolymorphicType(transTypeId))
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregate transition data type cannot be %s",

View File

@ -10,7 +10,7 @@
*
*
* 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
* These routines take the parse tree and pick out the
@ -1259,13 +1259,13 @@ CreateCast(CreateCastStmt *stmt)
targettypeid = typenameTypeId(NULL, stmt->targettype);
/* No pseudo-types allowed */
if (get_typtype(sourcetypeid) == 'p')
if (get_typtype(sourcetypeid) == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("source data type %s is a pseudo-type",
TypeNameToString(stmt->sourcetype))));
if (get_typtype(targettypeid) == 'p')
if (get_typtype(targettypeid) == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("target data type %s is a pseudo-type",

View File

@ -8,7 +8,7 @@
*
*
* 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
* The "DefineFoo" routines take the parse tree and pick out the
@ -39,6 +39,7 @@
#include "catalog/indexing.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
@ -205,7 +206,7 @@ DefineType(List *names, List *parameters)
{
elemType = typenameTypeId(NULL, defGetTypeName(defel));
/* disallow arrays of pseudotypes */
if (get_typtype(elemType) == 'p')
if (get_typtype(elemType) == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array element type cannot be %s",
@ -404,7 +405,7 @@ DefineType(List *names, List *parameters)
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
internalLength, /* internal size */
'b', /* type-type (base type) */
TYPTYPE_BASE, /* type-type (base type) */
delimiter, /* array element delimiter */
inputOid, /* input procedure */
outputOid, /* output procedure */
@ -438,7 +439,7 @@ DefineType(List *names, List *parameters)
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
-1, /* internal size */
'b', /* type-type (base type) */
TYPTYPE_BASE, /* type-type (base type) */
DEFAULT_TYPDELIM, /* array element delimiter */
F_ARRAY_IN, /* input procedure */
F_ARRAY_OUT, /* output procedure */
@ -543,6 +544,14 @@ RemoveTypeById(Oid typeOid)
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);
heap_close(relation, RowExclusiveLock);
@ -620,12 +629,15 @@ DefineDomain(CreateDomainStmt *stmt)
basetypeMod = typenameTypeMod(NULL, stmt->typename, basetypeoid);
/*
* Base type must be a plain base type or another domain. Domains over
* pseudotypes would create a security hole. Domains over composite types
* might be made to work in the future, but not today.
* Base type must be a plain base type, another domain or an enum.
* Domains over pseudotypes would create a security hole. Domains
* over composite types might be made to work in the future, but not
* today.
*/
typtype = baseType->typtype;
if (typtype != 'b' && typtype != 'd')
if (typtype != TYPTYPE_BASE &&
typtype != TYPTYPE_DOMAIN &&
typtype != TYPTYPE_ENUM)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("\"%s\" is not a valid base type for a domain",
@ -798,7 +810,7 @@ DefineDomain(CreateDomainStmt *stmt)
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
internalLength, /* internal size */
'd', /* type-type (domain type) */
TYPTYPE_DOMAIN, /* type-type (domain type) */
delimiter, /* array element delimiter */
inputProcedure, /* input procedure */
outputProcedure, /* output procedure */
@ -907,7 +919,7 @@ RemoveDomain(List *names, DropBehavior behavior, bool missing_ok)
/* Check that this is actually a domain */
typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
if (typtype != 'd')
if (typtype != TYPTYPE_DOMAIN)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a domain",
@ -925,6 +937,100 @@ RemoveDomain(List *names, DropBehavior behavior, bool missing_ok)
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.
@ -1835,7 +1941,7 @@ checkDomainOwner(HeapTuple tup, TypeName *typename)
Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
/* Check that this is actually a domain */
if (typTup->typtype != 'd')
if (typTup->typtype != TYPTYPE_DOMAIN)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a domain",
@ -2021,7 +2127,7 @@ GetDomainConstraints(Oid typeOid)
elog(ERROR, "cache lookup failed for type %u", typeOid);
typTup = (Form_pg_type) GETSTRUCT(tup);
if (typTup->typtype != 'd')
if (typTup->typtype != TYPTYPE_DOMAIN)
{
/* Not a domain, so done */
ReleaseSysCache(tup);
@ -2148,7 +2254,7 @@ AlterTypeOwner(List *names, Oid newOwnerId)
* free-standing composite type, and not a table's underlying type. We
* 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)
ereport(ERROR,
(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) */
isCompositeType =
(typform->typtype == 'c' &&
(typform->typtype == TYPTYPE_COMPOSITE &&
get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
/* Enforce not-table-type if requested */
if (typform->typtype == 'c' && !isCompositeType && errorOnTableType)
if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
errorOnTableType)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("%s is a table's row type",
@ -2376,14 +2483,14 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
else
{
/* If it's a domain, it might have constraints */
if (typform->typtype == 'd')
if (typform->typtype == TYPTYPE_DOMAIN)
AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
/*
* Update dependency on schema, if any --- a table rowtype has not got
* one.
*/
if (typform->typtype != 'c')
if (typform->typtype != TYPTYPE_COMPOSITE)
if (changeDependencyFor(TypeRelationId, typeOid,
NamespaceRelationId, oldNspOid, nspOid) != 1)
elog(ERROR, "failed to change schema dependency for type %s",

View File

@ -8,7 +8,7 @@
*
*
* 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;
if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
if (IsPolymorphicType(rettype))
{
rettype = get_fn_expr_rettype(finfo);
if (rettype == InvalidOid) /* this probably should not happen */
@ -218,7 +218,7 @@ init_sql_fcache(FmgrInfo *finfo)
{
Oid argtype = argOidVect[argnum];
if (argtype == ANYARRAYOID || argtype == ANYELEMENTOID)
if (IsPolymorphicType(argtype))
{
argtype = get_fn_expr_argtype(finfo, argnum);
if (argtype == InvalidOid)
@ -845,9 +845,9 @@ ShutdownSQLFunction(Datum arg)
* to be sure that the user is returning the type he claims.
*
* For a polymorphic function the passed rettype must be the actual resolved
* output type of the function; we should never see ANYARRAY or ANYELEMENT
* as rettype. (This means we can't check the type during function definition
* of a polymorphic function.)
* output type of the function; we should never see ANYARRAY, ANYENUM or
* ANYELEMENT as rettype. (This means we can't check the type during function
* definition of a polymorphic function.)
*
* 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
@ -925,7 +925,9 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
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
@ -948,7 +950,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
errdetail("Actual return type is %s.",
format_type_be(restype))));
}
else if (fn_typtype == 'c' || rettype == RECORDOID)
else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
{
/* Returns a rowtype */
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 */
return true;
}
else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
else if (IsPolymorphicType(rettype))
{
/* This should already have been caught ... */
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
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
ereport(ERROR,

View File

@ -61,7 +61,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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
* the agg's declared input types, when the agg accepts ANY, ANYARRAY
* or ANYELEMENT.
* the agg's declared input types, when the agg accepts ANY or
* a polymorphic type.
*/
i = 0;
foreach(lc, aggref->args)
@ -1421,7 +1421,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
/* resolve actual type of transition state, if polymorphic */
aggtranstype = aggform->aggtranstype;
if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
if (IsPolymorphicType(aggtranstype))
{
/* have to fetch the agg's declared input types... */
Oid *declaredArgTypes;

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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;
}
static CreateEnumStmt *
_copyCreateEnumStmt(CreateEnumStmt *from)
{
CreateEnumStmt *newnode = makeNode(CreateEnumStmt);
COPY_NODE_FIELD(typename);
COPY_NODE_FIELD(vals);
return newnode;
}
static ViewStmt *
_copyViewStmt(ViewStmt *from)
{
@ -3312,6 +3323,9 @@ copyObject(void *from)
case T_CompositeTypeStmt:
retval = _copyCompositeTypeStmt(from);
break;
case T_CreateEnumStmt:
retval = _copyCreateEnumStmt(from);
break;
case T_ViewStmt:
retval = _copyViewStmt(from);
break;

View File

@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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;
}
static bool
_equalCreateEnumStmt(CreateEnumStmt *a, CreateEnumStmt *b)
{
COMPARE_NODE_FIELD(typename);
COMPARE_NODE_FIELD(vals);
return true;
}
static bool
_equalViewStmt(ViewStmt *a, ViewStmt *b)
{
@ -2247,6 +2256,9 @@ equal(void *a, void *b)
case T_CompositeTypeStmt:
retval = _equalCompositeTypeStmt(a, b);
break;
case T_CreateEnumStmt:
retval = _equalCreateEnumStmt(a, b);
break;
case T_ViewStmt:
retval = _equalViewStmt(a, b);
break;

View File

@ -8,7 +8,7 @@
*
*
* 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
* AUTHOR DATE MAJOR EVENT
@ -435,7 +435,7 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts)
ReleaseSysCache(aggTuple);
/* 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... */
Oid *declaredArgTypes;
@ -2907,8 +2907,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
funcform->pronargs * sizeof(Oid));
for (i = 0; i < funcform->pronargs; i++)
{
if (argtypes[i] == ANYARRAYOID ||
argtypes[i] == ANYELEMENTOID)
if (IsPolymorphicType(argtypes[i]))
{
argtypes[i] = exprType((Node *) list_nth(args, i));
}

View File

@ -11,7 +11,7 @@
*
*
* 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
* AUTHOR DATE MAJOR EVENT
@ -248,6 +248,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
TableFuncElementList opt_type_modifiers
prep_type_clause
execute_param_clause using_clause returning_clause
enum_val_list
%type <range> OptTempTableName
%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
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
FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
@ -2922,6 +2923,13 @@ DefineStmt:
n->coldeflist = $6;
$$ = (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; }
@ -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
| ENCODING
| ENCRYPTED
| ENUM_P
| ESCAPE
| EXCLUDING
| EXCLUSIVE

View File

@ -8,7 +8,7 @@
*
*
* 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},
{"encrypted", ENCRYPTED},
{"end", END_P},
{"enum", ENUM_P},
{"escape", ESCAPE},
{"except", EXCEPT},
{"excluding", EXCLUDING},

View File

@ -8,7 +8,7 @@
*
*
* 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 ||
targetTypeId == ANYELEMENTOID ||
(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID))
(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID) ||
(targetTypeId == ANYENUMOID && inputTypeId != UNKNOWNOID))
{
/*
* 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
* an UNKNOWN value is definitely *not* an array, and so we mustn't
* 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.
*/
@ -406,9 +408,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
if (targetTypeId == ANYOID)
continue;
/* accept if target is ANYARRAY or ANYELEMENT, for now */
if (targetTypeId == ANYARRAYOID ||
targetTypeId == ANYELEMENTOID)
/* accept if target is polymorphic, for now */
if (IsPolymorphicType(targetTypeId))
{
have_generics = true; /* do more checking later */
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
* the actual ANYELEMENT datatype is in fact the element type for
* 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
* 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_typelem;
bool have_anyelement = false;
bool have_anyenum = false;
/*
* 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];
if (declared_arg_types[j] == ANYELEMENTOID)
if (declared_arg_types[j] == ANYELEMENTOID ||
declared_arg_types[j] == ANYENUMOID)
{
have_anyelement = true;
if (declared_arg_types[j] == ANYENUMOID)
have_anyenum = true;
if (actual_type == UNKNOWNOID)
continue;
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 */
return true;
}
@ -1136,18 +1151,18 @@ check_generic_type_consistency(Oid *actual_arg_types,
* Make sure a polymorphic function is legally callable, and
* 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
* each other. The argument consistency rules are shown above for
* check_generic_type_consistency().
*
* If we have UNKNOWN input (ie, an untyped literal) for any ANYELEMENT
* or ANYARRAY argument, we attempt to deduce the actual type it should
* have. If successful, we alter that position of declared_arg_types[]
* so that make_fn_arguments will coerce the literal to the right thing.
* If we have UNKNOWN input (ie, an untyped literal) for any polymorphic
* argument, we attempt to deduce the actual type it should have. If
* successful, we alter that position of declared_arg_types[] so that
* make_fn_arguments will coerce the literal to the right thing.
*
* 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
* 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,
* generate an ERROR. This condition is prevented by CREATE FUNCTION
* 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
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 array_typeid = InvalidOid;
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
@ -1190,9 +1210,12 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
{
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;
if (declared_arg_types[j] == ANYENUMOID)
have_anyenum = true;
if (actual_type == UNKNOWNOID)
{
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
* the unmodified rettype.
* Fast Track: if none of the arguments are polymorphic, return the
* unmodified rettype. We assume it can't be polymorphic either.
*/
if (!have_generics)
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 */
ereport(ERROR,
(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)
continue;
if (declared_arg_types[j] == ANYELEMENTOID)
if (declared_arg_types[j] == ANYELEMENTOID ||
declared_arg_types[j] == ANYENUMOID)
declared_arg_types[j] = elem_typeid;
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 (!OidIsValid(array_typeid))
@ -1322,8 +1356,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
return array_typeid;
}
/* if we return ANYELEMENTOID use the appropriate argument type */
if (rettype == ANYELEMENTOID)
/* if we return ANYELEMENT use the appropriate argument type */
if (rettype == ANYELEMENTOID || rettype == ANYENUMOID)
return elem_typeid;
/* 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()
* 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.
* 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))));
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 */
Oid array_typeid = get_array_type(context_actual_type);
@ -1375,7 +1410,7 @@ resolve_generic_type(Oid declared_type,
return array_typeid;
}
}
else if (declared_type == ANYELEMENTOID)
else if (declared_type == ANYELEMENTOID || declared_type == ANYENUMOID)
{
if (context_declared_type == ANYARRAYOID)
{
@ -1389,7 +1424,8 @@ resolve_generic_type(Oid declared_type,
format_type_be(context_actual_type))));
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 */
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 */
/* 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 */
}
@ -1502,6 +1538,7 @@ TypeCategory(Oid inType)
case (INTERNALOID):
case (OPAQUEOID):
case (ANYELEMENTOID):
case (ANYENUMOID):
result = GENERIC_TYPE;
break;
@ -1647,6 +1684,11 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
if (get_element_type(srctype) != InvalidOid)
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 */
tuple = SearchSysCache(CASTSOURCETARGET,
ObjectIdGetDatum(srctype),
@ -1777,6 +1819,22 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
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;
@ -1813,7 +1871,7 @@ find_typmod_coercion_function(Oid typeId,
/* Check for a varlena array type (and not a domain) */
if (typeForm->typelem != InvalidOid &&
typeForm->typlen == -1 &&
typeForm->typtype != 'd')
typeForm->typtype != TYPTYPE_DOMAIN)
{
/* Yes, switch our attention to the element type */
typeId = typeForm->typelem;

View File

@ -8,7 +8,7 @@
*
*
* 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;
case RTE_FUNCTION:
toid = exprType(rte->funcexpr);
if (toid == RECORDOID || get_typtype(toid) == 'c')
if (type_is_rowtype(toid))
{
/* func returns composite; same as relation case */
result = (Node *) makeVar(vnum,

View File

@ -8,7 +8,7 @@
*
*
* 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;
/*
* enforce consistency with ANYARRAY and ANYELEMENT argument and return
* types, possibly adjusting return type or declared_arg_types (which will
* enforce consistency with polymorphic argument and return types,
* possibly adjusting return type or declared_arg_types (which will
* be used as the cast destination by make_fn_arguments)
*/
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
* 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 (!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)));
if (IsPolymorphicType(declared_arg_types[1]))
{
/* assume the actual array type is OK */
res_atypeId = atypeId;
}
else
{
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;
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
* types, possibly adjusting return type or declared_arg_types (which will
* enforce consistency with polymorphic argument and return types,
* possibly adjusting return type or declared_arg_types (which will
* be used as the cast destination by make_fn_arguments)
*/
rettype = enforce_generic_type_consistency(actual_arg_types,

View File

@ -8,7 +8,7 @@
*
*
* 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;
}
/* 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 */
char *
typeTypeName(Type t)

View File

@ -10,7 +10,7 @@
*
*
* 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_CreateTrigStmt:
case T_CompositeTypeStmt:
case T_CreateEnumStmt:
case T_ViewStmt:
case T_DropCastStmt:
case T_DropStmt:
@ -779,6 +780,10 @@ ProcessUtility(Node *parsetree,
}
break;
case T_CreateEnumStmt: /* CREATE TYPE (enum) */
DefineEnum((CreateEnumStmt *) parsetree);
break;
case T_ViewStmt: /* CREATE VIEW */
DefineView((ViewStmt *) parsetree, queryString);
break;
@ -1640,6 +1645,10 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE TYPE";
break;
case T_CreateEnumStmt:
tag = "CREATE TYPE";
break;
case T_ViewStmt:
tag = "CREATE VIEW";
break;
@ -2075,6 +2084,10 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL;
break;
case T_CreateEnumStmt:
lev = LOGSTMT_DDL;
break;
case T_ViewStmt:
lev = LOGSTMT_DDL;
break;

View File

@ -1,7 +1,7 @@
#
# 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
@ -17,7 +17,7 @@ endif
OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.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 \
misc.o nabstime.o name.o not_in.o numeric.o numutils.o \
oid.o oracle_compat.o pseudotypes.o rowtypes.o \

View File

@ -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;
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 &&
typeform->typstorage != 'p' &&
typeform->typtype != 'd')
typeform->typtype != TYPTYPE_DOMAIN)
{
/* Switch our attention to the array element type */
ReleaseSysCache(tuple);

View File

@ -16,7 +16,7 @@
*
*
* 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.
*

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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);
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_namespace_name(typtuple->typnamespace),
NameStr(typtuple->typname)));
@ -2877,7 +2877,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
break;
default:
if (get_typtype(typeoid) == 'd')
if (get_typtype(typeoid) == TYPTYPE_DOMAIN)
{
Oid base_typeoid;
int32 base_typmod = -1;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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
* 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
* 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;
else
return HeapTupleGetOid(typeTuple);
@ -2022,7 +2022,7 @@ getBaseTypeAndTypmod(Oid typid, int32 *typmod)
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for type %u", typid);
typTup = (Form_pg_type) GETSTRUCT(tup);
if (typTup->typtype != 'd')
if (typTup->typtype != TYPTYPE_DOMAIN)
{
/* Not a domain, so done */
ReleaseSysCache(tup);
@ -2128,7 +2128,17 @@ get_typtype(Oid typid)
bool
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);
}
/*

View File

@ -8,7 +8,7 @@
*
*
* 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
* These routines allow the parser/planner/executor to perform
@ -31,6 +31,7 @@
#include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
@ -335,6 +336,30 @@ static const struct cachedesc cacheinfo[] = {
},
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 */
IndexRelidIndexId,
Anum_pg_index_indrelid,

View File

@ -36,7 +36,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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) &&
typentry->tupDesc == NULL &&
typentry->typtype == 'c')
typentry->typtype == TYPTYPE_COMPOSITE)
{
Relation rel;

View File

@ -7,7 +7,7 @@
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
*
* 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.
*
* The other hard case that this handles is resolution of polymorphism.
* We will never return ANYELEMENT or ANYARRAY, either as a scalar result
* type or as a component of a rowtype.
* We will never return ANYELEMENT, ANYARRAY or ANYENUM, either as a scalar
* result type or as a component of a rowtype.
*
* This function is relatively expensive --- in a function returning set,
* 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 (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
if (IsPolymorphicType(rettype))
{
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,
* replace any polymorphic columns (ANYELEMENT/ANYARRAY) with correct data
* types deduced from the input arguments. Returns TRUE if able to deduce
* replace any polymorphic columns (ANYELEMENT/ANYARRAY/ANYENUM) with correct
* data types deduced from the input arguments. Returns TRUE if able to deduce
* all types, FALSE if not.
*/
static bool
@ -401,6 +401,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
int nargs = declared_args->dim1;
bool have_anyelement_result = false;
bool have_anyarray_result = false;
bool have_anyenum = false;
Oid anyelement_type = InvalidOid;
Oid anyarray_type = InvalidOid;
int i;
@ -416,6 +417,10 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
case ANYARRAYOID:
have_anyarray_result = true;
break;
case ANYENUMOID:
have_anyelement_result = true;
have_anyenum = true;
break;
default:
break;
}
@ -435,6 +440,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
switch (declared_args->values[i])
{
case ANYELEMENTOID:
case ANYENUMOID:
if (!OidIsValid(anyelement_type))
anyelement_type = get_call_expr_argtype(call_expr, i);
break;
@ -461,12 +467,17 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
anyelement_type,
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 */
for (i = 0; i < natts; i++)
{
switch (tupdesc->attrs[i]->atttypid)
{
case ANYELEMENTOID:
case ANYENUMOID:
TupleDescInitEntry(tupdesc, i + 1,
NameStr(tupdesc->attrs[i]->attname),
anyelement_type,
@ -490,8 +501,8 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
/*
* Given the declared argument types and modes for a function,
* replace any polymorphic types (ANYELEMENT/ANYARRAY) with correct data
* types deduced from the input arguments. Returns TRUE if able to deduce
* replace any polymorphic types (ANYELEMENT/ANYARRAY/ANYENUM) with correct
* data types deduced from the input arguments. Returns TRUE if able to deduce
* all types, FALSE if not. This is the same logic as
* 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])
{
case ANYELEMENTOID:
case ANYENUMOID:
if (argmode == PROARGMODE_OUT)
have_anyelement_result = true;
else
@ -571,12 +583,15 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
anyelement_type,
ANYELEMENTOID);
/* XXX do we need to enforce ANYENUM here? I think not */
/* And finally replace the output column types as needed */
for (i = 0; i < numargs; i++)
{
switch (argtypes[i])
{
case ANYELEMENTOID:
case ANYENUMOID:
argtypes[i] = anyelement_type;
break;
case ANYARRAYOID:
@ -603,12 +618,13 @@ get_type_func_class(Oid typid)
{
switch (get_typtype(typid))
{
case 'c':
case TYPTYPE_COMPOSITE:
return TYPEFUNC_COMPOSITE;
case 'b':
case 'd':
case TYPTYPE_BASE:
case TYPTYPE_DOMAIN:
case TYPTYPE_ENUM:
return TYPEFUNC_SCALAR;
case 'p':
case TYPTYPE_PSEUDO:
if (typid == RECORDOID)
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
* 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.
*/
TupleDesc

View File

@ -12,7 +12,7 @@
* by PostgreSQL
*
* 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 dumpType(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 dumpCompositeType(Archive *fout, TypeInfo *tinfo);
static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
@ -2085,7 +2086,7 @@ getTypes(int *numTypes)
*/
tinfo[i].nDomChecks = 0;
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]));
/*
@ -2097,7 +2098,7 @@ getTypes(int *numTypes)
* should copy the base type's catId, but then it might capture the
* 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->dobj.objType = DO_SHELL_TYPE;
@ -5119,12 +5120,91 @@ dumpType(Archive *fout, TypeInfo *tinfo)
return;
/* Dump out in proper style */
if (tinfo->typtype == 'b')
if (tinfo->typtype == TYPTYPE_BASE)
dumpBaseType(fout, tinfo);
else if (tinfo->typtype == 'd')
else if (tinfo->typtype == TYPTYPE_DOMAIN)
dumpDomain(fout, tinfo);
else if (tinfo->typtype == 'c')
else if (tinfo->typtype == TYPTYPE_COMPOSITE)
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);
}
/*

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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
* 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 hashint8(PG_FUNCTION_ARGS);
extern Datum hashoid(PG_FUNCTION_ARGS);
extern Datum hashenum(PG_FUNCTION_ARGS);
extern Datum hashfloat4(PG_FUNCTION_ARGS);
extern Datum hashfloat8(PG_FUNCTION_ARGS);
extern Datum hashoidvector(PG_FUNCTION_ARGS);

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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 */
#define CATALOG_VERSION_NO 200704011
#define CATALOG_VERSION_NO 200704012
#endif

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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));
#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 */
DECLARE_INDEX(pg_index_indrelid_index, 2678, on pg_index using btree(indrelid oid_ops));
#define IndexIndrelidIndexId 2678

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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
* 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 ( 2244 bpchar_larger - 1060 1042 _null_ ));
DATA(insert ( 2797 tidlarger - 2800 27 _null_ ));
DATA(insert ( 3526 enum_larger - 3519 3500 _null_ ));
/* min */
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 ( 2245 bpchar_smaller - 1058 1042 _null_ ));
DATA(insert ( 2798 tidsmaller - 2799 27 _null_ ));
DATA(insert ( 3527 enum_smaller - 3518 3500 _null_ ));
/* count */
DATA(insert ( 2147 int8inc_any - 0 20 "0" ));

View File

@ -29,7 +29,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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
* 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 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 */

View File

@ -22,7 +22,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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
* 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 ( 2789 27 27 1 2794 ));
DATA(insert ( 2968 2950 2950 1 2960 ));
DATA(insert ( 3522 3500 3500 1 3514 ));
/* hash */
@ -162,6 +163,7 @@ DATA(insert ( 2231 1042 1042 1 456 ));
DATA(insert ( 2232 19 19 1 455 ));
DATA(insert ( 2235 1033 1033 1 329 ));
DATA(insert ( 2969 2950 2950 1 2963 ));
DATA(insert ( 3523 3500 3500 1 3515 ));
/* gist */

View File

@ -10,7 +10,7 @@
*
* 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
* 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 ( 2950 1043 2965 a ));
/*
* enums
*/
DATA(insert ( 3500 25 3532 e ));
DATA(insert ( 25 3500 3533 e ));
#endif /* PG_CAST_H */

View File

@ -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 */

View File

@ -28,7 +28,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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
* 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 _reltime_ops PGNSP PGUID 2745 1024 t 703 ));
DATA(insert ( 2742 _tinterval_ops PGNSP PGUID 2745 1025 t 704 ));
DATA(insert ( 403 uuid_ops PGNSP PGUID 2968 2950 t 0 ));
DATA(insert ( 405 uuid_ops PGNSP PGUID 2969 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 ( 403 enum_ops PGNSP PGUID 3522 3500 t 0 ));
DATA(insert ( 405 enum_ops PGNSP PGUID 3523 3500 t 0 ));
#endif /* PG_OPCLASS_H */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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
* 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 = 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

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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
* 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 = 2968 ( 403 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 */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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
* 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_ ));
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
* of a function is dependent *only* on the values of its explicit arguments,

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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
* the genbki.sh script reads this file and generates .bki
@ -66,8 +66,9 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP
bool typbyval;
/*
* typtype is 'b' for a basic type, 'c' for a complex type (ie a table's
* rowtype), 'd' for a domain type, or 'p' for a pseudo type.
* typtype is 'b' for a base type, 'c' for a composite type (e.g.,
* a table's rowtype), 'd' for a domain type, 'e' for an enum type,
* or 'p' for a pseudo-type. (Use the TYPTYPE macros below.)
*
* 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_ ));
#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
*
@ -560,11 +566,24 @@ DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p t \054 0 0 opaque_in opaque
#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_ ));
#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");
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_ ));
/*
* macros
*/
#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

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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 DefineDomain(CreateDomainStmt *stmt);
extern void RemoveDomain(List *names, DropBehavior behavior, bool missing_ok);
extern void DefineEnum(CreateEnumStmt *stmt);
extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist);
extern void AlterDomainDefault(List *names, Node *defaultRaw);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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_ReassignOwnedStmt,
T_CompositeTypeStmt,
T_CreateEnumStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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 */
} 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

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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 int16 typeLen(Type t);
extern bool typeByVal(Type t);
extern char typeTypType(Type t);
extern char *typeTypeName(Type t);
extern Oid typeTypeRelid(Type typ);
extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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_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 */
extern Datum int2in(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_recv(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_out(PG_FUNCTION_ARGS);
extern Datum trigger_in(PG_FUNCTION_ARGS);

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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 char get_typtype(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_element_type(Oid typid);
extern Oid get_array_type(Oid typid);

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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 CONVOID 18
#define DATABASEOID 19
#define INDEXRELID 20
#define LANGNAME 21
#define LANGOID 22
#define NAMESPACENAME 23
#define NAMESPACEOID 24
#define OPERNAMENSP 25
#define OPEROID 26
#define OPFAMILYAMNAMENSP 27
#define OPFAMILYOID 28
#define PROCNAMEARGSNSP 29
#define PROCOID 30
#define RELNAMENSP 31
#define RELOID 32
#define RULERELNAME 33
#define STATRELATT 34
#define TYPENAMENSP 35
#define TYPEOID 36
#define ENUMOID 20
#define ENUMTYPOIDNAME 21
#define INDEXRELID 22
#define LANGNAME 23
#define LANGOID 24
#define NAMESPACENAME 25
#define NAMESPACEOID 26
#define OPERNAMENSP 27
#define OPEROID 28
#define OPFAMILYAMNAMENSP 29
#define OPFAMILYOID 30
#define PROCNAMEARGSNSP 31
#define PROCOID 32
#define RELNAMENSP 33
#define RELOID 34
#define RULERELNAME 35
#define STATRELATT 36
#define TYPENAMENSP 37
#define TYPEOID 38
extern void InitCatalogCache(void);
extern void InitCatalogCachePhase2(void);

View File

@ -1,7 +1,7 @@
/**********************************************************************
* 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 */
/* except for TRIGGER, RECORD, or VOID */
if (functyptype == 'p')
if (functyptype == TYPTYPE_PSEUDO)
{
/* we assume OPAQUE with no arguments means a trigger */
if (proc->prorettype == TRIGGEROID ||
@ -862,7 +862,7 @@ plperl_validator(PG_FUNCTION_ARGS)
&argtypes, &argnames, &argmodes);
for (i = 0; i < numargs; i++)
{
if (get_typtype(argtypes[i]) == 'p')
if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
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);
/* Disallow pseudotype result, except VOID or RECORD */
if (typeStruct->typtype == 'p')
if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
if (procStruct->prorettype == VOIDOID ||
procStruct->prorettype == RECORDOID)
@ -1552,8 +1552,8 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
prodesc->result_oid = procStruct->prorettype;
prodesc->fn_retisset = procStruct->proretset;
prodesc->fn_retistuple = (typeStruct->typtype == 'c' ||
procStruct->prorettype == RECORDOID);
prodesc->fn_retistuple = (procStruct->prorettype == RECORDOID ||
typeStruct->typtype == TYPTYPE_COMPOSITE);
prodesc->fn_retisarray =
(typeStruct->typlen == -1 && typeStruct->typelem);
@ -1586,7 +1586,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype argument */
if (typeStruct->typtype == 'p')
if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
free(prodesc->proname);
free(prodesc);
@ -1596,7 +1596,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
format_type_be(procStruct->proargtypes.values[i]))));
}
if (typeStruct->typtype == 'c')
if (typeStruct->typtype == TYPTYPE_COMPOSITE)
prodesc->arg_is_rowtype[i] = true;
else
{

View File

@ -8,7 +8,7 @@
*
*
* 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);
/* Disallow pseudotype argument */
/* (note we already replaced ANYARRAY/ANYELEMENT) */
/* (note we already replaced polymorphic types) */
/* (build_variable would do this, but wrong message) */
if (argdtype->ttype != PLPGSQL_TTYPE_SCALAR &&
argdtype->ttype != PLPGSQL_TTYPE_ROW)
@ -474,7 +474,7 @@ do_compile(FunctionCallInfo fcinfo,
* the info available.
*/
rettypeid = procStruct->prorettype;
if (rettypeid == ANYARRAYOID || rettypeid == ANYELEMENTOID)
if (IsPolymorphicType(rettypeid))
{
if (forValidator)
{
@ -482,6 +482,7 @@ do_compile(FunctionCallInfo fcinfo,
rettypeid = INT4ARRAYOID;
else
rettypeid = INT4OID;
/* XXX what could we use for ANYENUM? */
}
else
{
@ -512,8 +513,8 @@ do_compile(FunctionCallInfo fcinfo,
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype result, except VOID or RECORD */
/* (note we already replaced ANYARRAY/ANYELEMENT) */
if (typeStruct->typtype == 'p')
/* (note we already replaced polymorphic types) */
if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
if (rettypeid == VOIDOID ||
rettypeid == RECORDOID)
@ -544,8 +545,7 @@ do_compile(FunctionCallInfo fcinfo,
* types, and not when the return is specified through an
* output parameter.
*/
if ((procStruct->prorettype == ANYARRAYOID ||
procStruct->prorettype == ANYELEMENTOID) &&
if (IsPolymorphicType(procStruct->prorettype) &&
num_out_args == 0)
{
(void) plpgsql_build_variable("$0", 0,
@ -1785,15 +1785,16 @@ build_datatype(HeapTuple typeTup, int32 typmod)
typ->typoid = HeapTupleGetOid(typeTup);
switch (typeStruct->typtype)
{
case 'b': /* base type */
case 'd': /* domain */
case TYPTYPE_BASE:
case TYPTYPE_DOMAIN:
case TYPTYPE_ENUM:
typ->ttype = PLPGSQL_TTYPE_SCALAR;
break;
case 'c': /* composite, ie, rowtype */
case TYPTYPE_COMPOSITE:
Assert(OidIsValid(typeStruct->typrelid));
typ->ttype = PLPGSQL_TTYPE_ROW;
break;
case 'p': /* pseudo */
case TYPTYPE_PSEUDO:
if (typ->typoid == RECORDOID)
typ->ttype = PLPGSQL_TTYPE_REC;
else
@ -2026,6 +2027,7 @@ plpgsql_resolve_polymorphic_argtypes(int numargs,
switch (argtypes[i])
{
case ANYELEMENTOID:
case ANYENUMOID: /* XXX dubious */
argtypes[i] = INT4OID;
break;
case ANYARRAYOID:

View File

@ -8,7 +8,7 @@
*
*
* 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;
/* Source must be of RECORD or composite type */
if (!(valtype == RECORDOID ||
get_typtype(valtype) == 'c'))
if (!type_is_rowtype(valtype))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
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;
/* Source must be of RECORD or composite type */
if (!(valtype == RECORDOID ||
get_typtype(valtype) == 'c'))
if (!type_is_rowtype(valtype))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot assign non-composite value to a record variable")));

View File

@ -8,7 +8,7 @@
*
*
* 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);
/* Disallow pseudotype result */
/* except for TRIGGER, RECORD, VOID, ANYARRAY, or ANYELEMENT */
if (functyptype == 'p')
/* except for TRIGGER, RECORD, VOID, or polymorphic */
if (functyptype == TYPTYPE_PSEUDO)
{
/* we assume OPAQUE with no arguments means a trigger */
if (proc->prorettype == TRIGGEROID ||
@ -156,8 +156,7 @@ plpgsql_validator(PG_FUNCTION_ARGS)
istrigger = true;
else if (proc->prorettype != RECORDOID &&
proc->prorettype != VOIDOID &&
proc->prorettype != ANYARRAYOID &&
proc->prorettype != ANYELEMENTOID)
!IsPolymorphicType(proc->prorettype))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpgsql functions cannot return type %s",
@ -165,15 +164,14 @@ plpgsql_validator(PG_FUNCTION_ARGS)
}
/* Disallow pseudotypes in arguments (either IN or OUT) */
/* except for ANYARRAY or ANYELEMENT */
/* except for polymorphic */
numargs = get_func_arg_info(tuple,
&argtypes, &argnames, &argmodes);
for (i = 0; i < numargs; i++)
{
if (get_typtype(argtypes[i]) == 'p')
if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
{
if (argtypes[i] != ANYARRAYOID &&
argtypes[i] != ANYELEMENTOID)
if (!IsPolymorphicType(argtypes[i]))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpgsql functions cannot take type %s",

View File

@ -1,7 +1,7 @@
/**********************************************************************
* 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);
/* Disallow pseudotype result, except for void */
if (rvTypeStruct->typtype == 'p' &&
if (rvTypeStruct->typtype == TYPTYPE_PSEUDO &&
procStruct->prorettype != VOIDOID)
{
if (procStruct->prorettype == TRIGGEROID)
@ -1199,7 +1199,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
format_type_be(procStruct->prorettype))));
}
if (rvTypeStruct->typtype == 'c')
if (rvTypeStruct->typtype == TYPTYPE_COMPOSITE)
{
/*
* 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);
/* Disallow pseudotype argument */
if (argTypeStruct->typtype == 'p')
if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpython functions cannot take type %s",
format_type_be(procStruct->proargtypes.values[i]))));
if (argTypeStruct->typtype != 'c')
if (argTypeStruct->typtype != TYPTYPE_COMPOSITE)
PLy_input_datum_func(&(proc->args[i]),
procStruct->proargtypes.values[i],
argTypeTup);
@ -2338,7 +2338,7 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
plan->types[i] = typeId;
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
if (typeStruct->typtype != 'c')
if (typeStruct->typtype != TYPTYPE_COMPOSITE)
PLy_output_datum_func(&plan->args[i], typeTup);
else
elog(ERROR, "tuples not handled in plpy.prepare, yet.");

View File

@ -2,7 +2,7 @@
* pltcl.c - PostgreSQL support for Tcl as
* 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);
/* Disallow pseudotype result, except VOID */
if (typeStruct->typtype == 'p')
if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
if (procStruct->prorettype == VOIDOID)
/* 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);
@ -1112,7 +1112,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid)
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype argument */
if (typeStruct->typtype == 'p')
if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
free(prodesc->proname);
free(prodesc);
@ -1122,7 +1122,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid)
format_type_be(procStruct->proargtypes.values[i]))));
}
if (typeStruct->typtype == 'c')
if (typeStruct->typtype == TYPTYPE_COMPOSITE)
{
prodesc->arg_is_rowtype[i] = true;
snprintf(buf, sizeof(buf), "__PLTcl_Tup_%d", i + 1);

View File

@ -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)

View File

@ -80,7 +80,7 @@ CREATE AGGREGATE myaggp01a(*) (SFUNC = stfnp, STYPE = int4[],
CREATE AGGREGATE myaggp02a(*) (SFUNC = stfnp, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}');
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
-- should CREATE
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,
FINALFUNC = ffp, INITCOND = '{}');
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,
INITCOND = '{}');
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))
-- -------------------------------------
-- 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,
FINALFUNC = ffp, INITCOND = '{}');
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
-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
CREATE AGGREGATE myaggp14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}');
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
-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
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,
FINALFUNC = ffp, INITCOND = '{}');
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,
INITCOND = '{}');
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
-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
CREATE AGGREGATE myaggp18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}');
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,
INITCOND = '{}');
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
-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
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,
FINALFUNC = ffnp, INITCOND = '{}');
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,
INITCOND = '{}');
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
-- should CREATE
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,
FINALFUNC = ffnp, INITCOND = '{}');
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))
-- -------------------------------------
-- 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,
FINALFUNC = ffnp, INITCOND = '{}');
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,
INITCOND = '{}');
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
-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
CREATE AGGREGATE myaggn14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}');
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,
INITCOND = '{}');
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
-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
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,
FINALFUNC = ffnp, INITCOND = '{}');
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
-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
CREATE AGGREGATE myaggn18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}');
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
-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
CREATE AGGREGATE myaggn19a(BASETYPE = anyelement, SFUNC = tf1p,

View File

@ -500,7 +500,7 @@ SELECT dup(22);
(1 row)
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);
dup
-------------------
@ -527,4 +527,4 @@ DROP FUNCTION dup(anyelement);
CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray)
AS 'select $1, array[$1,$1]' LANGUAGE sql;
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.

View File

@ -97,6 +97,7 @@ SELECT relname, relhasindex
pg_database | t
pg_depend | t
pg_description | t
pg_enum | t
pg_index | t
pg_inherits | t
pg_language | t
@ -141,7 +142,7 @@ SELECT relname, relhasindex
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
(130 rows)
(131 rows)
--
-- another sanity check: every system catalog that has OIDs should have

View File

@ -17,7 +17,7 @@ SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typnamespace = 0 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
(p1.typalign not in ('c', 's', 'i', 'd')) OR
(p1.typstorage not in ('p', 'x', 'e', 'm'));
@ -55,11 +55,11 @@ WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR
-----+---------
(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.
SELECT p1.oid, p1.typname
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
WHERE p2.typname = ('_' || p1.typname)::name AND
p2.typelem = p1.oid);

View File

@ -1,8 +1,8 @@
# ----------
# 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
test: strings

View File

@ -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.
test: boolean
test: char
@ -14,6 +14,7 @@ test: float8
test: bit
test: numeric
test: uuid
test: enum
test: strings
test: numerology
test: point

View File

@ -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);

View File

@ -20,7 +20,7 @@ SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typnamespace = 0 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
(p1.typalign not in ('c', 's', 'i', 'd')) OR
(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
(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.
SELECT p1.oid, p1.typname
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
WHERE p2.typname = ('_' || p1.typname)::name AND
p2.typelem = p1.oid);