mirror of
https://github.com/postgres/postgres.git
synced 2025-06-08 00:01:54 -04:00
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:
parent
7f19339cca
commit
8e68d78390
@ -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
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -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> (
|
|||||||
|
|
||||||
<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> (
|
|||||||
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;
|
|||||||
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,
|
||||||
|
@ -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">
|
<sect1 id="xtypes">
|
||||||
@ -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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
#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 @@
|
|||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* 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,21 +73,26 @@ 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 */
|
||||||
@ -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,
|
|||||||
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,
|
|||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
(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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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:
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
* 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 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200602251
|
#define CATALOG_VERSION_NO 200602281
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -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
|
|||||||
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 @@
|
|||||||
* 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
|
|||||||
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"
|
|||||||
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 @@
|
|||||||
* 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);
|
|||||||
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);
|
||||||
|
@ -1,6 +1,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,
|
||||||
@ -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)
|
|||||||
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';
|
|||||||
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 @@
|
|||||||
-- 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 (
|
|||||||
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';
|
|||||||
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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user