*** doc/src/sgml/catalogs.sgml.orig Mon Mar 26 12:58:37 2007
--- doc/src/sgml/catalogs.sgml Sun Apr 1 00:04:51 2007
***************
*** 129,134 ****
--- 129,139 ----
+ pg_enum
+ enum label and value definitions
+
+
+ pg_indexadditional index information
***************
*** 1425,1435 ****
in which the source and target types are the same, if the associated
function takes more than one argument. Such entries represent
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.
--- 1430,1436 ----
in which the source and target types are the same, if the associated
function takes more than one argument. Such entries represent
length coercion functions> that coerce values of the type
! to be legal for a particular type modifier value.
***************
*** 2413,2418 ****
--- 2414,2468 ----
+
+ pg_enum
+
+
+ pg_enum
+
+
+
+ The pg_enum 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 pg_enum. 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.
+
+
+
+ pg_enum> Columns
+
+
+
+
+ Name
+ Type
+ References
+ Description
+
+
+
+
+
+ enumtypid
+ oid
+ pg_type.oid
+ The OID of the pg_type> entry owning this enum value
+
+
+
+ enumlabel
+ name
+
+ The textual label for this enum value
+
+
+
+
+
+
pg_index
***************
*** 4395,4405 ****
char
! typtype is b for
! a base type, c for a composite type (e.g., a
! table's row type), d for a domain, or
! p for a pseudo-type. See also
! typrelid and
typbasetype
--- 4445,4457 ----
char
! typtype is
! b for a base type,
! c for a composite type (e.g., a table's row type),
! d for a domain,
! e for an enum type,
! or p for a pseudo-type.
! See also typrelid and
typbasetype
*** doc/src/sgml/datatype.sgml.orig Wed Mar 14 13:38:05 2007
--- doc/src/sgml/datatype.sgml Sun Apr 1 19:02:18 2007
***************
*** 2424,2429 ****
--- 2424,2584 ----
+
+ Enumerated Types
+
+
+ data type
+ enumerated (enum)
+
+
+
+ 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 enum
+ 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.
+
+
+
+ Declaration of Enumerated Types
+
+
+ Enum types are created using the command,
+ for example:
+
+
+ CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
+
+
+ Once created, the enum type can be used in table and function
+ definitions much like any other type:
+
+
+
+ Basic Enum Usage
+
+ 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)
+
+
+
+
+
+ Ordering
+
+
+ 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:
+
+
+
+ Enum Ordering
+
+ 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)
+
+
+
+
+
+ Type Safety
+
+
+ Enumerated types are completely separate data types and may not
+ be compared with each other.
+
+
+
+ Lack of Casting
+
+ 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
+
+
+
+
+ If you really need to do something like that, you can either
+ write a custom operator or add explicit casts to your query:
+
+
+
+ Comparing Different Enums by Casting to Text
+
+ SELECT person.name, holidays.num_weeks FROM person, holidays
+ WHERE person.current_mood::text = holidays.happiness::text;
+ name | num_weeks
+ ------+-----------
+ Moe | 4
+ (1 row)
+
+
+
+
+
+
+ Implementation Details
+
+
+ An enum value occupies four bytes on disk. The length of an enum
+ value's textual label is limited by the NAMEDATALEN
+ setting compiled into PostgreSQL; in standard
+ builds this means at most 63 bytes.
+
+
+
+ Enum labels are case sensitive, so
+ 'happy' is not the same as 'HAPPY'.
+ Spaces in the labels are significant, too.
+
+
+
+
+
Geometric Types
***************
*** 3279,3284 ****
--- 3434,3443 ----
+ anyenum
+
+
+ void
***************
*** 3344,3349 ****
--- 3503,3515 ----
+ anyenum>
+ Indicates that a function accepts any enum data type
+ (see and
+ ).
+
+
+ cstring>Indicates that a function accepts or returns a null-terminated C string.
***************
*** 3395,3402 ****
languages all forbid use of a pseudo-type as argument type, and allow
only void> and record> as a result type (plus
trigger> when the function is used as a trigger). Some also
! support polymorphic functions using the types anyarray> and
! anyelement>.
--- 3561,3568 ----
languages all forbid use of a pseudo-type as argument type, and allow
only void> and record> as a result type (plus
trigger> when the function is used as a trigger). Some also
! support polymorphic functions using the types anyarray>,
! anyelement> and anyenum>.
*** doc/src/sgml/extend.sgml.orig Wed Jan 31 18:54:08 2007
--- doc/src/sgml/extend.sgml Sun Apr 1 19:09:01 2007
***************
*** 193,201 ****
! Two pseudo-types of special interest are anyelement> and
! anyarray>, which are collectively called polymorphic
! types>. Any function declared using these types is said to be
a 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
--- 193,202 ----
! Three pseudo-types of special interest are anyelement>,
! anyarray>, and anyenum>,
! which are collectively called polymorphic types>.
! Any function declared using these types is said to be
a 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,220 ****
--- 216,224 ----
anyelement, the actual array type in the
anyarray positions must be an array whose elements are
the same type appearing in the anyelement positions.
+ anyenum> is treated exactly the same as anyelement>,
+ but adds the additional constraint that the actual type must
+ be an enum type.
***************
*** 234,240 ****
implements subscripting as 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.
--- 238,246 ----
implements subscripting as 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. Another example
! is that a function declared as f(anyarray) returns anyenum>
! will only accept arrays of enum types.
*** doc/src/sgml/func.sgml.orig Sun Apr 1 15:52:00 2007
--- doc/src/sgml/func.sgml Sun Apr 1 19:25:23 2007
***************
*** 6646,6651 ****
--- 6646,6732 ----
+
+ Enum Support Functions
+
+
+ For enum types (described in ),
+ there are several functions that allow cleaner programming without
+ hard-coding particular values of an enum type.
+ These are listed in . The examples
+ assume an enum type created as:
+
+
+ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
+
+
+
+
+
+ Enum Support Functions
+
+
+
+ Function
+ Description
+ Example
+ Example Result
+
+
+
+
+ enum_first(anyenum)
+ Returns the first value of the input enum type
+ enum_first(null::rainbow)
+ red
+
+
+ enum_last(anyenum)
+ Returns the last value of the input enum type
+ enum_last(null::rainbow)
+ purple
+
+
+ enum_range(anyenum)
+ Returns all values of the input enum type in an ordered array
+ enum_range(null::rainbow)
+ {red,orange,yellow,green,blue,purple}
+
+
+ enum_range(anyenum, anyenum)
+
+ 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.
+
+ enum_range('orange'::rainbow, 'green'::rainbow)
+ {orange,yellow,green}
+
+
+ enum_range(NULL, 'green'::rainbow)
+ {red,orange,yellow,green}
+
+
+ enum_range('orange'::rainbow, NULL)
+ {orange,yellow,green,blue,purple}
+
+
+
+
+
+
+ Notice that except for the two-argument form of 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.
+
+
+
Geometric Functions and Operators
*** doc/src/sgml/plpgsql.sgml.orig Thu Feb 1 14:48:54 2007
--- doc/src/sgml/plpgsql.sgml Sun Apr 1 19:43:13 2007
***************
*** 210,216 ****
PL/pgSQL> functions can also be declared to accept
and return the polymorphic types
! anyelement and anyarray. The actual
data types handled by a polymorphic function can vary from call to
call, as discussed in .
An example is shown in .
--- 210,217 ----
PL/pgSQL> functions can also be declared to accept
and return the polymorphic types
! anyelement, anyarray, and anyenum>.
! The actual
data types handled by a polymorphic function can vary from call to
call, as discussed in .
An example is shown in .
***************
*** 698,705 ****
When the return type of a PL/pgSQL
! function is declared as a polymorphic type (anyelement
! or anyarray), a special parameter $0
is created. Its data type is the actual return type of the function,
as deduced from the actual input types (see ).
--- 699,707 ----
When the return type of a PL/pgSQL
! function is declared as a polymorphic type (anyelement,
! anyarray, or anyenum>),
! a special parameter $0
is created. Its data type is the actual return type of the function,
as deduced from the actual input types (see ).
***************
*** 726,732 ****
The same effect can be had by declaring one or more output parameters as
! anyelement or anyarray. In this case the
special $0 parameter is not used; the output
parameters themselves serve the same purpose. For example:
--- 728,734 ----
The same effect can be had by declaring one or more output parameters as
! polymorphic types. In this case the
special $0 parameter is not used; the output
parameters themselves serve the same purpose. For example:
*** doc/src/sgml/ref/create_type.sgml.orig Thu Feb 1 14:48:58 2007
--- doc/src/sgml/ref/create_type.sgml Sun Apr 1 00:04:48 2007
***************
*** 23,28 ****
--- 23,31 ----
CREATE TYPE name AS
( attribute_namedata_type [, ... ] )
+ CREATE TYPE name AS ENUM
+ ( 'label' [, ... ] )
+
CREATE TYPE name (
INPUT = input_function,
OUTPUT = output_function
***************
*** 78,87 ****
Base Types
! The second form of CREATE TYPE 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 CREATE FUNCTION) before
--- 81,102 ----
+ Enumerated Types
+
+
+ The second form of CREATE TYPE creates an enumerated
+ (enum) type, as described in .
+ Enum types take a list of one or more quoted labels, each of which
+ must be less than NAMEDATALEN bytes long (64 in a standard
+ PostgreSQL build).
+
+
+
+ Base Types
! The third form of CREATE TYPE 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 CREATE FUNCTION) before
***************
*** 297,303 ****
Array Types
! Whenever a user-defined base data type is created,
PostgreSQL automatically creates an
associated array type, whose name consists of the base type's
name prepended with an underscore. The parser understands this
--- 312,318 ----
Array Types
! Whenever a user-defined base or enum data type is created,
PostgreSQL automatically creates an
associated array type, whose name consists of the base type's
name prepended with an underscore. The parser understands this
***************
*** 364,369 ****
--- 379,394 ----
+ label
+
+
+ A string literal representing the textual label associated with
+ one value of an enum type.
+
+
+
+
+ input_function
***************
*** 564,569 ****
--- 589,608 ----
CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$
SELECT fooid, fooname FROM foo
$$ LANGUAGE SQL;
+
+
+
+
+ This example creates an enumerated type and uses it in
+ a table definition:
+
+ CREATE TYPE bug_status AS ENUM ('new', 'open', 'closed');
+
+ CREATE TABLE bug (
+ serial id,
+ description text,
+ status bug_status
+ );
*** doc/src/sgml/xfunc.sgml.orig Tue Feb 27 18:48:06 2007
--- doc/src/sgml/xfunc.sgml Sun Apr 1 19:43:14 2007
***************
*** 717,724 ****
SQL functions can be declared to accept and
! return the polymorphic types anyelement and
! anyarray. See for a more detailed
explanation of polymorphic functions. Here is a polymorphic
function make_array that builds up an array
--- 717,724 ----
SQL functions can be declared to accept and
! return the polymorphic types anyelement,
! anyarray, and anyenum. See for a more detailed
explanation of polymorphic functions. Here is a polymorphic
function make_array that builds up an array
***************
*** 746,752 ****
Without the typecast, you will get errors like this:
! ERROR: could not determine "anyarray"/"anyelement" type because input has type "unknown"
--- 746,752 ----
Without the typecast, you will get errors like this:
! ERROR: could not determine polymorphic type because input has type "unknown"
***************
*** 769,775 ****
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.
--- 769,775 ----
SELECT 1;
$$ LANGUAGE SQL;
ERROR: cannot determine result data type
! DETAIL: A function returning a polymorphic type must have at least one polymorphic argument.
***************
*** 2831,2837 ****
C-language functions can be declared to accept and
return the polymorphic types
! anyelement and anyarray.
See for a more detailed explanation
of polymorphic functions. When function arguments or return types
are defined as polymorphic types, the function author cannot know
--- 2831,2837 ----
C-language functions can be declared to accept and
return the polymorphic types
! anyelement, anyarray, and anyenum.
See for a more detailed explanation
of polymorphic functions. When function arguments or return types
are defined as polymorphic types, the function author cannot know
*** src/backend/access/hash/hashfunc.c.orig Fri Jan 5 18:01:44 2007
--- src/backend/access/hash/hashfunc.c Sun Apr 1 00:05:03 2007
***************
*** 73,78 ****
--- 73,84 ----
}
Datum
+ hashenum(PG_FUNCTION_ARGS)
+ {
+ PG_RETURN_UINT32(~((uint32) PG_GETARG_OID(0)));
+ }
+
+ Datum
hashfloat4(PG_FUNCTION_ARGS)
{
float4 key = PG_GETARG_FLOAT4(0);
*** src/backend/catalog/Makefile.orig Sat Feb 10 13:09:49 2007
--- src/backend/catalog/Makefile Sun Apr 1 00:05:21 2007
***************
*** 11,17 ****
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_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
pg_type.o toasting.o
--- 11,17 ----
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_enum.o \
pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
pg_type.o toasting.o
***************
*** 32,38 ****
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_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 \
--- 32,38 ----
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_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 \
*** src/backend/catalog/heap.c.orig Tue Feb 13 20:58:56 2007
--- src/backend/catalog/heap.c Sun Apr 1 00:05:22 2007
***************
*** 412,418 ****
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" has type \"unknown\"", attname),
errdetail("Proceeding with relation creation anyway.")));
! else if (att_typtype == 'p')
{
/* Special hack for pg_statistic: allow ANYARRAY during initdb */
if (atttypid != ANYARRAYOID || IsUnderPostmaster)
--- 412,418 ----
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" has type \"unknown\"", attname),
errdetail("Proceeding with relation creation anyway.")));
! else if (att_typtype == TYPTYPE_PSEUDO)
{
/* Special hack for pg_statistic: allow ANYARRAY during initdb */
if (atttypid != ANYARRAYOID || IsUnderPostmaster)
***************
*** 718,724 ****
new_rel_oid, /* relation oid */
new_rel_kind, /* relation kind */
-1, /* internal size (varlena) */
! 'c', /* type-type (complex) */
',', /* default array delimiter */
F_RECORD_IN, /* input procedure */
F_RECORD_OUT, /* output procedure */
--- 718,724 ----
new_rel_oid, /* relation oid */
new_rel_kind, /* relation kind */
-1, /* internal size (varlena) */
! TYPTYPE_COMPOSITE, /* type-type (composite) */
',', /* default array delimiter */
F_RECORD_IN, /* input procedure */
F_RECORD_OUT, /* output procedure */
*** src/backend/catalog/pg_aggregate.c.orig Sun Jan 21 20:35:20 2007
--- src/backend/catalog/pg_aggregate.c Sun Apr 1 19:41:31 2007
***************
*** 80,87 ****
hasPolyArg = false;
for (i = 0; i < numArgs; i++)
{
! if (aggArgTypes[i] == ANYARRAYOID ||
! aggArgTypes[i] == ANYELEMENTOID)
{
hasPolyArg = true;
break;
--- 80,86 ----
hasPolyArg = false;
for (i = 0; i < numArgs; i++)
{
! if (IsPolymorphicType(aggArgTypes[i]))
{
hasPolyArg = true;
break;
***************
*** 92,103 ****
* 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))
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.")));
/* find the transfn */
nargs_transfn = numArgs + 1;
--- 91,101 ----
* If transtype is polymorphic, must have polymorphic argument also; else
* we will have no way to deduce the actual transtype.
*/
! if (IsPolymorphicType(aggTransType) && !hasPolyArg)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("cannot determine transition data type"),
! errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
/* find the transfn */
nargs_transfn = numArgs + 1;
***************
*** 170,182 ****
* that itself violates the rule against polymorphic result with no
* polymorphic input.)
*/
! if (!hasPolyArg &&
! (finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID))
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.")));
/* handle sortop, if supplied */
if (aggsortopName)
--- 168,179 ----
* that itself violates the rule against polymorphic result with no
* polymorphic input.)
*/
! if (IsPolymorphicType(finaltype) && !hasPolyArg)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot determine result data type"),
! errdetail("An aggregate returning a polymorphic type "
! "must have at least one polymorphic argument.")));
/* handle sortop, if supplied */
if (aggsortopName)
***************
*** 329,336 ****
*/
for (i = 0; i < nargs; i++)
{
! if (input_types[i] != ANYARRAYOID &&
! input_types[i] != ANYELEMENTOID)
{
allPolyArgs = false;
break;
--- 326,332 ----
*/
for (i = 0; i < nargs; i++)
{
! if (!IsPolymorphicType(input_types[i]))
{
allPolyArgs = false;
break;
***************
*** 351,358 ****
*/
for (i = 0; i < nargs; i++)
{
! if (true_oid_array[i] != ANYARRAYOID &&
! true_oid_array[i] != ANYELEMENTOID &&
!IsBinaryCoercible(input_types[i], true_oid_array[i]))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
--- 347,353 ----
*/
for (i = 0; i < nargs; i++)
{
! if (!IsPolymorphicType(true_oid_array[i]) &&
!IsBinaryCoercible(input_types[i], true_oid_array[i]))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
*** src/backend/catalog/pg_enum.c.orig Sun Apr 1 00:05:18 2007
--- src/backend/catalog/pg_enum.c Sun Apr 1 23:30:37 2007
***************
*** 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$
+ *
+ *-------------------------------------------------------------------------
+ */
+ #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;
+ }
*** src/backend/catalog/pg_proc.c.orig Sun Jan 21 20:35:20 2007
--- src/backend/catalog/pg_proc.c Sun Apr 1 19:41:31 2007
***************
*** 137,145 ****
}
/*
! * 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.
*/
for (i = 0; i < parameterCount; i++)
{
--- 137,145 ----
}
/*
! * 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,152 ****
--- 147,153 ----
{
case ANYARRAYOID:
case ANYELEMENTOID:
+ case ANYENUMOID:
genericInParam = true;
break;
case INTERNALOID:
***************
*** 169,174 ****
--- 170,176 ----
{
case ANYARRAYOID:
case ANYELEMENTOID:
+ case ANYENUMOID:
genericOutParam = true;
break;
case INTERNALOID:
***************
*** 178,189 ****
}
}
! if ((returnType == ANYARRAYOID || returnType == ANYELEMENTOID ||
! 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.")));
if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
ereport(ERROR,
--- 180,191 ----
}
}
! if ((IsPolymorphicType(returnType) || genericOutParam)
! && !genericInParam)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("cannot determine result data type"),
! errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));
if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
ereport(ERROR,
***************
*** 533,558 ****
proc = (Form_pg_proc) GETSTRUCT(tuple);
/* Disallow pseudotype result */
! /* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */
! if (get_typtype(proc->prorettype) == 'p' &&
proc->prorettype != RECORDOID &&
proc->prorettype != VOIDOID &&
! proc->prorettype != ANYARRAYOID &&
! proc->prorettype != ANYELEMENTOID)
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 */
haspolyarg = false;
for (i = 0; i < proc->pronargs; i++)
{
! if (get_typtype(proc->proargtypes.values[i]) == 'p')
{
! if (proc->proargtypes.values[i] == ANYARRAYOID ||
! proc->proargtypes.values[i] == ANYELEMENTOID)
haspolyarg = true;
else
ereport(ERROR,
--- 535,558 ----
proc = (Form_pg_proc) GETSTRUCT(tuple);
/* Disallow pseudotype result */
! /* except for RECORD, VOID, or polymorphic */
! if (get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
proc->prorettype != RECORDOID &&
proc->prorettype != VOIDOID &&
! !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 polymorphic */
haspolyarg = false;
for (i = 0; i < proc->pronargs; i++)
{
! if (get_typtype(proc->proargtypes.values[i]) == TYPTYPE_PSEUDO)
{
! if (IsPolymorphicType(proc->proargtypes.values[i]))
haspolyarg = true;
else
ereport(ERROR,
*** src/backend/catalog/pg_type.c.orig Fri Jan 5 18:01:49 2007
--- src/backend/catalog/pg_type.c Sun Apr 1 00:05:23 2007
***************
*** 75,81 ****
*
* 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
* mistaken for a usable type.
*/
i = 0;
--- 75,81 ----
*
* 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 = TYPTYPE_PSEUDO as extra insurance that it won't be
* mistaken for a usable type.
*/
i = 0;
***************
*** 85,91 ****
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */
values[i++] = BoolGetDatum(true); /* typbyval */
! values[i++] = CharGetDatum('p'); /* typtype */
values[i++] = BoolGetDatum(false); /* typisdefined */
values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
--- 85,91 ----
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */
values[i++] = BoolGetDatum(true); /* typbyval */
! values[i++] = CharGetDatum(TYPTYPE_PSEUDO); /* typtype */
values[i++] = BoolGetDatum(false); /* typisdefined */
values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
***************
*** 159,165 ****
Oid
TypeCreate(const char *typeName,
Oid typeNamespace,
! Oid relationOid, /* only for 'c'atalog types */
char relationKind, /* ditto */
int16 internalSize,
char typeType,
--- 159,165 ----
Oid
TypeCreate(const char *typeName,
Oid typeNamespace,
! Oid relationOid, /* only for composite types */
char relationKind, /* ditto */
int16 internalSize,
char typeType,
***************
*** 243,249 ****
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(elementType); /* typelem */
values[i++] = ObjectIdGetDatum(inputProcedure); /* typinput */
values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */
--- 243,250 ----
values[i++] = CharGetDatum(typeType); /* typtype */
values[i++] = BoolGetDatum(true); /* typisdefined */
values[i++] = CharGetDatum(typDelim); /* typdelim */
! 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,383 ****
void
GenerateTypeDependencies(Oid typeNamespace,
Oid typeObjectId,
! Oid relationOid, /* only for 'c'atalog types */
char relationKind, /* ditto */
Oid owner,
Oid inputProcedure,
--- 378,384 ----
void
GenerateTypeDependencies(Oid typeNamespace,
Oid typeObjectId,
! Oid relationOid, /* only for composite types */
char relationKind, /* ditto */
Oid owner,
Oid inputProcedure,
*** src/backend/commands/aggregatecmds.c.orig Fri Jan 5 18:01:49 2007
--- src/backend/commands/aggregatecmds.c Sun Apr 1 00:05:57 2007
***************
*** 176,184 ****
* in some cases (AggregateCreate will check).
*/
transTypeId = typenameTypeId(NULL, transType);
! if (get_typtype(transTypeId) == 'p' &&
! transTypeId != ANYARRAYOID &&
! transTypeId != ANYELEMENTOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregate transition data type cannot be %s",
--- 176,183 ----
* in some cases (AggregateCreate will check).
*/
transTypeId = typenameTypeId(NULL, transType);
! if (get_typtype(transTypeId) == TYPTYPE_PSEUDO &&
! !IsPolymorphicType(transTypeId))
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregate transition data type cannot be %s",
*** src/backend/commands/functioncmds.c.orig Sun Jan 21 20:35:20 2007
--- src/backend/commands/functioncmds.c Sun Apr 1 00:05:57 2007
***************
*** 1259,1271 ****
targettypeid = typenameTypeId(NULL, stmt->targettype);
/* No pseudo-types allowed */
! if (get_typtype(sourcetypeid) == 'p')
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("source data type %s is a pseudo-type",
TypeNameToString(stmt->sourcetype))));
! if (get_typtype(targettypeid) == 'p')
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("target data type %s is a pseudo-type",
--- 1259,1271 ----
targettypeid = typenameTypeId(NULL, stmt->targettype);
/* No pseudo-types allowed */
! 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) == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("target data type %s is a pseudo-type",
*** src/backend/commands/typecmds.c.orig Tue Feb 13 20:58:57 2007
--- src/backend/commands/typecmds.c Sun Apr 1 20:05:38 2007
***************
*** 39,44 ****
--- 39,45 ----
#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,211 ****
{
elemType = typenameTypeId(NULL, defGetTypeName(defel));
/* disallow arrays of pseudotypes */
! if (get_typtype(elemType) == 'p')
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array element type cannot be %s",
--- 206,212 ----
{
elemType = typenameTypeId(NULL, defGetTypeName(defel));
/* disallow arrays of pseudotypes */
! if (get_typtype(elemType) == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array element type cannot be %s",
***************
*** 404,410 ****
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
internalLength, /* internal size */
! 'b', /* type-type (base type) */
delimiter, /* array element delimiter */
inputOid, /* input procedure */
outputOid, /* output procedure */
--- 405,411 ----
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
internalLength, /* internal size */
! TYPTYPE_BASE, /* type-type (base type) */
delimiter, /* array element delimiter */
inputOid, /* input procedure */
outputOid, /* output procedure */
***************
*** 438,444 ****
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
-1, /* internal size */
! 'b', /* type-type (base type) */
DEFAULT_TYPDELIM, /* array element delimiter */
F_ARRAY_IN, /* input procedure */
F_ARRAY_OUT, /* output procedure */
--- 439,445 ----
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 */
***************
*** 543,548 ****
--- 544,557 ----
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,631 ****
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.
*/
typtype = baseType->typtype;
! if (typtype != 'b' && typtype != 'd')
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("\"%s\" is not a valid base type for a domain",
--- 629,643 ----
basetypeMod = typenameTypeMod(NULL, stmt->typename, basetypeoid);
/*
! * 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 != 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,804 ****
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
internalLength, /* internal size */
! 'd', /* type-type (domain type) */
delimiter, /* array element delimiter */
inputProcedure, /* input procedure */
outputProcedure, /* output procedure */
--- 810,816 ----
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
internalLength, /* internal size */
! TYPTYPE_DOMAIN, /* type-type (domain type) */
delimiter, /* array element delimiter */
inputProcedure, /* input procedure */
outputProcedure, /* output procedure */
***************
*** 907,913 ****
/* Check that this is actually a domain */
typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
! if (typtype != 'd')
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a domain",
--- 919,925 ----
/* Check that this is actually a domain */
typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
! if (typtype != TYPTYPE_DOMAIN)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a domain",
***************
*** 925,930 ****
--- 937,1036 ----
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,1841 ****
Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
/* Check that this is actually a domain */
! if (typTup->typtype != 'd')
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a domain",
--- 1941,1947 ----
Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
/* Check that this is actually a domain */
! if (typTup->typtype != TYPTYPE_DOMAIN)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a domain",
***************
*** 2021,2027 ****
elog(ERROR, "cache lookup failed for type %u", typeOid);
typTup = (Form_pg_type) GETSTRUCT(tup);
! if (typTup->typtype != 'd')
{
/* Not a domain, so done */
ReleaseSysCache(tup);
--- 2127,2133 ----
elog(ERROR, "cache lookup failed for type %u", typeOid);
typTup = (Form_pg_type) GETSTRUCT(tup);
! if (typTup->typtype != TYPTYPE_DOMAIN)
{
/* Not a domain, so done */
ReleaseSysCache(tup);
***************
*** 2148,2154 ****
* 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' &&
get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
--- 2254,2260 ----
* 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 == TYPTYPE_COMPOSITE &&
get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
***************
*** 2325,2335 ****
/* Detect whether type is a composite type (but not a table rowtype) */
isCompositeType =
! (typform->typtype == 'c' &&
get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
/* Enforce not-table-type if requested */
! if (typform->typtype == 'c' && !isCompositeType && errorOnTableType)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("%s is a table's row type",
--- 2431,2442 ----
/* Detect whether type is a composite type (but not a table rowtype) */
isCompositeType =
! (typform->typtype == TYPTYPE_COMPOSITE &&
get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
/* Enforce not-table-type if requested */
! if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
! errorOnTableType)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("%s is a table's row type",
***************
*** 2376,2389 ****
else
{
/* If it's a domain, it might have constraints */
! if (typform->typtype == 'd')
AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
/*
* Update dependency on schema, if any --- a table rowtype has not got
* one.
*/
! if (typform->typtype != 'c')
if (changeDependencyFor(TypeRelationId, typeOid,
NamespaceRelationId, oldNspOid, nspOid) != 1)
elog(ERROR, "failed to change schema dependency for type %s",
--- 2483,2496 ----
else
{
/* If it's a domain, it might have constraints */
! 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 != TYPTYPE_COMPOSITE)
if (changeDependencyFor(TypeRelationId, typeOid,
NamespaceRelationId, oldNspOid, nspOid) != 1)
elog(ERROR, "failed to change schema dependency for type %s",
*** src/backend/executor/functions.c.orig Mon Mar 12 20:33:40 2007
--- src/backend/executor/functions.c Sun Apr 1 19:41:19 2007
***************
*** 182,188 ****
*/
rettype = procedureStruct->prorettype;
! if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
{
rettype = get_fn_expr_rettype(finfo);
if (rettype == InvalidOid) /* this probably should not happen */
--- 182,188 ----
*/
rettype = procedureStruct->prorettype;
! if (IsPolymorphicType(rettype))
{
rettype = get_fn_expr_rettype(finfo);
if (rettype == InvalidOid) /* this probably should not happen */
***************
*** 218,224 ****
{
Oid argtype = argOidVect[argnum];
! if (argtype == ANYARRAYOID || argtype == ANYELEMENTOID)
{
argtype = get_fn_expr_argtype(finfo, argnum);
if (argtype == InvalidOid)
--- 218,224 ----
{
Oid argtype = argOidVect[argnum];
! if (IsPolymorphicType(argtype))
{
argtype = get_fn_expr_argtype(finfo, argnum);
if (argtype == InvalidOid)
***************
*** 845,853 ****
* 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.)
*
* 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
--- 845,853 ----
* 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, 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,931 ****
fn_typtype = get_typtype(rettype);
! if (fn_typtype == 'b' || fn_typtype == 'd')
{
/*
* For base-type returns, the target list should have exactly one
--- 925,933 ----
fn_typtype = get_typtype(rettype);
! 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,954 ****
errdetail("Actual return type is %s.",
format_type_be(restype))));
}
! else if (fn_typtype == 'c' || rettype == RECORDOID)
{
/* Returns a rowtype */
TupleDesc tupdesc;
--- 950,956 ----
errdetail("Actual return type is %s.",
format_type_be(restype))));
}
! else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
{
/* Returns a rowtype */
TupleDesc tupdesc;
***************
*** 1053,1065 ****
/* Report that we are returning entire tuple result */
return true;
}
! else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
{
/* 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.")));
}
else
ereport(ERROR,
--- 1055,1067 ----
/* Report that we are returning entire tuple result */
return true;
}
! 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 a polymorphic type must have at least one polymorphic argument.")));
}
else
ereport(ERROR,
*** src/backend/executor/nodeAgg.c.orig Thu Feb 22 18:44:24 2007
--- src/backend/executor/nodeAgg.c Sun Apr 1 00:06:05 2007
***************
*** 1363,1370 ****
/*
* 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.
*/
i = 0;
foreach(lc, aggref->args)
--- 1363,1370 ----
/*
* Get actual datatypes of the inputs. These could be different from
! * the agg's declared input types, when the agg accepts ANY or
! * a polymorphic type.
*/
i = 0;
foreach(lc, aggref->args)
***************
*** 1421,1427 ****
/* resolve actual type of transition state, if polymorphic */
aggtranstype = aggform->aggtranstype;
! if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
{
/* have to fetch the agg's declared input types... */
Oid *declaredArgTypes;
--- 1421,1427 ----
/* resolve actual type of transition state, if polymorphic */
aggtranstype = aggform->aggtranstype;
! if (IsPolymorphicType(aggtranstype))
{
/* have to fetch the agg's declared input types... */
Oid *declaredArgTypes;
*** src/backend/nodes/copyfuncs.c.orig Tue Mar 27 19:21:09 2007
--- src/backend/nodes/copyfuncs.c Sun Apr 1 00:06:13 2007
***************
*** 2361,2366 ****
--- 2361,2377 ----
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)
{
***************
*** 3311,3316 ****
--- 3322,3330 ----
break;
case T_CompositeTypeStmt:
retval = _copyCompositeTypeStmt(from);
+ break;
+ case T_CreateEnumStmt:
+ retval = _copyCreateEnumStmt(from);
break;
case T_ViewStmt:
retval = _copyViewStmt(from);
*** src/backend/nodes/equalfuncs.c.orig Tue Mar 27 19:21:09 2007
--- src/backend/nodes/equalfuncs.c Sun Apr 1 00:06:13 2007
***************
*** 1187,1192 ****
--- 1187,1201 ----
}
static bool
+ _equalCreateEnumStmt(CreateEnumStmt *a, CreateEnumStmt *b)
+ {
+ COMPARE_NODE_FIELD(typename);
+ COMPARE_NODE_FIELD(vals);
+
+ return true;
+ }
+
+ static bool
_equalViewStmt(ViewStmt *a, ViewStmt *b)
{
COMPARE_NODE_FIELD(view);
***************
*** 2246,2251 ****
--- 2255,2263 ----
break;
case T_CompositeTypeStmt:
retval = _equalCompositeTypeStmt(a, b);
+ break;
+ case T_CreateEnumStmt:
+ retval = _equalCreateEnumStmt(a, b);
break;
case T_ViewStmt:
retval = _equalViewStmt(a, b);
*** src/backend/optimizer/util/clauses.c.orig Tue Mar 27 19:21:09 2007
--- src/backend/optimizer/util/clauses.c Sun Apr 1 00:06:30 2007
***************
*** 435,441 ****
ReleaseSysCache(aggTuple);
/* resolve actual type of transition state, if polymorphic */
! if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
{
/* have to fetch the agg's declared input types... */
Oid *declaredArgTypes;
--- 435,441 ----
ReleaseSysCache(aggTuple);
/* resolve actual type of transition state, if polymorphic */
! if (IsPolymorphicType(aggtranstype))
{
/* have to fetch the agg's declared input types... */
Oid *declaredArgTypes;
***************
*** 2907,2914 ****
funcform->pronargs * sizeof(Oid));
for (i = 0; i < funcform->pronargs; i++)
{
! if (argtypes[i] == ANYARRAYOID ||
! argtypes[i] == ANYELEMENTOID)
{
argtypes[i] = exprType((Node *) list_nth(args, i));
}
--- 2907,2913 ----
funcform->pronargs * sizeof(Oid));
for (i = 0; i < funcform->pronargs; i++)
{
! if (IsPolymorphicType(argtypes[i]))
{
argtypes[i] = exprType((Node *) list_nth(args, i));
}
*** src/backend/parser/gram.y.orig Mon Mar 26 12:58:39 2007
--- src/backend/parser/gram.y Sun Apr 1 00:06:40 2007
***************
*** 248,253 ****
--- 248,254 ----
TableFuncElementList opt_type_modifiers
prep_type_clause
execute_param_clause using_clause returning_clause
+ enum_val_list
%type OptTempTableName
%type into_clause create_as_target
***************
*** 383,389 ****
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
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
--- 384,390 ----
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 ENUM_P ESCAPE EXCEPT EXCLUDING
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
***************
*** 2922,2927 ****
--- 2923,2935 ----
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,2971 ****
--- 2974,2985 ----
}
;
+ enum_val_list: Sconst
+ { $$ = list_make1(makeString($1)); }
+ | enum_val_list ',' Sconst
+ { $$ = lappend($1, makeString($3)); }
+ ;
+
/*****************************************************************************
*
***************
*** 8760,8765 ****
--- 8774,8780 ----
| ENABLE_P
| ENCODING
| ENCRYPTED
+ | ENUM_P
| ESCAPE
| EXCLUDING
| EXCLUSIVE
*** src/backend/parser/keywords.c.orig Mon Mar 19 20:16:19 2007
--- src/backend/parser/keywords.c Sun Apr 1 00:06:40 2007
***************
*** 136,141 ****
--- 136,142 ----
{"encoding", ENCODING},
{"encrypted", ENCRYPTED},
{"end", END_P},
+ {"enum", ENUM_P},
{"escape", ESCAPE},
{"except", EXCEPT},
{"excluding", EXCLUDING},
*** src/backend/parser/parse_coerce.c.orig Tue Mar 27 19:21:10 2007
--- src/backend/parser/parse_coerce.c Sun Apr 1 19:50:11 2007
***************
*** 132,138 ****
}
if (targetTypeId == ANYOID ||
targetTypeId == ANYELEMENTOID ||
! (targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID))
{
/*
* Assume can_coerce_type verified that implicit coercion is okay.
--- 132,139 ----
}
if (targetTypeId == ANYOID ||
targetTypeId == ANYELEMENTOID ||
! (targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID) ||
! (targetTypeId == ANYENUMOID && inputTypeId != UNKNOWNOID))
{
/*
* Assume can_coerce_type verified that implicit coercion is okay.
***************
*** 143,149 ****
* 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.)
*
* NB: we do NOT want a RelabelType here.
*/
--- 144,151 ----
* 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.) Likewise, UNKNOWN input is no good
! * for ANYENUM.
*
* NB: we do NOT want a RelabelType here.
*/
***************
*** 406,414 ****
if (targetTypeId == ANYOID)
continue;
! /* accept if target is ANYARRAY or ANYELEMENT, for now */
! if (targetTypeId == ANYARRAYOID ||
! targetTypeId == ANYELEMENTOID)
{
have_generics = true; /* do more checking later */
continue;
--- 408,415 ----
if (targetTypeId == ANYOID)
continue;
! /* accept if target is polymorphic, for now */
! if (IsPolymorphicType(targetTypeId))
{
have_generics = true; /* do more checking later */
continue;
***************
*** 1048,1053 ****
--- 1049,1057 ----
* 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,1075 ****
--- 1074,1080 ----
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,1087 ****
{
Oid actual_type = actual_arg_types[j];
! if (declared_arg_types[j] == ANYELEMENTOID)
{
have_anyelement = true;
if (actual_type == UNKNOWNOID)
continue;
if (OidIsValid(elem_typeid) && actual_type != elem_typeid)
--- 1084,1095 ----
{
Oid actual_type = actual_arg_types[j];
! 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,1132 ****
--- 1135,1147 ----
}
}
+ if (have_anyenum)
+ {
+ /* require the element type to be an enum */
+ if (!type_is_enum(elem_typeid))
+ return false;
+ }
+
/* Looks valid */
return true;
}
***************
*** 1136,1153 ****
* 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
* 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.
*
* Rules are applied to the function's return type (possibly altering it)
! * if it is declared ANYARRAY or ANYELEMENT:
*
* 1) If return type is ANYARRAY, and any argument is ANYARRAY, use the
* argument's actual type as the function's return type.
--- 1151,1168 ----
* Make sure a polymorphic function is legally callable, and
* deduce actual argument and result types.
*
! * 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 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 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,1172 ****
--- 1182,1190 ----
* 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,1186 ****
Oid elem_typeid = InvalidOid;
Oid array_typeid = InvalidOid;
Oid array_typelem;
! bool have_anyelement = (rettype == ANYELEMENTOID);
/*
* Loop through the arguments to see if we have any that are ANYARRAY or
--- 1198,1206 ----
Oid elem_typeid = InvalidOid;
Oid array_typeid = InvalidOid;
Oid array_typelem;
! 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,1198 ****
{
Oid actual_type = actual_arg_types[j];
! if (declared_arg_types[j] == ANYELEMENTOID)
{
have_generics = have_anyelement = true;
if (actual_type == UNKNOWNOID)
{
have_unknowns = true;
--- 1210,1221 ----
{
Oid actual_type = actual_arg_types[j];
! 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,1234 ****
}
/*
! * Fast Track: if none of the arguments are ANYARRAY or ANYELEMENT, return
! * the unmodified rettype.
*/
if (!have_generics)
return rettype;
--- 1250,1257 ----
}
/*
! * 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,1280 ****
/* 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\"")));
}
/*
--- 1297,1313 ----
/* Only way to get here is if all the generic args are UNKNOWN */
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
! 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,1295 ****
if (actual_type != UNKNOWNOID)
continue;
! if (declared_arg_types[j] == ANYELEMENTOID)
declared_arg_types[j] = elem_typeid;
else if (declared_arg_types[j] == ANYARRAYOID)
{
--- 1322,1329 ----
if (actual_type != UNKNOWNOID)
continue;
! 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,1313 ****
}
}
! /* if we return ANYARRAYOID use the appropriate argument type */
if (rettype == ANYARRAYOID)
{
if (!OidIsValid(array_typeid))
--- 1341,1347 ----
}
}
! /* if we return ANYARRAY use the appropriate argument type */
if (rettype == ANYARRAYOID)
{
if (!OidIsValid(array_typeid))
***************
*** 1322,1329 ****
return array_typeid;
}
! /* if we return ANYELEMENTOID use the appropriate argument type */
! if (rettype == ANYELEMENTOID)
return elem_typeid;
/* we don't return a generic type; send back the original return type */
--- 1356,1363 ----
return array_typeid;
}
! /* 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,1339 ****
/*
* resolve_generic_type()
* Deduce an individual actual datatype on the assumption that
! * the rules for ANYARRAY/ANYELEMENT are being followed.
*
* declared_type is the declared datatype we want to resolve.
* context_actual_type is the actual input datatype to some argument
--- 1367,1373 ----
/*
* resolve_generic_type()
* Deduce an individual actual datatype on the assumption that
! * 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,1368 ****
format_type_be(context_actual_type))));
return context_actual_type;
}
! else if (context_declared_type == ANYELEMENTOID)
{
/* Use the array type corresponding to actual type */
Oid array_typeid = get_array_type(context_actual_type);
--- 1396,1403 ----
format_type_be(context_actual_type))));
return context_actual_type;
}
! 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,1381 ****
return array_typeid;
}
}
! else if (declared_type == ANYELEMENTOID)
{
if (context_declared_type == ANYARRAYOID)
{
--- 1410,1416 ----
return array_typeid;
}
}
! else if (declared_type == ANYELEMENTOID || declared_type == ANYENUMOID)
{
if (context_declared_type == ANYARRAYOID)
{
***************
*** 1389,1395 ****
format_type_be(context_actual_type))));
return array_typelem;
}
! else if (context_declared_type == ANYELEMENTOID)
{
/* Use the actual type; it doesn't matter if array or not */
return context_actual_type;
--- 1424,1431 ----
format_type_be(context_actual_type))));
return array_typelem;
}
! 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,1408 ****
}
/* 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");
return InvalidOid; /* keep compiler quiet */
}
--- 1438,1444 ----
}
/* 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 polymorphic type because context isn't polymorphic");
return InvalidOid; /* keep compiler quiet */
}
***************
*** 1502,1507 ****
--- 1538,1544 ----
case (INTERNALOID):
case (OPAQUEOID):
case (ANYELEMENTOID):
+ case (ANYENUMOID):
result = GENERIC_TYPE;
break;
***************
*** 1647,1652 ****
--- 1684,1694 ----
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,1782 ****
--- 1819,1840 ----
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,1819 ****
/* Check for a varlena array type (and not a domain) */
if (typeForm->typelem != InvalidOid &&
typeForm->typlen == -1 &&
! typeForm->typtype != 'd')
{
/* Yes, switch our attention to the element type */
typeId = typeForm->typelem;
--- 1871,1877 ----
/* Check for a varlena array type (and not a domain) */
if (typeForm->typelem != InvalidOid &&
typeForm->typlen == -1 &&
! typeForm->typtype != TYPTYPE_DOMAIN)
{
/* Yes, switch our attention to the element type */
typeId = typeForm->typelem;
*** src/backend/parser/parse_expr.c.orig Tue Mar 27 19:21:10 2007
--- src/backend/parser/parse_expr.c Sun Apr 1 00:06:41 2007
***************
*** 1627,1633 ****
break;
case RTE_FUNCTION:
toid = exprType(rte->funcexpr);
! if (toid == RECORDOID || get_typtype(toid) == 'c')
{
/* func returns composite; same as relation case */
result = (Node *) makeVar(vnum,
--- 1627,1633 ----
break;
case RTE_FUNCTION:
toid = exprType(rte->funcexpr);
! if (type_is_rowtype(toid))
{
/* func returns composite; same as relation case */
result = (Node *) makeVar(vnum,
*** src/backend/parser/parse_oper.c.orig Thu Feb 1 15:09:28 2007
--- src/backend/parser/parse_oper.c Sun Apr 1 18:52:35 2007
***************
*** 886,893 ****
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
* be used as the cast destination by make_fn_arguments)
*/
rettype = enforce_generic_type_consistency(actual_arg_types,
--- 886,893 ----
declared_arg_types[1] = opform->oprright;
/*
! * 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,925 ****
/*
* Now switch back to the array type on the right, arranging for any
! * needed cast to be applied.
*/
! 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;
--- 911,935 ----
/*
* Now switch back to the array type on the right, arranging for any
! * 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.
*/
! 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,993 ****
}
/*
! * enforce consistency with ANYARRAY and ANYELEMENT 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,
--- 996,1003 ----
}
/*
! * 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,
*** src/backend/parser/parse_type.c.orig Fri Jan 5 18:02:04 2007
--- src/backend/parser/parse_type.c Sun Apr 1 00:06:42 2007
***************
*** 398,413 ****
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)
--- 398,403 ----
*** src/backend/tcop/utility.c.orig Mon Mar 26 12:58:39 2007
--- src/backend/tcop/utility.c Sun Apr 1 00:07:00 2007
***************
*** 337,342 ****
--- 337,343 ----
case T_CreateTableSpaceStmt:
case T_CreateTrigStmt:
case T_CompositeTypeStmt:
+ case T_CreateEnumStmt:
case T_ViewStmt:
case T_DropCastStmt:
case T_DropStmt:
***************
*** 779,784 ****
--- 780,789 ----
}
break;
+ case T_CreateEnumStmt: /* CREATE TYPE (enum) */
+ DefineEnum((CreateEnumStmt *) parsetree);
+ break;
+
case T_ViewStmt: /* CREATE VIEW */
DefineView((ViewStmt *) parsetree, queryString);
break;
***************
*** 1640,1645 ****
--- 1645,1654 ----
tag = "CREATE TYPE";
break;
+ case T_CreateEnumStmt:
+ tag = "CREATE TYPE";
+ break;
+
case T_ViewStmt:
tag = "CREATE VIEW";
break;
***************
*** 2072,2077 ****
--- 2081,2090 ----
break;
case T_CompositeTypeStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
+ case T_CreateEnumStmt:
lev = LOGSTMT_DDL;
break;
*** src/backend/utils/adt/Makefile.orig Wed Jan 31 10:04:08 2007
--- src/backend/utils/adt/Makefile Sun Apr 1 00:42:28 2007
***************
*** 17,23 ****
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 \
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 \
--- 17,23 ----
OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
cash.o char.o date.o datetime.o datum.o domains.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 \
*** src/backend/utils/adt/enum.c.orig Sun Apr 1 00:07:11 2007
--- src/backend/utils/adt/enum.c Sun Apr 1 23:38:46 2007
***************
*** 0 ****
--- 1,409 ----
+ /*-------------------------------------------------------------------------
+ *
+ * enum.c
+ * I/O functions, operators, aggregates etc for enum types
+ *
+ * Copyright (c) 2006-2007, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL$
+ *
+ *-------------------------------------------------------------------------
+ */
+ #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;
+ }
*** src/backend/utils/adt/format_type.c.orig Fri Jan 5 18:02:17 2007
--- src/backend/utils/adt/format_type.c Sun Apr 1 00:07:14 2007
***************
*** 148,154 ****
if (array_base_type != InvalidOid &&
typeform->typstorage != 'p' &&
! typeform->typtype != 'd')
{
/* Switch our attention to the array element type */
ReleaseSysCache(tuple);
--- 148,154 ----
if (array_base_type != InvalidOid &&
typeform->typstorage != 'p' &&
! typeform->typtype != TYPTYPE_DOMAIN)
{
/* Switch our attention to the array element type */
ReleaseSysCache(tuple);
*** src/backend/utils/adt/pseudotypes.c.orig Fri Jan 5 18:02:19 2007
--- src/backend/utils/adt/pseudotypes.c Sun Apr 1 00:07:14 2007
***************
*** 164,169 ****
--- 164,194 ----
/*
+ * 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.
*
* We allow this so that PL functions can return VOID without any special
*** src/backend/utils/adt/xml.c.orig Sun Apr 1 15:54:23 2007
--- src/backend/utils/adt/xml.c Sun Apr 1 15:54:49 2007
***************
*** 2648,2654 ****
Form_pg_type typtuple = (Form_pg_type) GETSTRUCT(tuple);
appendStringInfoString(&result,
! map_multipart_sql_identifier_to_xml_name((typtuple->typtype == 'd') ? "Domain" : "UDT",
get_database_name(MyDatabaseId),
get_namespace_name(typtuple->typnamespace),
NameStr(typtuple->typname)));
--- 2648,2654 ----
Form_pg_type typtuple = (Form_pg_type) GETSTRUCT(tuple);
appendStringInfoString(&result,
! 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,2883 ****
break;
default:
! if (get_typtype(typeoid) == 'd')
{
Oid base_typeoid;
int32 base_typmod = -1;
--- 2877,2883 ----
break;
default:
! if (get_typtype(typeoid) == TYPTYPE_DOMAIN)
{
Oid base_typeoid;
int32 base_typmod = -1;
*** src/backend/utils/cache/lsyscache.c.orig Mon Mar 19 12:30:31 2007
--- src/backend/utils/cache/lsyscache.c Sun Apr 1 16:37:43 2007
***************
*** 1770,1776 ****
* 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))
return typeStruct->typelem;
else
return HeapTupleGetOid(typeTuple);
--- 1770,1776 ----
* 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 == TYPTYPE_BASE && OidIsValid(typeStruct->typelem))
return typeStruct->typelem;
else
return HeapTupleGetOid(typeTuple);
***************
*** 2022,2028 ****
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for type %u", typid);
typTup = (Form_pg_type) GETSTRUCT(tup);
! if (typTup->typtype != 'd')
{
/* Not a domain, so done */
ReleaseSysCache(tup);
--- 2022,2028 ----
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for type %u", typid);
typTup = (Form_pg_type) GETSTRUCT(tup);
! if (typTup->typtype != TYPTYPE_DOMAIN)
{
/* Not a domain, so done */
ReleaseSysCache(tup);
***************
*** 2128,2134 ****
bool
type_is_rowtype(Oid typid)
{
! return (typid == RECORDOID || get_typtype(typid) == 'c');
}
/*
--- 2128,2144 ----
bool
type_is_rowtype(Oid typid)
{
! 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);
}
/*
*** src/backend/utils/cache/syscache.c.orig Tue Feb 13 20:58:57 2007
--- src/backend/utils/cache/syscache.c Sun Apr 1 00:28:39 2007
***************
*** 31,36 ****
--- 31,37 ----
#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"
***************
*** 334,339 ****
--- 335,364 ----
0
},
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,
*** src/backend/utils/cache/typcache.c.orig Fri Jan 5 18:02:22 2007
--- src/backend/utils/cache/typcache.c Sun Apr 1 00:07:24 2007
***************
*** 275,281 ****
*/
if ((flags & TYPECACHE_TUPDESC) &&
typentry->tupDesc == NULL &&
! typentry->typtype == 'c')
{
Relation rel;
--- 275,281 ----
*/
if ((flags & TYPECACHE_TUPDESC) &&
typentry->tupDesc == NULL &&
! typentry->typtype == TYPTYPE_COMPOSITE)
{
Relation rel;
*** src/backend/utils/fmgr/funcapi.c.orig Thu Feb 1 15:09:34 2007
--- src/backend/utils/fmgr/funcapi.c Sun Apr 1 18:52:23 2007
***************
*** 193,200 ****
* 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.
*
* This function is relatively expensive --- in a function returning set,
* try to call it only the first time through.
--- 193,200 ----
* 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, 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,344 ****
/*
* If scalar polymorphic result, try to resolve it.
*/
! if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
{
Oid newrettype = exprType(call_expr);
--- 338,344 ----
/*
* If scalar polymorphic result, try to resolve it.
*/
! if (IsPolymorphicType(rettype))
{
Oid newrettype = exprType(call_expr);
***************
*** 389,396 ****
/*
* 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
* all types, FALSE if not.
*/
static bool
--- 389,396 ----
/*
* Given the result tuple descriptor for a function with OUT parameters,
! * 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,406 ****
--- 401,407 ----
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,421 ****
--- 417,426 ----
case ANYARRAYOID:
have_anyarray_result = true;
break;
+ case ANYENUMOID:
+ have_anyelement_result = true;
+ have_anyenum = true;
+ break;
default:
break;
}
***************
*** 435,440 ****
--- 440,446 ----
switch (declared_args->values[i])
{
case ANYELEMENTOID:
+ case ANYENUMOID:
if (!OidIsValid(anyelement_type))
anyelement_type = get_call_expr_argtype(call_expr, i);
break;
***************
*** 461,472 ****
--- 467,483 ----
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,497 ****
/*
* 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
* all types, FALSE if not. This is the same logic as
* resolve_polymorphic_tupdesc, but with a different argument representation.
*
--- 501,508 ----
/*
* Given the declared argument types and modes for a function,
! * 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,522 ****
--- 528,534 ----
switch (argtypes[i])
{
case ANYELEMENTOID:
+ case ANYENUMOID:
if (argmode == PROARGMODE_OUT)
have_anyelement_result = true;
else
***************
*** 571,582 ****
--- 583,597 ----
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,614 ****
{
switch (get_typtype(typid))
{
! case 'c':
return TYPEFUNC_COMPOSITE;
! case 'b':
! case 'd':
return TYPEFUNC_SCALAR;
! case 'p':
if (typid == RECORDOID)
return TYPEFUNC_RECORD;
--- 618,630 ----
{
switch (get_typtype(typid))
{
! case TYPTYPE_COMPOSITE:
return TYPEFUNC_COMPOSITE;
! case TYPTYPE_BASE:
! case TYPTYPE_DOMAIN:
! case TYPTYPE_ENUM:
return TYPEFUNC_SCALAR;
! case TYPTYPE_PSEUDO:
if (typid == RECORDOID)
return TYPEFUNC_RECORD;
***************
*** 840,846 ****
* 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;
* that is deliberate.
*/
TupleDesc
--- 856,862 ----
* 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 polymorphic types;
* that is deliberate.
*/
TupleDesc
*** src/bin/pg_dump/pg_dump.c.orig Mon Mar 26 12:58:39 2007
--- src/bin/pg_dump/pg_dump.c Sun Apr 1 00:07:51 2007
***************
*** 137,142 ****
--- 137,143 ----
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,2091 ****
*/
tinfo[i].nDomChecks = 0;
tinfo[i].domChecks = NULL;
! if (tinfo[i].dobj.dump && tinfo[i].typtype == 'd')
getDomainConstraints(&(tinfo[i]));
/*
--- 2086,2092 ----
*/
tinfo[i].nDomChecks = 0;
tinfo[i].domChecks = NULL;
! if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_DOMAIN)
getDomainConstraints(&(tinfo[i]));
/*
***************
*** 2097,2103 ****
* 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')
{
stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
stinfo->dobj.objType = DO_SHELL_TYPE;
--- 2098,2104 ----
* 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 == TYPTYPE_BASE)
{
stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
stinfo->dobj.objType = DO_SHELL_TYPE;
***************
*** 5119,5130 ****
return;
/* Dump out in proper style */
! if (tinfo->typtype == 'b')
dumpBaseType(fout, tinfo);
! else if (tinfo->typtype == 'd')
dumpDomain(fout, tinfo);
! else if (tinfo->typtype == 'c')
dumpCompositeType(fout, tinfo);
}
/*
--- 5120,5210 ----
return;
/* Dump out in proper style */
! if (tinfo->typtype == TYPTYPE_BASE)
dumpBaseType(fout, tinfo);
! else if (tinfo->typtype == TYPTYPE_DOMAIN)
dumpDomain(fout, tinfo);
! 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);
}
/*
*** src/include/access/hash.h.orig Mon Jan 29 21:27:50 2007
--- src/include/access/hash.h Sun Apr 1 00:04:10 2007
***************
*** 258,263 ****
--- 258,264 ----
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);
*** src/include/catalog/catversion.h.orig Sun Apr 1 15:56:24 2007
--- src/include/catalog/catversion.h Sun Apr 1 15:56:47 2007
***************
*** 53,58 ****
*/
/* yyyymmddN */
! #define CATALOG_VERSION_NO 200704011
#endif
--- 53,58 ----
*/
/* yyyymmddN */
! #define CATALOG_VERSION_NO 200704012
#endif
*** src/include/catalog/indexing.h.orig Tue Feb 13 20:58:58 2007
--- src/include/catalog/indexing.h Sun Apr 1 00:02:00 2007
***************
*** 146,151 ****
--- 146,156 ----
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
*** src/include/catalog/pg_aggregate.h.orig Sun Feb 18 18:38:37 2007
--- src/include/catalog/pg_aggregate.h Sun Apr 1 00:02:01 2007
***************
*** 118,123 ****
--- 118,124 ----
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,144 ****
--- 140,146 ----
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" ));
*** src/include/catalog/pg_amop.h.orig Mon Feb 5 21:59:12 2007
--- src/include/catalog/pg_amop.h Sun Apr 1 00:02:01 2007
***************
*** 636,639 ****
--- 636,653 ----
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 */
*** src/include/catalog/pg_amproc.h.orig Wed Jan 31 10:04:16 2007
--- src/include/catalog/pg_amproc.h Sun Apr 1 00:02:01 2007
***************
*** 128,133 ****
--- 128,134 ----
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,167 ****
--- 163,169 ----
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 */
*** src/include/catalog/pg_cast.h.orig Sun Feb 4 15:03:07 2007
--- src/include/catalog/pg_cast.h Sun Apr 1 00:02:02 2007
***************
*** 403,406 ****
--- 403,412 ----
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 */
*** src/include/catalog/pg_enum.h.orig Sun Apr 1 00:02:20 2007
--- src/include/catalog/pg_enum.h Sun Apr 1 23:32:04 2007
***************
*** 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$
+ *
+ * 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 */
*** src/include/catalog/pg_opclass.h.orig Wed Jan 31 10:04:16 2007
--- src/include/catalog/pg_opclass.h Sun Apr 1 00:02:02 2007
***************
*** 200,206 ****
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 ));
#endif /* PG_OPCLASS_H */
--- 200,208 ----
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 enum_ops PGNSP PGUID 3522 3500 t 0 ));
! DATA(insert ( 405 enum_ops PGNSP PGUID 3523 3500 t 0 ));
#endif /* PG_OPCLASS_H */
*** src/include/catalog/pg_operator.h.orig Mon Feb 5 21:59:12 2007
--- src/include/catalog/pg_operator.h Sun Apr 1 00:02:06 2007
***************
*** 903,908 ****
--- 903,916 ----
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
*** src/include/catalog/pg_opfamily.h.orig Wed Jan 31 10:04:16 2007
--- src/include/catalog/pg_opfamily.h Sun Apr 1 00:02:06 2007
***************
*** 136,141 ****
--- 136,143 ----
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 */
*** src/include/catalog/pg_proc.h.orig Sun Apr 1 15:58:53 2007
--- src/include/catalog/pg_proc.h Sun Apr 1 17:35:44 2007
***************
*** 4149,4154 ****
--- 4149,4194 ----
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,
*** src/include/catalog/pg_type.h.orig Wed Jan 31 10:04:17 2007
--- src/include/catalog/pg_type.h Sun Apr 1 00:23:54 2007
***************
*** 66,73 ****
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.
*
* If typtype is 'c', typrelid is the OID of the class' entry in pg_class.
*/
--- 66,74 ----
bool typbyval;
/*
! * 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,536 ****
--- 532,542 ----
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,570 ****
#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
! /* 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_ ));
/*
* prototypes for functions in pg_type.c
--- 566,589 ----
#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
!
! /*
! * 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
*** src/include/commands/typecmds.h.orig Fri Jan 5 18:02:45 2007
--- src/include/commands/typecmds.h Sun Apr 1 00:04:00 2007
***************
*** 24,29 ****
--- 24,30 ----
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);
*** src/include/nodes/nodes.h.orig Tue Mar 27 19:21:12 2007
--- src/include/nodes/nodes.h Sun Apr 1 00:03:33 2007
***************
*** 307,312 ****
--- 307,313 ----
T_DropOwnedStmt,
T_ReassignOwnedStmt,
T_CompositeTypeStmt,
+ T_CreateEnumStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
*** src/include/nodes/parsenodes.h.orig Mon Mar 19 20:16:32 2007
--- src/include/nodes/parsenodes.h Sun Apr 1 00:03:34 2007
***************
*** 1706,1711 ****
--- 1706,1722 ----
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
*** src/include/parser/parse_type.h.orig Fri Jan 5 18:02:53 2007
--- src/include/parser/parse_type.h Sun Apr 1 00:03:23 2007
***************
*** 33,39 ****
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);
--- 33,38 ----
*** src/include/utils/builtins.h.orig Wed Mar 21 11:04:42 2007
--- src/include/utils/builtins.h Sun Apr 1 00:03:11 2007
***************
*** 103,108 ****
--- 103,127 ----
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,455 ****
--- 469,476 ----
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);
*** src/include/utils/lsyscache.h.orig Tue Feb 13 20:58:58 2007
--- src/include/utils/lsyscache.h Sun Apr 1 16:35:48 2007
***************
*** 105,110 ****
--- 105,111 ----
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);
*** src/include/utils/syscache.h.orig Tue Feb 13 20:58:58 2007
--- src/include/utils/syscache.h Sun Apr 1 00:03:12 2007
***************
*** 48,70 ****
#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
extern void InitCatalogCache(void);
extern void InitCatalogCachePhase2(void);
--- 48,72 ----
#define CONSTROID 17
#define CONVOID 18
#define DATABASEOID 19
! #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);
*** src/pl/plperl/plperl.c.orig Thu Feb 8 22:35:34 2007
--- src/pl/plperl/plperl.c Sun Apr 1 00:08:02 2007
***************
*** 843,849 ****
/* Disallow pseudotype result */
/* except for TRIGGER, RECORD, or VOID */
! if (functyptype == 'p')
{
/* we assume OPAQUE with no arguments means a trigger */
if (proc->prorettype == TRIGGEROID ||
--- 843,849 ----
/* Disallow pseudotype result */
/* except for TRIGGER, RECORD, or VOID */
! if (functyptype == TYPTYPE_PSEUDO)
{
/* we assume OPAQUE with no arguments means a trigger */
if (proc->prorettype == TRIGGEROID ||
***************
*** 862,868 ****
&argtypes, &argnames, &argmodes);
for (i = 0; i < numargs; i++)
{
! if (get_typtype(argtypes[i]) == 'p')
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plperl functions cannot take type %s",
--- 862,868 ----
&argtypes, &argnames, &argmodes);
for (i = 0; i < numargs; i++)
{
! if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plperl functions cannot take type %s",
***************
*** 1525,1531 ****
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype result, except VOID or RECORD */
! if (typeStruct->typtype == 'p')
{
if (procStruct->prorettype == VOIDOID ||
procStruct->prorettype == RECORDOID)
--- 1525,1531 ----
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype result, except VOID or RECORD */
! if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
if (procStruct->prorettype == VOIDOID ||
procStruct->prorettype == RECORDOID)
***************
*** 1552,1559 ****
prodesc->result_oid = procStruct->prorettype;
prodesc->fn_retisset = procStruct->proretset;
! prodesc->fn_retistuple = (typeStruct->typtype == 'c' ||
! procStruct->prorettype == RECORDOID);
prodesc->fn_retisarray =
(typeStruct->typlen == -1 && typeStruct->typelem);
--- 1552,1559 ----
prodesc->result_oid = procStruct->prorettype;
prodesc->fn_retisset = procStruct->proretset;
! prodesc->fn_retistuple = (procStruct->prorettype == RECORDOID ||
! typeStruct->typtype == TYPTYPE_COMPOSITE);
prodesc->fn_retisarray =
(typeStruct->typlen == -1 && typeStruct->typelem);
***************
*** 1586,1592 ****
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype argument */
! if (typeStruct->typtype == 'p')
{
free(prodesc->proname);
free(prodesc);
--- 1586,1592 ----
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype argument */
! if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
free(prodesc->proname);
free(prodesc);
***************
*** 1596,1602 ****
format_type_be(procStruct->proargtypes.values[i]))));
}
! if (typeStruct->typtype == 'c')
prodesc->arg_is_rowtype[i] = true;
else
{
--- 1596,1602 ----
format_type_be(procStruct->proargtypes.values[i]))));
}
! if (typeStruct->typtype == TYPTYPE_COMPOSITE)
prodesc->arg_is_rowtype[i] = true;
else
{
*** src/pl/plpgsql/src/pl_comp.c.orig Thu Feb 8 22:35:34 2007
--- src/pl/plpgsql/src/pl_comp.c Sun Apr 1 00:08:15 2007
***************
*** 406,412 ****
argdtype = plpgsql_build_datatype(argtypeid, -1);
/* Disallow pseudotype argument */
! /* (note we already replaced ANYARRAY/ANYELEMENT) */
/* (build_variable would do this, but wrong message) */
if (argdtype->ttype != PLPGSQL_TTYPE_SCALAR &&
argdtype->ttype != PLPGSQL_TTYPE_ROW)
--- 406,412 ----
argdtype = plpgsql_build_datatype(argtypeid, -1);
/* Disallow pseudotype argument */
! /* (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,480 ****
* the info available.
*/
rettypeid = procStruct->prorettype;
! if (rettypeid == ANYARRAYOID || rettypeid == ANYELEMENTOID)
{
if (forValidator)
{
--- 474,480 ----
* the info available.
*/
rettypeid = procStruct->prorettype;
! if (IsPolymorphicType(rettypeid))
{
if (forValidator)
{
***************
*** 482,487 ****
--- 482,488 ----
rettypeid = INT4ARRAYOID;
else
rettypeid = INT4OID;
+ /* XXX what could we use for ANYENUM? */
}
else
{
***************
*** 512,519 ****
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype result, except VOID or RECORD */
! /* (note we already replaced ANYARRAY/ANYELEMENT) */
! if (typeStruct->typtype == 'p')
{
if (rettypeid == VOIDOID ||
rettypeid == RECORDOID)
--- 513,520 ----
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype result, except VOID or RECORD */
! /* (note we already replaced polymorphic types) */
! if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
if (rettypeid == VOIDOID ||
rettypeid == RECORDOID)
***************
*** 544,551 ****
* types, and not when the return is specified through an
* output parameter.
*/
! if ((procStruct->prorettype == ANYARRAYOID ||
! procStruct->prorettype == ANYELEMENTOID) &&
num_out_args == 0)
{
(void) plpgsql_build_variable("$0", 0,
--- 545,551 ----
* types, and not when the return is specified through an
* output parameter.
*/
! if (IsPolymorphicType(procStruct->prorettype) &&
num_out_args == 0)
{
(void) plpgsql_build_variable("$0", 0,
***************
*** 1785,1799 ****
typ->typoid = HeapTupleGetOid(typeTup);
switch (typeStruct->typtype)
{
! case 'b': /* base type */
! case 'd': /* domain */
typ->ttype = PLPGSQL_TTYPE_SCALAR;
break;
! case 'c': /* composite, ie, rowtype */
Assert(OidIsValid(typeStruct->typrelid));
typ->ttype = PLPGSQL_TTYPE_ROW;
break;
! case 'p': /* pseudo */
if (typ->typoid == RECORDOID)
typ->ttype = PLPGSQL_TTYPE_REC;
else
--- 1785,1800 ----
typ->typoid = HeapTupleGetOid(typeTup);
switch (typeStruct->typtype)
{
! case TYPTYPE_BASE:
! case TYPTYPE_DOMAIN:
! case TYPTYPE_ENUM:
typ->ttype = PLPGSQL_TTYPE_SCALAR;
break;
! case TYPTYPE_COMPOSITE:
Assert(OidIsValid(typeStruct->typrelid));
typ->ttype = PLPGSQL_TTYPE_ROW;
break;
! case TYPTYPE_PSEUDO:
if (typ->typoid == RECORDOID)
typ->ttype = PLPGSQL_TTYPE_REC;
else
***************
*** 2026,2031 ****
--- 2027,2033 ----
switch (argtypes[i])
{
case ANYELEMENTOID:
+ case ANYENUMOID: /* XXX dubious */
argtypes[i] = INT4OID;
break;
case ANYARRAYOID:
*** src/pl/plpgsql/src/pl_exec.c.orig Tue Mar 27 19:21:12 2007
--- src/pl/plpgsql/src/pl_exec.c Sun Apr 1 00:08:15 2007
***************
*** 3294,3301 ****
PLpgSQL_row *row = (PLpgSQL_row *) target;
/* Source must be of RECORD or composite type */
! if (!(valtype == RECORDOID ||
! get_typtype(valtype) == 'c'))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot assign non-composite value to a row variable")));
--- 3294,3300 ----
PLpgSQL_row *row = (PLpgSQL_row *) target;
/* Source must be of RECORD or composite type */
! if (!type_is_rowtype(valtype))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot assign non-composite value to a row variable")));
***************
*** 3337,3344 ****
PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
/* Source must be of RECORD or composite type */
! if (!(valtype == RECORDOID ||
! get_typtype(valtype) == 'c'))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot assign non-composite value to a record variable")));
--- 3336,3342 ----
PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
/* Source must be of RECORD or composite type */
! if (!type_is_rowtype(valtype))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot assign non-composite value to a record variable")));
*** src/pl/plpgsql/src/pl_handler.c.orig Tue Jan 30 17:05:13 2007
--- src/pl/plpgsql/src/pl_handler.c Sun Apr 1 00:08:15 2007
***************
*** 147,154 ****
functyptype = get_typtype(proc->prorettype);
/* Disallow pseudotype result */
! /* except for TRIGGER, RECORD, VOID, ANYARRAY, or ANYELEMENT */
! if (functyptype == 'p')
{
/* we assume OPAQUE with no arguments means a trigger */
if (proc->prorettype == TRIGGEROID ||
--- 147,154 ----
functyptype = get_typtype(proc->prorettype);
/* Disallow pseudotype result */
! /* 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,163 ****
istrigger = true;
else if (proc->prorettype != RECORDOID &&
proc->prorettype != VOIDOID &&
! proc->prorettype != ANYARRAYOID &&
! proc->prorettype != ANYELEMENTOID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpgsql functions cannot return type %s",
--- 156,162 ----
istrigger = true;
else if (proc->prorettype != RECORDOID &&
proc->prorettype != VOIDOID &&
! !IsPolymorphicType(proc->prorettype))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpgsql functions cannot return type %s",
***************
*** 165,179 ****
}
/* Disallow pseudotypes in arguments (either IN or OUT) */
! /* except for ANYARRAY or ANYELEMENT */
numargs = get_func_arg_info(tuple,
&argtypes, &argnames, &argmodes);
for (i = 0; i < numargs; i++)
{
! if (get_typtype(argtypes[i]) == 'p')
{
! if (argtypes[i] != ANYARRAYOID &&
! argtypes[i] != ANYELEMENTOID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpgsql functions cannot take type %s",
--- 164,177 ----
}
/* Disallow pseudotypes in arguments (either IN or OUT) */
! /* except for polymorphic */
numargs = get_func_arg_info(tuple,
&argtypes, &argnames, &argmodes);
for (i = 0; i < numargs; i++)
{
! if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
{
! if (!IsPolymorphicType(argtypes[i]))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("plpgsql functions cannot take type %s",
*** src/pl/plpython/plpython.c.orig Thu Feb 22 17:05:14 2007
--- src/pl/plpython/plpython.c Sun Apr 1 00:08:23 2007
***************
*** 1185,1191 ****
rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
/* Disallow pseudotype result, except for void */
! if (rvTypeStruct->typtype == 'p' &&
procStruct->prorettype != VOIDOID)
{
if (procStruct->prorettype == TRIGGEROID)
--- 1185,1191 ----
rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
/* Disallow pseudotype result, except for void */
! if (rvTypeStruct->typtype == TYPTYPE_PSEUDO &&
procStruct->prorettype != VOIDOID)
{
if (procStruct->prorettype == TRIGGEROID)
***************
*** 1199,1205 ****
format_type_be(procStruct->prorettype))));
}
! if (rvTypeStruct->typtype == 'c')
{
/*
* Tuple: set up later, during first call to
--- 1199,1205 ----
format_type_be(procStruct->prorettype))));
}
! if (rvTypeStruct->typtype == TYPTYPE_COMPOSITE)
{
/*
* Tuple: set up later, during first call to
***************
*** 1258,1270 ****
argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
/* Disallow pseudotype argument */
! if (argTypeStruct->typtype == 'p')
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')
PLy_input_datum_func(&(proc->args[i]),
procStruct->proargtypes.values[i],
argTypeTup);
--- 1258,1270 ----
argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
/* Disallow pseudotype argument */
! 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 != TYPTYPE_COMPOSITE)
PLy_input_datum_func(&(proc->args[i]),
procStruct->proargtypes.values[i],
argTypeTup);
***************
*** 2338,2344 ****
plan->types[i] = typeId;
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
! if (typeStruct->typtype != 'c')
PLy_output_datum_func(&plan->args[i], typeTup);
else
elog(ERROR, "tuples not handled in plpy.prepare, yet.");
--- 2338,2344 ----
plan->types[i] = typeId;
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
! if (typeStruct->typtype != TYPTYPE_COMPOSITE)
PLy_output_datum_func(&plan->args[i], typeTup);
else
elog(ERROR, "tuples not handled in plpy.prepare, yet.");
*** src/pl/tcl/pltcl.c.orig Thu Feb 22 17:05:14 2007
--- src/pl/tcl/pltcl.c Sun Apr 1 00:08:28 2007
***************
*** 1051,1057 ****
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype result, except VOID */
! if (typeStruct->typtype == 'p')
{
if (procStruct->prorettype == VOIDOID)
/* okay */ ;
--- 1051,1057 ----
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype result, except VOID */
! if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
if (procStruct->prorettype == VOIDOID)
/* okay */ ;
***************
*** 1074,1080 ****
}
}
! if (typeStruct->typtype == 'c')
{
free(prodesc->proname);
free(prodesc);
--- 1074,1080 ----
}
}
! if (typeStruct->typtype == TYPTYPE_COMPOSITE)
{
free(prodesc->proname);
free(prodesc);
***************
*** 1112,1118 ****
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype argument */
! if (typeStruct->typtype == 'p')
{
free(prodesc->proname);
free(prodesc);
--- 1112,1118 ----
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
/* Disallow pseudotype argument */
! if (typeStruct->typtype == TYPTYPE_PSEUDO)
{
free(prodesc->proname);
free(prodesc);
***************
*** 1122,1128 ****
format_type_be(procStruct->proargtypes.values[i]))));
}
! if (typeStruct->typtype == 'c')
{
prodesc->arg_is_rowtype[i] = true;
snprintf(buf, sizeof(buf), "__PLTcl_Tup_%d", i + 1);
--- 1122,1128 ----
format_type_be(procStruct->proargtypes.values[i]))));
}
! if (typeStruct->typtype == TYPTYPE_COMPOSITE)
{
prodesc->arg_is_rowtype[i] = true;
snprintf(buf, sizeof(buf), "__PLTcl_Tup_%d", i + 1);
*** src/test/regress/expected/enum.out.orig Sun Apr 1 00:13:26 2007
--- src/test/regress/expected/enum.out Sun Apr 1 18:17:04 2007
***************
*** 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)
+
*** src/test/regress/expected/polymorphism.out.orig Thu Jul 27 15:52:07 2006
--- src/test/regress/expected/polymorphism.out Sun Apr 1 19:45:33 2007
***************
*** 80,86 ****
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.
-- N P
-- should CREATE
CREATE AGGREGATE myaggp03a(*) (SFUNC = stfp, STYPE = int4[],
--- 80,86 ----
CREATE AGGREGATE myaggp02a(*) (SFUNC = stfnp, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}');
ERROR: cannot determine transition data 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,102 ****
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.
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.
-- Case2 (R = P) && ((B = P) || (B = N))
-- -------------------------------------
-- S tf1 B tf2
--- 92,102 ----
CREATE AGGREGATE myaggp04a(*) (SFUNC = stfp, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}');
ERROR: cannot determine transition data 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 a polymorphic transition type must have at least one polymorphic argument.
-- Case2 (R = P) && ((B = P) || (B = N))
-- -------------------------------------
-- S tf1 B tf2
***************
*** 151,163 ****
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.
-- 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.
-- P N P N
-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
CREATE AGGREGATE myaggp15a(BASETYPE = anyelement, SFUNC = tfnp,
--- 151,163 ----
CREATE AGGREGATE myaggp13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}');
ERROR: cannot determine transition data 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 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,193 ****
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.
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.
-- 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.
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.
-- P P P N
-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
CREATE AGGREGATE myaggp19a(BASETYPE = anyelement, SFUNC = tf1p,
--- 173,193 ----
CREATE AGGREGATE myaggp17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}');
ERROR: cannot determine transition data 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 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 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 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,227 ****
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.
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.
-- N P
-- should CREATE
CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[],
--- 217,227 ----
CREATE AGGREGATE myaggn02a(*) (SFUNC = stfnp, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}');
ERROR: cannot determine transition data 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 a polymorphic transition type must have at least one polymorphic argument.
-- N P
-- should CREATE
CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[],
***************
*** 231,237 ****
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.
-- Case4 (R = N) && ((B = P) || (B = N))
-- -------------------------------------
-- S tf1 B tf2
--- 231,237 ----
CREATE AGGREGATE myaggn04a(*) (SFUNC = stfp, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}');
ERROR: cannot determine transition data 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,305 ****
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.
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.
-- 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.
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.
-- P N P N
-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
CREATE AGGREGATE myaggn15a(BASETYPE = anyelement, SFUNC = tfnp,
--- 285,305 ----
CREATE AGGREGATE myaggn13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}');
ERROR: cannot determine transition data 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 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 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 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,333 ****
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.
-- 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.
-- P P P N
-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
CREATE AGGREGATE myaggn19a(BASETYPE = anyelement, SFUNC = tf1p,
--- 321,333 ----
CREATE AGGREGATE myaggn17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}');
ERROR: cannot determine transition data 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 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,
*** src/test/regress/expected/rangefuncs.out.orig Thu Feb 1 15:09:55 2007
--- src/test/regress/expected/rangefuncs.out Sun Apr 1 19:53:26 2007
***************
*** 500,506 ****
(1 row)
SELECT dup('xyz'); -- fails
! ERROR: could not determine anyarray/anyelement type because input has type "unknown"
SELECT dup('xyz'::text);
dup
-------------------
--- 500,506 ----
(1 row)
SELECT dup('xyz'); -- fails
! ERROR: could not determine polymorphic type because input has type "unknown"
SELECT dup('xyz'::text);
dup
-------------------
***************
*** 527,530 ****
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.
--- 527,530 ----
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 a polymorphic type must have at least one polymorphic argument.
*** src/test/regress/expected/sanity_check.out.orig Tue Dec 19 11:23:38 2006
--- src/test/regress/expected/sanity_check.out Sun Apr 1 00:55:15 2007
***************
*** 97,102 ****
--- 97,103 ----
pg_database | t
pg_depend | t
pg_description | t
+ pg_enum | t
pg_index | t
pg_inherits | t
pg_language | t
***************
*** 141,147 ****
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (130 rows)
--
-- another sanity check: every system catalog that has OIDs should have
--- 142,148 ----
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (131 rows)
--
-- another sanity check: every system catalog that has OIDs should have
*** src/test/regress/expected/type_sanity.out.orig Fri Dec 29 18:38:36 2006
--- src/test/regress/expected/type_sanity.out Sun Apr 1 01:30:50 2007
***************
*** 17,23 ****
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
NOT p1.typisdefined OR
(p1.typalign not in ('c', 's', 'i', 'd')) OR
(p1.typstorage not in ('p', 'x', 'e', 'm'));
--- 17,23 ----
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', '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,65 ****
-----+---------
(0 rows)
! -- Look for basic 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
(SELECT 1 FROM pg_type as p2
WHERE p2.typname = ('_' || p1.typname)::name AND
p2.typelem = p1.oid);
--- 55,65 ----
-----+---------
(0 rows)
! -- 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','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);
*** src/test/regress/parallel_schedule.orig Mon Mar 19 12:44:41 2007
--- src/test/regress/parallel_schedule Sun Apr 1 01:30:19 2007
***************
*** 2,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 $
# ----------
! test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric uuid
# Depends on things setup during char, varchar and text
test: strings
--- 2,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 $
# ----------
! 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
*** src/test/regress/serial_schedule.orig Mon Mar 12 20:33:44 2007
--- src/test/regress/serial_schedule Sun Apr 1 01:30:19 2007
***************
*** 14,19 ****
--- 14,20 ----
test: bit
test: numeric
test: uuid
+ test: enum
test: strings
test: numerology
test: point
*** src/test/regress/sql/enum.sql.orig Sun Apr 1 00:13:13 2007
--- src/test/regress/sql/enum.sql Sun Apr 1 18:16:47 2007
***************
*** 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);
*** src/test/regress/sql/type_sanity.sql.orig Fri Dec 29 18:38:14 2006
--- src/test/regress/sql/type_sanity.sql Sun Apr 1 01:24:35 2007
***************
*** 20,26 ****
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
NOT p1.typisdefined OR
(p1.typalign not in ('c', 's', 'i', 'd')) OR
(p1.typstorage not in ('p', 'x', 'e', 'm'));
--- 20,26 ----
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', '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,60 ****
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.
-- 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
(SELECT 1 FROM pg_type as p2
WHERE p2.typname = ('_' || p1.typname)::name AND
p2.typelem = p1.oid);
--- 49,60 ----
WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR
(p1.typtype != 'c' AND p1.typrelid != 0);
! -- 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','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);