Commit 8e68d783 authored by Tom Lane's avatar Tom Lane

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.
parent 7f19339c
<!-- <!--
$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 PostgreSQL documentation
--> -->
...@@ -37,6 +37,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ( ...@@ -37,6 +37,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
[ , ELEMENT = <replaceable class="parameter">element</replaceable> ] [ , ELEMENT = <replaceable class="parameter">element</replaceable> ]
[ , DELIMITER = <replaceable class="parameter">delimiter</replaceable> ] [ , DELIMITER = <replaceable class="parameter">delimiter</replaceable> ]
) )
CREATE TYPE <replaceable class="parameter">name</replaceable>
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
...@@ -142,17 +144,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ( ...@@ -142,17 +144,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
<para> <para>
You should at this point be wondering how the input and output functions 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 can be declared to have results or arguments of the new type, when they
to be created before the new type can be created. The answer is that the have to be created before the new type can be created. The answer is that
input function must be created first, then the output function (and the type should first be defined as a <firstterm>shell type</>, which is a
the binary I/O functions if wanted), and finally the data type. placeholder type that has no properties except a name and an owner. This
<productname>PostgreSQL</productname> will first see the name of the new is done by issuing the command <literal>CREATE TYPE
data type as the return type of the input function. It will create a <replaceable>name</></literal>, with no additional parameters. Then the
<quote>shell</> type, which is simply a placeholder entry in I/O functions can be defined referencing the shell type. Finally,
the system catalog, and link the input function definition to the shell <command>CREATE TYPE</> with a full definition replaces the shell entry
type. Similarly the other functions will be linked to the (now already with a complete, valid type definition, after which the new type can be
existing) shell type. Finally, <command>CREATE TYPE</> replaces the used normally.
shell entry with a complete type definition, and the new type can be used.
</para> </para>
<para> <para>
...@@ -457,17 +458,33 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> ( ...@@ -457,17 +458,33 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
while converting it to or from external form. while converting it to or from external form.
</para> </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> <para>
In <productname>PostgreSQL</productname> versions before 7.3, it 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 functions' forward references to the type name with the placeholder
pseudotype <type>opaque</>. The <type>cstring</> arguments and pseudotype <type>opaque</>. The <type>cstring</> arguments and
results also had to be declared as <type>opaque</> before 7.3. To results also had to be declared as <type>opaque</> before 7.3. To
support loading of old dump files, <command>CREATE TYPE</> will support loading of old dump files, <command>CREATE TYPE</> will
accept functions declared using <type>opaque</>, but it will issue accept I/O functions declared using <type>opaque</>, but it will issue
a notice and change the function's declaration to use the correct a notice and change the function declarations to use the correct
types. types.
</para> </para>
</refsect1> </refsect1>
<refsect1> <refsect1>
...@@ -489,6 +506,11 @@ $$ LANGUAGE SQL; ...@@ -489,6 +506,11 @@ $$ LANGUAGE SQL;
This example creates the base data type <type>box</type> and then uses the This example creates the base data type <type>box</type> and then uses the
type in a table definition: type in a table definition:
<programlisting> <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 ( CREATE TYPE box (
INTERNALLENGTH = 16, INTERNALLENGTH = 16,
INPUT = my_box_in_function, INPUT = my_box_in_function,
......
<!-- <!--
$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"> <sect1 id="xtypes">
...@@ -168,8 +168,16 @@ complex_send(PG_FUNCTION_ARGS) ...@@ -168,8 +168,16 @@ complex_send(PG_FUNCTION_ARGS)
</para> </para>
<para> <para>
To define the <type>complex</type> type, we need to create the Once we have written the I/O functions and compiled them into a shared
user-defined I/O functions before creating the type: 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> <programlisting>
CREATE FUNCTION complex_in(cstring) CREATE FUNCTION complex_in(cstring)
...@@ -192,15 +200,10 @@ CREATE FUNCTION complex_send(complex) ...@@ -192,15 +200,10 @@ CREATE FUNCTION complex_send(complex)
AS '<replaceable>filename</replaceable>' AS '<replaceable>filename</replaceable>'
LANGUAGE C IMMUTABLE STRICT; LANGUAGE C IMMUTABLE STRICT;
</programlisting> </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>
<para> <para>
Finally, we can declare the data type: Finally, we can provide the full definition of the data type:
<programlisting> <programlisting>
CREATE TYPE complex ( CREATE TYPE complex (
internallength = 16, internallength = 16,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -20,8 +20,11 @@
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/typecmds.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/acl.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -29,14 +32,14 @@ ...@@ -29,14 +32,14 @@
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* TypeShellMake * TypeShellMake
* *
* This procedure inserts a "shell" tuple into the type * This procedure inserts a "shell" tuple into the pg_type relation.
* relation. The type tuple inserted has invalid values * The type tuple inserted has valid but dummy values, and its
* and in particular, the "typisdefined" field is false. * "typisdefined" field is false indicating it's not really defined.
* *
* This is used so that a tuple exists in the catalogs. * This is used so that a tuple exists in the catalogs. The I/O
* The invalid fields should be fixed up sometime after * functions for the type will link to this tuple. When the full
* this routine is called, and then the "typeisdefined" * CREATE TYPE command is issued, the bogus values will be replaced
* field is set to true. -cim 6/15/90 * with correct ones, and "typisdefined" will be set to true.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
Oid Oid
...@@ -70,30 +73,35 @@ TypeShellMake(const char *typeName, Oid typeNamespace) ...@@ -70,30 +73,35 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
/* /*
* initialize *values with the type name and dummy values * 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; i = 0;
namestrcpy(&name, typeName); namestrcpy(&name, typeName);
values[i++] = NameGetDatum(&name); /* typname */ values[i++] = NameGetDatum(&name); /* typname */
values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */ values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */ values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
values[i++] = Int16GetDatum(0); /* typlen */ values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */
values[i++] = BoolGetDatum(false); /* typbyval */ values[i++] = BoolGetDatum(true); /* typbyval */
values[i++] = CharGetDatum(0); /* typtype */ values[i++] = CharGetDatum('p'); /* typtype */
values[i++] = BoolGetDatum(false); /* typisdefined */ values[i++] = BoolGetDatum(false); /* typisdefined */
values[i++] = CharGetDatum(0); /* typdelim */ values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typinput */ values[i++] = ObjectIdGetDatum(F_SHELL_IN); /* typinput */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typoutput */ values[i++] = ObjectIdGetDatum(F_SHELL_OUT); /* typoutput */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typsend */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typsend */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typanalyze */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typanalyze */
values[i++] = CharGetDatum('i'); /* typalign */ values[i++] = CharGetDatum('i'); /* typalign */
values[i++] = CharGetDatum('p'); /* typstorage */ values[i++] = CharGetDatum('p'); /* typstorage */
values[i++] = BoolGetDatum(false); /* typnotnull */ values[i++] = BoolGetDatum(false); /* typnotnull */
values[i++] = ObjectIdGetDatum(InvalidOid); /* typbasetype */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typbasetype */
values[i++] = Int32GetDatum(-1); /* typtypmod */ values[i++] = Int32GetDatum(-1); /* typtypmod */
values[i++] = Int32GetDatum(0); /* typndims */ values[i++] = Int32GetDatum(0); /* typndims */
nulls[i++] = 'n'; /* typdefaultbin */ nulls[i++] = 'n'; /* typdefaultbin */
nulls[i++] = 'n'; /* typdefault */ nulls[i++] = 'n'; /* typdefault */
...@@ -118,8 +126,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace) ...@@ -118,8 +126,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
InvalidOid, InvalidOid,
0, 0,
GetUserId(), GetUserId(),
InvalidOid, F_SHELL_IN,
InvalidOid, F_SHELL_OUT,
InvalidOid, InvalidOid,
InvalidOid, InvalidOid,
InvalidOid, InvalidOid,
...@@ -289,7 +297,13 @@ TypeCreate(const char *typeName, ...@@ -289,7 +297,13 @@ TypeCreate(const char *typeName,
errmsg("type \"%s\" already exists", 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, tup = heap_modifytuple(tup,
RelationGetDescr(pg_type_desc), RelationGetDescr(pg_type_desc),
...@@ -350,8 +364,6 @@ TypeCreate(const char *typeName, ...@@ -350,8 +364,6 @@ TypeCreate(const char *typeName,
* If rebuild is true, we remove existing dependencies and rebuild them * If rebuild is true, we remove existing dependencies and rebuild them
* from scratch. This is needed for ALTER TYPE, and also when replacing * from scratch. This is needed for ALTER TYPE, and also when replacing
* a shell type. * a shell type.
*
* NOTE: a shell type will have a dependency to its namespace, and no others.
*/ */
void void
GenerateTypeDependencies(Oid typeNamespace, GenerateTypeDependencies(Oid typeNamespace,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
...@@ -138,6 +138,37 @@ DefineType(List *names, List *parameters) ...@@ -138,6 +138,37 @@ DefineType(List *names, List *parameters)
errmsg("type names must be %d characters or less", errmsg("type names must be %d characters or less",
NAMEDATALEN - 2))); 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) foreach(pl, parameters)
{ {
DefElem *defel = (DefElem *) lfirst(pl); DefElem *defel = (DefElem *) lfirst(pl);
...@@ -240,22 +271,6 @@ DefineType(List *names, List *parameters) ...@@ -240,22 +271,6 @@ DefineType(List *names, List *parameters)
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("type output function must be specified"))); 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 * Convert I/O proc names to OIDs
*/ */
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -2690,6 +2690,15 @@ DefineStmt: ...@@ -2690,6 +2690,15 @@ DefineStmt:
n->definition = $4; n->definition = $4;
$$ = (Node *)n; $$ = (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 ')' | CREATE TYPE_P any_name AS '(' TableFuncElementList ')'
{ {
CompositeTypeStmt *n = makeNode(CompositeTypeStmt); CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -321,3 +321,29 @@ anyelement_out(PG_FUNCTION_ARGS)
PG_RETURN_VOID(); /* keep compiler quiet */ 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 */
}
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200602251 #define CATALOG_VERSION_NO 200602281
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * 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 ...@@ -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 = 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 = 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 = 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 #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 = 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 )); DATA(insert OID = 411 ( "<>" PGNSP PGUID b f 20 20 16 411 410 0 0 0 0 int8ne neqsel neqjoinsel ));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * 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 ...@@ -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"); 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_ )); 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"); 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"); 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_ )); 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" ...@@ -3321,6 +3321,10 @@ DATA(insert OID = 2312 ( anyelement_in PGNSP PGUID 12 f f t f i 1 2283 "2275"
DESCR("I/O"); 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_ )); 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"); 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 */ /* cryptographic */
DATA(insert OID = 2311 ( md5 PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_ md5_text - _null_ )); DATA(insert OID = 2311 ( md5 PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_ md5_text - _null_ ));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -443,6 +443,8 @@ extern Datum opaque_in(PG_FUNCTION_ARGS);
extern Datum opaque_out(PG_FUNCTION_ARGS); extern Datum opaque_out(PG_FUNCTION_ARGS);
extern Datum anyelement_in(PG_FUNCTION_ARGS); extern Datum anyelement_in(PG_FUNCTION_ARGS);
extern Datum anyelement_out(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 */ /* regexp.c */
extern Datum nameregexeq(PG_FUNCTION_ARGS); extern Datum nameregexeq(PG_FUNCTION_ARGS);
......
-- --
-- CREATE_TYPE -- 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 ( CREATE TYPE widget (
internallength = 24, internallength = 24,
input = widget_in, input = widget_in,
...@@ -13,14 +18,27 @@ CREATE TYPE city_budget ( ...@@ -13,14 +18,27 @@ CREATE TYPE city_budget (
output = int44out, output = int44out,
element = int4 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) -- 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 -- Make dummy I/O routines using the existing internal support for int4, text
CREATE FUNCTION int42_in(cstring) CREATE FUNCTION int42_in(cstring)
RETURNS int42 RETURNS int42
AS 'int4in' AS 'int4in'
LANGUAGE internal STRICT; LANGUAGE internal STRICT;
NOTICE: type "int42" is not yet defined NOTICE: return type int42 is only a shell
DETAIL: Creating a shell type definition.
CREATE FUNCTION int42_out(int42) CREATE FUNCTION int42_out(int42)
RETURNS cstring RETURNS cstring
AS 'int4out' AS 'int4out'
...@@ -30,8 +48,7 @@ CREATE FUNCTION text_w_default_in(cstring) ...@@ -30,8 +48,7 @@ CREATE FUNCTION text_w_default_in(cstring)
RETURNS text_w_default RETURNS text_w_default
AS 'textin' AS 'textin'
LANGUAGE internal STRICT; LANGUAGE internal STRICT;
NOTICE: type "text_w_default" is not yet defined NOTICE: return type text_w_default is only a shell
DETAIL: Creating a shell type definition.
CREATE FUNCTION text_w_default_out(text_w_default) CREATE FUNCTION text_w_default_out(text_w_default)
RETURNS cstring RETURNS cstring
AS 'textout' AS 'textout'
...@@ -76,6 +93,9 @@ COMMENT ON TYPE bad IS 'bad comment'; ...@@ -76,6 +93,9 @@ COMMENT ON TYPE bad IS 'bad comment';
ERROR: type "bad" does not exist ERROR: type "bad" does not exist
COMMENT ON TYPE default_test_row IS 'good comment'; COMMENT ON TYPE default_test_row IS 'good comment';
COMMENT ON TYPE default_test_row IS NULL; 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; DROP TYPE default_test_row CASCADE;
NOTICE: drop cascades to function get_default_test() NOTICE: drop cascades to function get_default_test()
DROP TABLE default_test; DROP TABLE default_test;
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
-- CREATE_TYPE -- 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 ( CREATE TYPE widget (
internallength = 24, internallength = 24,
input = widget_in, input = widget_in,
...@@ -16,7 +21,20 @@ CREATE TYPE city_budget ( ...@@ -16,7 +21,20 @@ CREATE TYPE city_budget (
element = int4 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) -- 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 -- Make dummy I/O routines using the existing internal support for int4, text
CREATE FUNCTION int42_in(cstring) CREATE FUNCTION int42_in(cstring)
...@@ -74,6 +92,9 @@ COMMENT ON TYPE bad IS 'bad comment'; ...@@ -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 'good comment';
COMMENT ON TYPE default_test_row IS NULL; 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 TYPE default_test_row CASCADE;
DROP TABLE default_test; DROP TABLE default_test;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment