Support enum data types. Along the way, use macros for the values of
authorTom Lane
Mon, 2 Apr 2007 03:49:42 +0000 (03:49 +0000)
committerTom Lane
Mon, 2 Apr 2007 03:49:42 +0000 (03:49 +0000)
pg_type.typtype whereever practical.  Tom Dunstan, with some kibitzing
from Tom Lane.

74 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/datatype.sgml
doc/src/sgml/extend.sgml
doc/src/sgml/func.sgml
doc/src/sgml/plpgsql.sgml
doc/src/sgml/ref/create_type.sgml
doc/src/sgml/xfunc.sgml
src/backend/access/hash/hashfunc.c
src/backend/catalog/Makefile
src/backend/catalog/heap.c
src/backend/catalog/pg_aggregate.c
src/backend/catalog/pg_enum.c [new file with mode: 0644]
src/backend/catalog/pg_proc.c
src/backend/catalog/pg_type.c
src/backend/commands/aggregatecmds.c
src/backend/commands/functioncmds.c
src/backend/commands/typecmds.c
src/backend/executor/functions.c
src/backend/executor/nodeAgg.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/optimizer/util/clauses.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_oper.c
src/backend/parser/parse_type.c
src/backend/tcop/utility.c
src/backend/utils/adt/Makefile
src/backend/utils/adt/enum.c [new file with mode: 0644]
src/backend/utils/adt/format_type.c
src/backend/utils/adt/pseudotypes.c
src/backend/utils/adt/xml.c
src/backend/utils/cache/lsyscache.c
src/backend/utils/cache/syscache.c
src/backend/utils/cache/typcache.c
src/backend/utils/fmgr/funcapi.c
src/bin/pg_dump/pg_dump.c
src/include/access/hash.h
src/include/catalog/catversion.h
src/include/catalog/indexing.h
src/include/catalog/pg_aggregate.h
src/include/catalog/pg_amop.h
src/include/catalog/pg_amproc.h
src/include/catalog/pg_cast.h
src/include/catalog/pg_enum.h [new file with mode: 0644]
src/include/catalog/pg_opclass.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_opfamily.h
src/include/catalog/pg_proc.h
src/include/catalog/pg_type.h
src/include/commands/typecmds.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/parser/parse_type.h
src/include/utils/builtins.h
src/include/utils/lsyscache.h
src/include/utils/syscache.h
src/pl/plperl/plperl.c
src/pl/plpgsql/src/pl_comp.c
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_handler.c
src/pl/plpython/plpython.c
src/pl/tcl/pltcl.c
src/test/regress/expected/enum.out [new file with mode: 0644]
src/test/regress/expected/polymorphism.out
src/test/regress/expected/rangefuncs.out
src/test/regress/expected/sanity_check.out
src/test/regress/expected/type_sanity.out
src/test/regress/parallel_schedule
src/test/regress/serial_schedule
src/test/regress/sql/enum.sql [new file with mode: 0644]
src/test/regress/sql/type_sanity.sql

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