OSDN Git Service

Allow the syntax CREATE TYPE foo, with no parameters, to permit explicit
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 28 Feb 2006 22:37:27 +0000 (22:37 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 28 Feb 2006 22:37:27 +0000 (22:37 +0000)
creation of a shell type.  This allows a less hacky way of dealing with
the mutual dependency between a datatype and its I/O functions: make a
shell type, then make the functions, then define the datatype fully.
We should fix pg_dump to handle things this way, but this commit just deals
with the backend.

Martijn van Oosterhout, with some corrections by Tom Lane.

12 files changed:
doc/src/sgml/ref/create_type.sgml
doc/src/sgml/xtypes.sgml
src/backend/catalog/pg_type.c
src/backend/commands/typecmds.c
src/backend/parser/gram.y
src/backend/utils/adt/pseudotypes.c
src/include/catalog/catversion.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/test/regress/expected/create_type.out
src/test/regress/sql/create_type.sql

index a39c244..9382395 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.60 2006/01/13 18:06:45 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.61 2006/02/28 22:37:25 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -37,6 +37,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
     [ , ELEMENT = <replaceable class="parameter">element</replaceable> ]
     [ , DELIMITER = <replaceable class="parameter">delimiter</replaceable> ]
 )
+
+CREATE TYPE <replaceable class="parameter">name</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -142,17 +144,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
 
   <para>
    You should at this point be wondering how the input and output functions
-   can be declared to have results or arguments of the new type, when they have
-   to be created before the new type can be created.  The answer is that the
-   input function must be created first, then the output function (and
-   the binary I/O functions if wanted), and finally the data type.
-   <productname>PostgreSQL</productname> will first see the name of the new
-   data type as the return type of the input function.  It will create a
-   <quote>shell</> type, which is simply a placeholder entry in
-   the system catalog, and link the input function definition to the shell
-   type.  Similarly the other functions will be linked to the (now already
-   existing) shell type.  Finally, <command>CREATE TYPE</> replaces the
-   shell entry with a complete type definition, and the new type can be used.
+   can be declared to have results or arguments of the new type, when they
+   have to be created before the new type can be created.  The answer is that
+   the type should first be defined as a <firstterm>shell type</>, which is a
+   placeholder type that has no properties except a name and an owner.  This
+   is done by issuing the command <literal>CREATE TYPE
+   <replaceable>name</></literal>, with no additional parameters.  Then the
+   I/O functions can be defined referencing the shell type.  Finally,
+   <command>CREATE TYPE</> with a full definition replaces the shell entry
+   with a complete, valid type definition, after which the new type can be
+   used normally.
   </para>
 
   <para>
@@ -458,16 +459,32 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
   </para>
 
   <para>
+   Before <productname>PostgreSQL</productname> version 8.2, the syntax
+   <literal>CREATE TYPE <replaceable>name</></literal> did not exist.
+   The way to create a new base type was to create its input function first.
+   In this approach, <productname>PostgreSQL</productname> will first see
+   the name of the new data type as the return type of the input function.
+   The shell type is implicitly created in this situation, and then it
+   can be referenced in the definitions of the remaining I/O functions.
+   This approach still works, but is deprecated and may be disallowed in
+   some future release.  Also, to avoid accidentally cluttering
+   the catalogs with shell types as a result of simple typos in function
+   definitions, a shell type will only be made this way when the input
+   function is written in C.
+  </para>
+
+  <para>
    In <productname>PostgreSQL</productname> versions before 7.3, it
-   was customary to avoid creating a shell type by replacing the
+   was customary to avoid creating a shell type at all, by replacing the
    functions' forward references to the type name with the placeholder
    pseudotype <type>opaque</>.  The <type>cstring</> arguments and
    results also had to be declared as <type>opaque</> before 7.3.  To
    support loading of old dump files, <command>CREATE TYPE</> will
-   accept functions declared using <type>opaque</>, but it will issue
-   a notice and change the function's declaration to use the correct
+   accept I/O functions declared using <type>opaque</>, but it will issue
+   a notice and change the function declarations to use the correct
    types.
   </para>
