From 8e68d783902b0b47f377efa4a23a04ddeef272a8 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 28 Feb 2006 22:37:27 +0000 Subject: [PATCH] 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. --- doc/src/sgml/ref/create_type.sgml | 52 +++++++++++++++------- doc/src/sgml/xtypes.sgml | 21 +++++---- src/backend/catalog/pg_type.c | 74 ++++++++++++++++++------------- src/backend/commands/typecmds.c | 49 +++++++++++++------- src/backend/parser/gram.y | 11 ++++- src/backend/utils/adt/pseudotypes.c | 28 +++++++++++- src/include/catalog/catversion.h | 4 +- src/include/catalog/pg_operator.h | 6 +-- src/include/catalog/pg_proc.h | 8 +++- src/include/utils/builtins.h | 4 +- src/test/regress/expected/create_type.out | 28 ++++++++++-- src/test/regress/sql/create_type.sql | 21 +++++++++ 12 files changed, 220 insertions(+), 86 deletions(-) diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml index a39c244c6c..9382395182 100644 --- a/doc/src/sgml/ref/create_type.sgml +++ b/doc/src/sgml/ref/create_type.sgml @@ -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. @@ -458,16 +459,32 @@ CREATE TYPE name ( + 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, diff --git a/doc/src/sgml/xtypes.sgml b/doc/src/sgml/xtypes.sgml index 22d11a6300..95723360e7 100644 --- a/doc/src/sgml/xtypes.sgml +++ b/doc/src/sgml/xtypes.sgml @@ -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, diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index ab250b02ea..f6fbbef005 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -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, diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 143695252f..f8e1a2665c 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -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); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 6cb6f96fa4..a60d4157b2 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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); diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index 105598afcc..9893432827 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -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 */ +} diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 1a391bad3f..dbca22ea76 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -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 diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index a746bff271..84fb254f97 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -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 )); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index ec43235eef..4a9da19366 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -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_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 28a70d11ce..50f349abdf 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -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); diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out index 4e2d44d5c4..3e2edeb1e0 100644 --- a/src/test/regress/expected/create_type.out +++ b/src/test/regress/expected/create_type.out @@ -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; diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql index 66d78c9216..097d51fc92 100644 --- a/src/test/regress/sql/create_type.sql +++ b/src/test/regress/sql/create_type.sql @@ -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; -- 2.11.0