Allow the syntax CREATE TYPE foo, with no parameters, to permit explicit
authorTom Lane
Tue, 28 Feb 2006 22:37:27 +0000 (22:37 +0000)
committerTom Lane
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 a39c244c6c7d524c2e5047b4ba32d3d63ca8978d..9382395182a9776ef9b677e911c452338a000f02 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -37,6 +37,8 @@ CREATE TYPE name (
     [ , ELEMENT = element ]
     [ , DELIMITER = delimiter ]
 )
+
+CREATE TYPE name
 
  
 
@@ -142,17 +144,16 @@ CREATE TYPE name (
 
   
    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.
-   PostgreSQL will first see the name of the new
-   data type as the return type of the input function.  It will create a
-   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, 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 shell type, which is a
+   placeholder type that has no properties except a name and an owner.  This
+   is done by issuing the command CREATE TYPE
+   name, with no additional parameters.  Then the
+   I/O functions can be defined referencing the shell type.  Finally,
+   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.
   
 
   
@@ -457,17 +458,33 @@ CREATE TYPE name (
    while converting it to or from external form.
   
 
+  
+   Before PostgreSQL version 8.2, the syntax
+   CREATE TYPE name did not exist.
+   The way to create a new base type was to create its input function first.
+   In this approach, PostgreSQL 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.
+  
+
   
    In PostgreSQL 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 opaque.  The cstring arguments and
    results also had to be declared as opaque before 7.3.  To
    support loading of old dump files, CREATE TYPE will
-   accept functions declared using opaque, but it will issue
-   a notice and change the function's declaration to use the correct
+   accept I/O functions declared using opaque, but it will issue
+   a notice and change the function declarations to use the correct
    types.
   
+
  
  
  
@@ -489,6 +506,11 @@ $$ LANGUAGE SQL;
    This example creates the base data type box and then uses the
    type in a table definition:
 
+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 22d11a6300be67756f273d5763e507630eb4296a..95723360e70f512e846bb130e13d3fd27f7b9234 100644 (file)
@@ -1,5 +1,5 @@
 
 
  
@@ -168,8 +168,16 @@ complex_send(PG_FUNCTION_ARGS)
  
 
  
-  To define the complex 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 complex type in SQL.
+  First we declare it as a shell type:
+
+
+CREATE TYPE complex;
+
+
+  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:
 
 
 CREATE FUNCTION complex_in(cstring)
@@ -192,15 +200,10 @@ CREATE FUNCTION complex_send(complex)
    AS 'filename'
    LANGUAGE C IMMUTABLE STRICT;
 
-
-  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.
  
 
  
-  Finally, we can declare the data type:
+  Finally, we can provide the full definition of the data type:
 
 CREATE TYPE complex (
    internallength = 16, 
index ab250b02ea9aa77246e85f1f05693507e51b0be1..f6fbbef005ef1292675541111541c1bbe6511a49 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 143695252f4290a4f8a9742573c3c0d4b7182e24..f8e1a2665cfe79bba05f15a10153ffa5e154f61c 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);
@@ -240,22 +271,6 @@ DefineType(List *names, List *parameters)
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 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
     */
index 6cb6f96fa4f5ea7480d2f42d0b6b2c29384e1b09..a60d4157b2ef64faf8f652e9d363ba06eaf78499 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 105598afcce1d548e9093ed48d137cbd5e7d7a14..98934328271e909e5fc9e1ae798afc3153a75a0f 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 1a391bad3f3994388a6bc486080df396cc351ac0..dbca22ea76125d262a5f5c1b2b46726b7dd9b1ff 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 a746bff271191487bfa9889e884ed2146336249c..84fb254f97b3ddbcaaa6dee46b34d1752c9b7d96 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 ec43235eef3ab5a0e82fabbcfb687d6e187d1dac..4a9da19366ebd64d9e93008b37091eb21a91a35e 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 28a70d11ce7515edf350ee960384a8587c405f85..50f349abdfd3e60490ad90e47546f146b01ae2c0 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 4e2d44d5c41cd0b519699af11307c9e0ba537b2a..3e2edeb1e0b6ff20482a42a30b61f7a3c6380c57 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 66d78c9216b9d7647d882979cfeeff807e79a5d3..097d51fc925685dd8590ee2d2deb2a998a7f0726 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;