+
  </refsect1>
  
  <refsect1>
@@ -489,6 +506,11 @@ $$ LANGUAGE SQL;
    This example creates the base data type <type>box</type> and then uses the
    type in a table definition:
 <programlisting>
+CREATE TYPE box;
+
+CREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ;
+CREATE FUNCTION my_box_out_function(box) RETURNS cstring AS ... ;
+
 CREATE TYPE box (
     INTERNALLENGTH = 16,
     INPUT = my_box_in_function,
index 22d11a6..9572336 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/xtypes.sgml,v 1.25 2005/01/10 00:04:38 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/xtypes.sgml,v 1.26 2006/02/28 22:37:25 tgl Exp $
 -->
 
  <sect1 id="xtypes">
@@ -168,8 +168,16 @@ complex_send(PG_FUNCTION_ARGS)
  </para>
 
  <para>
-  To define the <type>complex</type> type, we need to create the
-  user-defined I/O functions before creating the type:
+  Once we have written the I/O functions and compiled them into a shared
+  library, we can define the <type>complex</type> type in SQL.
+  First we declare it as a shell type:
+
+<programlisting>
+CREATE TYPE complex;
+</programlisting>
+
+  This serves as a placeholder that allows us to reference the type while
+  defining its I/O functions.  Now we can define the I/O functions:
 
 <programlisting>
 CREATE FUNCTION complex_in(cstring)
@@ -192,15 +200,10 @@ CREATE FUNCTION complex_send(complex)
    AS '<replaceable>filename</replaceable>'
    LANGUAGE C IMMUTABLE STRICT;
 </programlisting>
-
-  Notice that the declarations of the input and output functions must
-  reference the not-yet-defined type.  This is allowed, but will draw
-  warning messages that may be ignored.  The input function must
-  appear first.
  </para>
 
  <para>
-  Finally, we can declare the data type:
+  Finally, we can provide the full definition of the data type:
 <programlisting>
 CREATE TYPE complex (
    internallength = 16, 
index ab250b0..f6fbbef 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.104 2005/10/15 02:49:14 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.105 2006/02/28 22:37:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "commands/typecmds.h"
 #include "miscadmin.h"
+#include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 /* ----------------------------------------------------------------
  *             TypeShellMake
  *
- *             This procedure inserts a "shell" tuple into the type
- *             relation.  The type tuple inserted has invalid values
- *             and in particular, the "typisdefined" field is false.
+ *             This procedure inserts a "shell" tuple into the pg_type relation.
+ *             The type tuple inserted has valid but dummy values, and its
+ *             "typisdefined" field is false indicating it's not really defined.
  *
- *             This is used so that a tuple exists in the catalogs.
- *             The invalid fields should be fixed up sometime after
- *             this routine is called, and then the "typeisdefined"
- *             field is set to true. -cim 6/15/90
+ *             This is used so that a tuple exists in the catalogs.  The I/O
+ *             functions for the type will link to this tuple.  When the full
+ *             CREATE TYPE command is issued, the bogus values will be replaced
+ *             with correct ones, and "typisdefined" will be set to true.
  * ----------------------------------------------------------------
  */
 Oid
@@ -70,30 +73,35 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
 
        /*
         * initialize *values with the type name and dummy values
+        *
+        * The representational details are the same as int4 ... it doesn't
+        * really matter what they are so long as they are consistent.  Also
+        * note that we give it typtype = 'p' (pseudotype) as extra insurance
+        * that it won't be mistaken for a usable type.
         */
        i = 0;
        namestrcpy(&name, typeName);
        values[i++] = NameGetDatum(&name);      /* typname */
        values[i++] = ObjectIdGetDatum(typeNamespace);          /* typnamespace */
        values[i++] = ObjectIdGetDatum(GetUserId());            /* typowner */
-       values[i++] = Int16GetDatum(0);         /* typlen */
-       values[i++] = BoolGetDatum(false);      /* typbyval */
-       values[i++] = CharGetDatum(0);          /* typtype */
-       values[i++] = BoolGetDatum(false);      /* typisdefined */
-       values[i++] = CharGetDatum(0);          /* typdelim */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* typinput */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* typoutput */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* typsend */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* typanalyze */
-       values[i++] = CharGetDatum('i');        /* typalign */
-       values[i++] = CharGetDatum('p');        /* typstorage */
-       values[i++] = BoolGetDatum(false);      /* typnotnull */
-       values[i++] = ObjectIdGetDatum(InvalidOid); /* typbasetype */
-       values[i++] = Int32GetDatum(-1);        /* typtypmod */
-       values[i++] = Int32GetDatum(0);         /* typndims */
+       values[i++] = Int16GetDatum(sizeof(int4));                      /* typlen */
+       values[i++] = BoolGetDatum(true);                                       /* typbyval */
+       values[i++] = CharGetDatum('p');                                        /* typtype */
+       values[i++] = BoolGetDatum(false);                                      /* typisdefined */
+       values[i++] = CharGetDatum(DEFAULT_TYPDELIM);           /* typdelim */
+       values[i++] = ObjectIdGetDatum(InvalidOid);                     /* typrelid */
+       values[i++] = ObjectIdGetDatum(InvalidOid);                     /* typelem */
+       values[i++] = ObjectIdGetDatum(F_SHELL_IN);                     /* typinput */
+       values[i++] = ObjectIdGetDatum(F_SHELL_OUT);            /* typoutput */
+       values[i++] = ObjectIdGetDatum(InvalidOid);                     /* typreceive */
+       values[i++] = ObjectIdGetDatum(InvalidOid);                     /* typsend */
+       values[i++] = ObjectIdGetDatum(InvalidOid);                     /* typanalyze */
+       values[i++] = CharGetDatum('i');                                        /* typalign */
+       values[i++] = CharGetDatum('p');                                        /* typstorage */
+       values[i++] = BoolGetDatum(false);                                      /* typnotnull */
+       values[i++] = ObjectIdGetDatum(InvalidOid);                     /* typbasetype */
+       values[i++] = Int32GetDatum(-1);                                        /* typtypmod */
+       values[i++] = Int32GetDatum(0);                                         /* typndims */
        nulls[i++] = 'n';                       /* typdefaultbin */
        nulls[i++] = 'n';                       /* typdefault */
 
@@ -118,8 +126,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
                                                                 InvalidOid,
                                                                 0,
                                                                 GetUserId(),
-                                                                InvalidOid,
-                                                                InvalidOid,
+                                                                F_SHELL_IN,
+                                                                F_SHELL_OUT,
                                                                 InvalidOid,
                                                                 InvalidOid,
                                                                 InvalidOid,
@@ -289,7 +297,13 @@ TypeCreate(const char *typeName,
                                         errmsg("type \"%s\" already exists", typeName)));
 
                /*
-                * Okay to update existing "shell" type tuple
+                * shell type must have been created by same owner
+                */
+               if (((Form_pg_type) GETSTRUCT(tup))->typowner != GetUserId())
+                       aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName);
+
+               /*
+                * Okay to update existing shell type tuple
                 */
                tup = heap_modifytuple(tup,
                                                           RelationGetDescr(pg_type_desc),
@@ -350,8 +364,6 @@ TypeCreate(const char *typeName,
  * If rebuild is true, we remove existing dependencies and rebuild them
  * from scratch.  This is needed for ALTER TYPE, and also when replacing
  * a shell type.
- *
- * NOTE: a shell type will have a dependency to its namespace, and no others.
  */
 void
 GenerateTypeDependencies(Oid typeNamespace,
index 1436952..f8e1a26 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.86 2006/01/13 18:06:45 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.87 2006/02/28 22:37:26 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -138,6 +138,37 @@ DefineType(List *names, List *parameters)
                                 errmsg("type names must be %d characters or less",
                                                NAMEDATALEN - 2)));
 
+       /*
+        * Look to see if type already exists (presumably as a shell; if not,
+        * TypeCreate will complain).  If it doesn't, create it as a shell, so
+        * that the OID is known for use in the I/O function definitions.
+        */
+       typoid = GetSysCacheOid(TYPENAMENSP,
+                                                       CStringGetDatum(typeName),
+                                                       ObjectIdGetDatum(typeNamespace),
+                                                       0, 0);
+       if (!OidIsValid(typoid))
+       {
+               typoid = TypeShellMake(typeName, typeNamespace);
+               /* Make new shell type visible for modification below */
+               CommandCounterIncrement();
+
+               /*
+                * If the command was a parameterless CREATE TYPE, we're done ---
+                * creating the shell type was all we're supposed to do.
+                */
+               if (parameters == NIL)
+                       return;
+       }
+       else
+       {
+               /* Complain if dummy CREATE TYPE and entry already exists */
+               if (parameters == NIL)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_DUPLICATE_OBJECT),
+                                        errmsg("type \"%s\" already exists", typeName)));
+       }
+
        foreach(pl, parameters)
        {
                DefElem    *defel = (DefElem *) lfirst(pl);
@@ -241,22 +272,6 @@ DefineType(List *names, List *parameters)
                                 errmsg("type output function must be specified")));
 
        /*
-        * Look to see if type already exists (presumably as a shell; if not,
-        * TypeCreate will complain).  If it doesn't, create it as a shell, so
-        * that the OID is known for use in the I/O function definitions.
-        */
-       typoid = GetSysCacheOid(TYPENAMENSP,
-                                                       CStringGetDatum(typeName),
-                                                       ObjectIdGetDatum(typeNamespace),
-                                                       0, 0);
-       if (!OidIsValid(typoid))
-       {
-               typoid = TypeShellMake(typeName, typeNamespace);
-               /* Make new shell type visible for modification below */
-               CommandCounterIncrement();
-       }
-
-       /*
         * Convert I/O proc names to OIDs
         */
        inputOid = findTypeInputFunction(inputName, typoid);
