Index: doc/src/sgml/xtypes.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/xtypes.sgml,v
retrieving revision 1.25
diff -c -r1.25 xtypes.sgml
*** doc/src/sgml/xtypes.sgml 10 Jan 2005 00:04:38 -0000 1.25
--- doc/src/sgml/xtypes.sgml 21 Feb 2006 10:30:54 -0000
***************
*** 168,175 ****
! To define the complex type, we need to create the
! user-defined I/O functions before creating the type:
CREATE FUNCTION complex_in(cstring)
--- 168,180 ----
! To define the complex type, we first declare it as a shell type:
!
!
! CREATE TYPE complex;
!
!
! Then we create the user-defined I/O functions needed to create the type:
CREATE FUNCTION complex_in(cstring)
***************
*** 193,206 ****
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:
CREATE TYPE complex (
internallength = 16,
--- 198,207 ----
LANGUAGE C IMMUTABLE STRICT;
! Finally, we can declare the data type properly:
CREATE TYPE complex (
internallength = 16,
Index: doc/src/sgml/ref/create_type.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v
retrieving revision 1.60
diff -c -r1.60 create_type.sgml
*** doc/src/sgml/ref/create_type.sgml 13 Jan 2006 18:06:45 -0000 1.60
--- doc/src/sgml/ref/create_type.sgml 21 Feb 2006 10:30:54 -0000
***************
*** 23,29 ****
CREATE TYPE name AS
( attribute_name data_type [, ... ] )
! CREATE TYPE name (
INPUT = input_function,
OUTPUT = output_function
[ , RECEIVE = receive_function ]
--- 23,29 ----
CREATE TYPE name AS
( attribute_name data_type [, ... ] )
! CREATE TYPE name [ (
INPUT = input_function,
OUTPUT = output_function
[ , RECEIVE = receive_function ]
***************
*** 36,42 ****
[ , DEFAULT = default ]
[ , ELEMENT = element ]
[ , DELIMITER = delimiter ]
! )
--- 36,42 ----
[ , DEFAULT = default ]
[ , ELEMENT = element ]
[ , DELIMITER = delimiter ]
! ) ]
***************
*** 142,158 ****
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.
--- 142,157 ----
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 the entire declaration portion of the type is optional. If you
! just issue the command CREATE TYPE foo>, it will create a
! shell> type, which is simply a placeholder entry in the system
! catalog. With the shell type in place, you can create the necessary
! functions. Finally, CREATE TYPE> with a full definition
! replaces the shell entry with a complete type definition and the new
! type can be used. Note that many procedural languages do not allow you to
! create functions that create or return shell types.
***************
*** 468,473 ****
--- 467,485 ----
a notice and change the function's declaration to use the correct
types.
+
+
+ Prior to version 8.2, you could not explicitly create shell types, but an
+ alternate way to create shell types was provided. For this to work 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 and create the shell
+ type. This workaround only works for types where the type input function
+ is of language C> or internal>.
+
+
+
Index: src/backend/catalog/pg_type.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/pg_type.c,v
retrieving revision 1.104
diff -c -r1.104 pg_type.c
*** src/backend/catalog/pg_type.c 15 Oct 2005 02:49:14 -0000 1.104
--- src/backend/catalog/pg_type.c 21 Feb 2006 10:30:55 -0000
***************
*** 76,90 ****
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 */
--- 76,90 ----
values[i++] = NameGetDatum(&name); /* typname */
values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
! values[i++] = Int16GetDatum(4); /* typlen */
! values[i++] = BoolGetDatum(true); /* typbyval */
! values[i++] = CharGetDatum('p'); /* typtype */
values[i++] = BoolGetDatum(false); /* typisdefined */
! values[i++] = CharGetDatum('\054'); /* typdelim */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */
! values[i++] = ObjectIdGetDatum(2398); /* typinput */
! values[i++] = ObjectIdGetDatum(2399); /* typoutput */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typsend */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typanalyze */
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.86
diff -c -r1.86 typecmds.c
*** src/backend/commands/typecmds.c 13 Jan 2006 18:06:45 -0000 1.86
--- src/backend/commands/typecmds.c 21 Feb 2006 10:30:56 -0000
***************
*** 229,246 ****
}
/*
- * make sure we have our required definitions
- */
- if (inputName == NIL)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("type input function must be specified")));
- if (outputName == NIL)
- ereport(ERROR,
- (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.
--- 229,234 ----
***************
*** 255,260 ****
--- 243,264 ----
/* Make new shell type visible for modification below */
CommandCounterIncrement();
}
+
+ /* Shell type definition, we're done */
+ if( parameters == NULL )
+ return;
+
+ /*
+ * make sure we have our required definitions
+ */
+ if (inputName == NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("type input function must be specified")));
+ if (outputName == NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("type output function must be specified")));
/*
* Convert I/O proc names to OIDs
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.530
diff -c -r2.530 gram.y
*** src/backend/parser/gram.y 19 Feb 2006 00:04:27 -0000 2.530
--- src/backend/parser/gram.y 21 Feb 2006 10:31:01 -0000
***************
*** 2690,2695 ****
--- 2690,2703 ----
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 = NULL;
+ $$ = (Node *)n;
+ }
| CREATE TYPE_P any_name AS '(' TableFuncElementList ')'
{
CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
Index: src/backend/utils/adt/pseudotypes.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/pseudotypes.c,v
retrieving revision 1.15
diff -c -r1.15 pseudotypes.c
*** src/backend/utils/adt/pseudotypes.c 31 Dec 2004 22:01:22 -0000 1.15
--- src/backend/utils/adt/pseudotypes.c 21 Feb 2006 10:31:01 -0000
***************
*** 321,323 ****
--- 321,350 ----
PG_RETURN_VOID(); /* keep compiler quiet */
}
+
+ /*
+ * shell_in - input routine for shell-type.
+ */
+ 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-type.
+ */
+ 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: src/include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.397
diff -c -r1.397 pg_proc.h
*** src/include/catalog/pg_proc.h 12 Feb 2006 03:22:19 -0000 1.397
--- src/include/catalog/pg_proc.h 21 Feb 2006 10:31:06 -0000
***************
*** 3319,3324 ****
--- 3319,3328 ----
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: src/test/regress/expected/create_type.out
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/create_type.out,v
retrieving revision 1.11
diff -c -r1.11 create_type.out
*** src/test/regress/expected/create_type.out 21 Nov 2003 22:32:49 -0000 1.11
--- src/test/regress/expected/create_type.out 21 Feb 2006 10:31:07 -0000
***************
*** 13,26 ****
output = int44out,
element = int4
);
-- Test type-related default values (broken in releases before PG 7.2)
-- Make dummy I/O routines using the existing internal support for int4, text
CREATE FUNCTION int42_in(cstring)
RETURNS int42
AS 'int4in'
LANGUAGE 'internal' WITH (isStrict);
! NOTICE: type "int42" is not yet defined
! DETAIL: Creating a shell type definition.
CREATE FUNCTION int42_out(int42)
RETURNS cstring
AS 'int4out'
--- 13,32 ----
output = int44out,
element = int4
);
+ -- Test creation and destruction of shell types
+ CREATE TYPE shell;
+ CREATE TYPE shell; -- succeed, no error
+ 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)
+ CREATE TYPE int42;
-- Make dummy I/O routines using the existing internal support for int4, text
CREATE FUNCTION int42_in(cstring)
RETURNS int42
AS 'int4in'
LANGUAGE 'internal' WITH (isStrict);
! NOTICE: return type int42 is only a shell
CREATE FUNCTION int42_out(int42)
RETURNS cstring
AS 'int4out'
***************
*** 76,81 ****
--- 82,89 ----
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;
DROP TYPE default_test_row CASCADE;
NOTICE: drop cascades to function get_default_test()
DROP TABLE default_test;
Index: src/test/regress/sql/create_type.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/create_type.sql,v
retrieving revision 1.7
diff -c -r1.7 create_type.sql
*** src/test/regress/sql/create_type.sql 21 Nov 2003 22:32:49 -0000 1.7
--- src/test/regress/sql/create_type.sql 21 Feb 2006 10:31:07 -0000
***************
*** 16,22 ****
--- 16,29 ----
element = int4
);
+ -- Test creation and destruction of shell types
+ CREATE TYPE shell;
+ CREATE TYPE shell; -- succeed, no error
+ DROP TYPE shell;
+ DROP TYPE shell; -- fail, type not exist
+
-- Test type-related default values (broken in releases before PG 7.2)
+ CREATE TYPE int42;
-- Make dummy I/O routines using the existing internal support for int4, text
CREATE FUNCTION int42_in(cstring)
***************
*** 74,79 ****
--- 81,89 ----
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;
+
DROP TYPE default_test_row CASCADE;
DROP TABLE default_test;