Allow the syntax CREATE TYPE foo, with no parameters, to permit explicit

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.
This commit is contained in:
Tom Lane 2006-02-28 22:37:27 +00:00
parent 7f19339cca
commit 8e68d78390
12 changed files with 220 additions and 86 deletions

View 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>
@ -457,17 +458,33 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
while converting it to or from external form.
</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,

View 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,

View 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 $
*
*-------------------------------------------------------------------------
*/
@ -20,8 +20,11 @@
#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"
@ -29,14 +32,14 @@
/* ----------------------------------------------------------------
* 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,

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

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

View 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 */
}

View 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

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

View 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_ ));

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

View 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;

View 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;