index 6cb6f96..a60d415 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.530 2006/02/19 00:04:27 neilc Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.531 2006/02/28 22:37:26 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -2690,6 +2690,15 @@ DefineStmt:
                                        n->definition = $4;
                                        $$ = (Node *)n;
                                }
+                       | CREATE TYPE_P any_name 
+                               {
+                                       /* Shell type (identified by lack of definition) */
+                                       DefineStmt *n = makeNode(DefineStmt);
+                                       n->kind = OBJECT_TYPE;
+                                       n->defnames = $3;
+                                       n->definition = NIL;
+                                       $$ = (Node *)n;
+                               }
                        | CREATE TYPE_P any_name AS '(' TableFuncElementList ')'
                                {
                                        CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
index 105598a..9893432 100644 (file)
@@ -16,7 +16,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.15 2004/12/31 22:01:22 pgsql Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.16 2006/02/28 22:37:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -321,3 +321,29 @@ anyelement_out(PG_FUNCTION_ARGS)
 
        PG_RETURN_VOID();                       /* keep compiler quiet */
 }
+
+/*
+ * shell_in            - input routine for "shell" types (those not yet filled in).
+ */
+Datum
+shell_in(PG_FUNCTION_ARGS)
+{
+       ereport(ERROR,
+                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                        errmsg("cannot accept a value of a shell type")));
+
+       PG_RETURN_VOID();                       /* keep compiler quiet */
+}
+
+/*
+ * shell_out           - output routine for "shell" types.
+ */
+Datum
+shell_out(PG_FUNCTION_ARGS)
+{
+       ereport(ERROR,
+                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                        errmsg("cannot display a value of a shell type")));
+
+       PG_RETURN_VOID();                       /* keep compiler quiet */
+}
index 1a391ba..dbca22e 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.316 2006/02/26 18:36:21 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.317 2006/02/28 22:37:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200602251
+#define CATALOG_VERSION_NO     200602281
 
 #endif
index a746bff..84fb254 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.140 2006/02/26 18:36:21 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.141 2006/02/28 22:37:26 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -128,9 +128,9 @@ DATA(insert OID = 388 (  "!"           PGNSP PGUID r f      20       0      1700   0   0   0   0  0
 DATA(insert OID = 389 (  "!!"     PGNSP PGUID l f       0      20      1700   0   0   0   0  0   0 numeric_fac - - ));
 DATA(insert OID = 385 (  "="      PGNSP PGUID b t      29      29      16 385   0       0       0       0       0 cideq eqsel eqjoinsel ));
 DATA(insert OID = 386 (  "="      PGNSP PGUID b t      22      22      16 386   0       0       0       0       0 int2vectoreq eqsel eqjoinsel ));
-DATA(insert OID = 387 (  "="      PGNSP PGUID b f      27      27      16 387   0       0       0       0       0 tideq eqsel eqjoinsel ));
+DATA(insert OID = 387 (  "="      PGNSP PGUID b f      27      27      16 387 402       0       0       0       0 tideq eqsel eqjoinsel ));
 #define TIDEqualOperator   387
-DATA(insert OID = 402 (  "<>"     PGNSP PGUID b f      27      27      16 402   0       0       0       0       0 tidne neqsel neqjoinsel ));
+DATA(insert OID = 402 (  "<>"     PGNSP PGUID b f      27      27      16 402 387       0       0       0       0 tidne neqsel neqjoinsel ));
 
 DATA(insert OID = 410 ( "="               PGNSP PGUID b t      20      20      16 410 411 412 412 412 413 int8eq eqsel eqjoinsel ));
 DATA(insert OID = 411 ( "<>"      PGNSP PGUID b f      20      20      16 411 410 0 0 0 0 int8ne neqsel neqjoinsel ));
index ec43235..4a9da19 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.398 2006/02/26 18:36:21 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.399 2006/02/28 22:37:26 tgl Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -1598,7 +1598,7 @@ DATA(insert OID = 1293 ( currtid             PGNSP PGUID 12 f f t f v 2 27 "26 27" _null
 DESCR("latest tid of a tuple");
 DATA(insert OID = 1294 ( currtid2                 PGNSP PGUID 12 f f t f v 2 27 "25 27" _null_ _null_ _null_ currtid_byrelname - _null_ ));
 DESCR("latest tid of a tuple");
-DATA(insert OID = 2398 ( tidne                    PGNSP PGUID 12 f f t f i 2 16 "27 27" _null_ _null_ _null_ tidne - _null_ ));
+DATA(insert OID = 1265 ( tidne                    PGNSP PGUID 12 f f t f i 2 16 "27 27" _null_ _null_ _null_ tidne - _null_ ));
 DESCR("not equal");
 
 DATA(insert OID = 2168 ( pg_database_size              PGNSP PGUID 12 f f t f v 1 20 "19" _null_ _null_ _null_ pg_database_size_name - _null_ ));
@@ -3321,6 +3321,10 @@ DATA(insert OID = 2312 (  anyelement_in          PGNSP PGUID 12 f f t f i 1 2283 "2275"
 DESCR("I/O");
 DATA(insert OID = 2313 (  anyelement_out       PGNSP PGUID 12 f f t f i 1 2275 "2283" _null_ _null_ _null_ anyelement_out - _null_ ));
 DESCR("I/O");
+DATA(insert OID = 2398 (  shell_in                     PGNSP PGUID 12 f f t f i 1 2282 "2275" _null_ _null_ _null_ shell_in - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2399 (  shell_out                    PGNSP PGUID 12 f f t f i 1 2275 "2282" _null_ _null_ _null_ shell_out - _null_ ));
+DESCR("I/O");
 
 /* cryptographic */
 DATA(insert OID =  2311 (  md5    PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_      md5_text - _null_ ));
index 28a70d1..50f349a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.274 2006/02/26 18:36:22 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.275 2006/02/28 22:37:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -443,6 +443,8 @@ extern Datum opaque_in(PG_FUNCTION_ARGS);
 extern Datum opaque_out(PG_FUNCTION_ARGS);
 extern Datum anyelement_in(PG_FUNCTION_ARGS);
 extern Datum anyelement_out(PG_FUNCTION_ARGS);
+extern Datum shell_in(PG_FUNCTION_ARGS);
+extern Datum shell_out(PG_FUNCTION_ARGS);
 
 /* regexp.c */
 extern Datum nameregexeq(PG_FUNCTION_ARGS);
index 4e2d44d..3e2edeb 100644 (file)
@@ -1,6 +1,11 @@
 --
 -- CREATE_TYPE
 --
+--
+-- Note: widget_in/out were created in create_function_1, without any
+-- prior shell-type creation.  These commands therefore complete a test
+-- of the "old style" approach of making the functions first.
+--
 CREATE TYPE widget (
    internallength = 24, 
    input = widget_in,
@@ -13,14 +18,27 @@ CREATE TYPE city_budget (
    output = int44out, 
    element = int4
 );
+-- Test creation and destruction of shell types
+CREATE TYPE shell;
+CREATE TYPE shell;   -- fail, type already present
+ERROR:  type "shell" already exists
+DROP TYPE shell;
+DROP TYPE shell;     -- fail, type not exist
+ERROR:  type "shell" does not exist
+--
 -- Test type-related default values (broken in releases before PG 7.2)
+--
+-- This part of the test also exercises the "new style" approach of making
+-- a shell type and then filling it in.
+--
+CREATE TYPE int42;
+CREATE TYPE text_w_default;
 -- Make dummy I/O routines using the existing internal support for int4, text
 CREATE FUNCTION int42_in(cstring)
    RETURNS int42
    AS 'int4in'
    LANGUAGE internal STRICT;
-NOTICE:  type "int42" is not yet defined
-DETAIL:  Creating a shell type definition.
+NOTICE:  return type int42 is only a shell
 CREATE FUNCTION int42_out(int42)
    RETURNS cstring
    AS 'int4out'
@@ -30,8 +48,7 @@ CREATE FUNCTION text_w_default_in(cstring)
    RETURNS text_w_default
    AS 'textin'
    LANGUAGE internal STRICT;
-NOTICE:  type "text_w_default" is not yet defined
-DETAIL:  Creating a shell type definition.
+NOTICE:  return type text_w_default is only a shell
 CREATE FUNCTION text_w_default_out(text_w_default)
    RETURNS cstring
    AS 'textout'
@@ -76,6 +93,9 @@ COMMENT ON TYPE bad IS 'bad comment';
 ERROR:  type "bad" does not exist
 COMMENT ON TYPE default_test_row IS 'good comment';
 COMMENT ON TYPE default_test_row IS NULL;
+-- Check shell type create for existing types
+CREATE TYPE text_w_default;            -- should fail
+ERROR:  type "text_w_default" already exists
 DROP TYPE default_test_row CASCADE;
 NOTICE:  drop cascades to function get_default_test()
 DROP TABLE default_test;
index 66d78c9..097d51f 100644 (file)
@@ -2,6 +2,11 @@
 -- CREATE_TYPE
 --
 
+--
+-- Note: widget_in/out were created in create_function_1, without any
+-- prior shell-type creation.  These commands therefore complete a test
+-- of the "old style" approach of making the functions first.
+--
 CREATE TYPE widget (
    internallength = 24, 
    input = widget_in,
@@ -16,7 +21,20 @@ CREATE TYPE city_budget (
    element = int4
 );
 
+-- Test creation and destruction of shell types
+CREATE TYPE shell;
+CREATE TYPE shell;   -- fail, type already present
+DROP TYPE shell;
+DROP TYPE shell;     -- fail, type not exist
+
+--
 -- Test type-related default values (broken in releases before PG 7.2)
+--
+-- This part of the test also exercises the "new style" approach of making
+-- a shell type and then filling it in.
+--
+CREATE TYPE int42;
+CREATE TYPE text_w_default;
 
 -- Make dummy I/O routines using the existing internal support for int4, text
 CREATE FUNCTION int42_in(cstring)
@@ -74,6 +92,9 @@ COMMENT ON TYPE bad IS 'bad comment';
 COMMENT ON TYPE default_test_row IS 'good comment';
 COMMENT ON TYPE default_test_row IS NULL;
 
+-- Check shell type create for existing types
+CREATE TYPE text_w_default;            -- should fail
+
 DROP TYPE default_test_row CASCADE;
 
 DROP TABLE default_test;