Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8e68d78

Browse files
committed
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 withthe mutual dependency between a datatype and its I/O functions: make ashell type, then make the functions, then define the datatype fully.We should fix pg_dump to handle things this way, but this commit just dealswith the backend.Martijn van Oosterhout, with some corrections by Tom Lane.
1 parent7f19339 commit8e68d78

File tree

12 files changed

+220
-86
lines changed

12 files changed

+220
-86
lines changed

‎doc/src/sgml/ref/create_type.sgml

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.60 2006/01/13 18:06:45 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.61 2006/02/28 22:37:25 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -37,6 +37,8 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
3737
[ , ELEMENT = <replaceable class="parameter">element</replaceable> ]
3838
[ , DELIMITER = <replaceable class="parameter">delimiter</replaceable> ]
3939
)
40+
41+
CREATE TYPE <replaceable class="parameter">name</replaceable>
4042
</synopsis>
4143
</refsynopsisdiv>
4244

@@ -142,17 +144,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
142144

143145
<para>
144146
You should at this point be wondering how the input and output functions
145-
can be declared to have results or arguments of the new type, when they have
146-
to be created before the new type can be created. The answer is that the
147-
input function must be created first, then the output function (and
148-
the binary I/O functions if wanted), and finally the data type.
149-
<productname>PostgreSQL</productname> will first see the name of the new
150-
data type as the return type of the input function. It will create a
151-
<quote>shell</> type, which is simply a placeholder entry in
152-
the system catalog, and link the input function definition to the shell
153-
type. Similarly the other functions will be linked to the (now already
154-
existing) shell type. Finally, <command>CREATE TYPE</> replaces the
155-
shell entry with a complete type definition, and the new type can be used.
147+
can be declared to have results or arguments of the new type, when they
148+
have to be created before the new type can be created. The answer is that
149+
the type should first be defined as a <firstterm>shell type</>, which is a
150+
placeholder type that has no properties except a name and an owner. This
151+
is done by issuing the command <literal>CREATE TYPE
152+
<replaceable>name</></literal>, with no additional parameters. Then the
153+
I/O functions can be defined referencing the shell type. Finally,
154+
<command>CREATE TYPE</> with a full definition replaces the shell entry
155+
with a complete, valid type definition, after which the new type can be
156+
used normally.
156157
</para>
157158

158159
<para>
@@ -457,17 +458,33 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
457458
while converting it to or from external form.
458459
</para>
459460

461+
<para>
462+
Before <productname>PostgreSQL</productname> version 8.2, the syntax
463+
<literal>CREATE TYPE <replaceable>name</></literal> did not exist.
464+
The way to create a new base type was to create its input function first.
465+
In this approach, <productname>PostgreSQL</productname> will first see
466+
the name of the new data type as the return type of the input function.
467+
The shell type is implicitly created in this situation, and then it
468+
can be referenced in the definitions of the remaining I/O functions.
469+
This approach still works, but is deprecated and may be disallowed in
470+
some future release. Also, to avoid accidentally cluttering
471+
the catalogs with shell types as a result of simple typos in function
472+
definitions, a shell type will only be made this way when the input
473+
function is written in C.
474+
</para>
475+
460476
<para>
461477
In <productname>PostgreSQL</productname> versions before 7.3, it
462-
was customary to avoid creating a shell type by replacing the
478+
was customary to avoid creating a shell typeat all,by replacing the
463479
functions' forward references to the type name with the placeholder
464480
pseudotype <type>opaque</>. The <type>cstring</> arguments and
465481
results also had to be declared as <type>opaque</> before 7.3. To
466482
support loading of old dump files, <command>CREATE TYPE</> will
467-
accept functions declared using <type>opaque</>, but it will issue
468-
a notice and change the function's declaration to use the correct
483+
acceptI/Ofunctions declared using <type>opaque</>, but it will issue
484+
a notice and change the function declarations to use the correct
469485
types.
470486
</para>
487+
471488
</refsect1>
472489

473490
<refsect1>
@@ -489,6 +506,11 @@ $$ LANGUAGE SQL;
489506
This example creates the base data type <type>box</type> and then uses the
490507
type in a table definition:
491508
<programlisting>
509+
CREATE TYPE box;
510+
511+
CREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ;
512+
CREATE FUNCTION my_box_out_function(box) RETURNS cstring AS ... ;
513+
492514
CREATE TYPE box (
493515
INTERNALLENGTH = 16,
494516
INPUT = my_box_in_function,

‎doc/src/sgml/xtypes.sgml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/xtypes.sgml,v 1.25 2005/01/10 00:04:38 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/xtypes.sgml,v 1.26 2006/02/28 22:37:25 tgl Exp $
33
-->
44

55
<sect1 id="xtypes">
@@ -168,8 +168,16 @@ complex_send(PG_FUNCTION_ARGS)
168168
</para>
169169

170170
<para>
171-
To define the <type>complex</type> type, we need to create the
172-
user-defined I/O functions before creating the type:
171+
Once we have written the I/O functions and compiled them into a shared
172+
library, we can define the <type>complex</type> type in SQL.
173+
First we declare it as a shell type:
174+
175+
<programlisting>
176+
CREATE TYPE complex;
177+
</programlisting>
178+
179+
This serves as a placeholder that allows us to reference the type while
180+
defining its I/O functions. Now we can define the I/O functions:
173181

174182
<programlisting>
175183
CREATE FUNCTION complex_in(cstring)
@@ -192,15 +200,10 @@ CREATE FUNCTION complex_send(complex)
192200
AS '<replaceable>filename</replaceable>'
193201
LANGUAGE C IMMUTABLE STRICT;
194202
</programlisting>
195-
196-
Notice that the declarations of the input and output functions must
197-
reference the not-yet-defined type. This is allowed, but will draw
198-
warning messages that may be ignored. The input function must
199-
appear first.
200203
</para>
201204

202205
<para>
203-
Finally, we candeclare the data type:
206+
Finally, we canprovide the full definition of the data type:
204207
<programlisting>
205208
CREATE TYPE complex (
206209
internallength = 16,

‎src/backend/catalog/pg_type.c

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.104 2005/10/15 02:49:14 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.105 2006/02/28 22:37:25 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -20,23 +20,26 @@
2020
#include"catalog/pg_namespace.h"
2121
#include"catalog/pg_proc.h"
2222
#include"catalog/pg_type.h"
23+
#include"commands/typecmds.h"
2324
#include"miscadmin.h"
25+
#include"utils/acl.h"
2426
#include"utils/builtins.h"
27+
#include"utils/fmgroids.h"
2528
#include"utils/lsyscache.h"
2629
#include"utils/syscache.h"
2730

2831

2932
/* ----------------------------------------------------------------
3033
*TypeShellMake
3134
*
32-
*This procedure inserts a "shell" tuple into thetype
33-
*relation.The type tuple inserted hasinvalidvalues
34-
*and in particular, the"typisdefined" field is false.
35+
*This procedure inserts a "shell" tuple into thepg_type relation.
36+
*The type tuple inserted hasvalid but dummyvalues, and its
37+
*"typisdefined" field is false indicating it's not really defined.
3538
*
36-
*This is used so that a tuple exists in the catalogs.
37-
*The invalid fields should be fixed up sometime after
38-
*this routineiscalled, and then the "typeisdefined"
39-
*field isset to true. -cim 6/15/90
39+
*This is used so that a tuple exists in the catalogs. The I/O
40+
*functions for the type will link to this tuple. When the full
41+
*CREATE TYPE commandisissued, the bogus values will be replaced
42+
*with correct ones, and "typisdefined" will beset to true.
4043
* ----------------------------------------------------------------
4144
*/
4245
Oid
@@ -70,30 +73,35 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
7073

7174
/*
7275
* initialize *values with the type name and dummy values
76+
*
77+
* The representational details are the same as int4 ... it doesn't
78+
* really matter what they are so long as they are consistent. Also
79+
* note that we give it typtype = 'p' (pseudotype) as extra insurance
80+
* that it won't be mistaken for a usable type.
7381
*/
7482
i=0;
7583
namestrcpy(&name,typeName);
7684
values[i++]=NameGetDatum(&name);/* typname */
7785
values[i++]=ObjectIdGetDatum(typeNamespace);/* typnamespace */
7886
values[i++]=ObjectIdGetDatum(GetUserId());/* typowner */
79-
values[i++]=Int16GetDatum(0);/* typlen */
80-
values[i++]=BoolGetDatum(false);/* typbyval */
81-
values[i++]=CharGetDatum(0);/* typtype */
82-
values[i++]=BoolGetDatum(false);/* typisdefined */
83-
values[i++]=CharGetDatum(0);/* typdelim */
84-
values[i++]=ObjectIdGetDatum(InvalidOid);/* typrelid */
85-
values[i++]=ObjectIdGetDatum(InvalidOid);/* typelem */
86-
values[i++]=ObjectIdGetDatum(InvalidOid);/* typinput */
87-
values[i++]=ObjectIdGetDatum(InvalidOid);/* typoutput */
88-
values[i++]=ObjectIdGetDatum(InvalidOid);/* typreceive */
89-
values[i++]=ObjectIdGetDatum(InvalidOid);/* typsend */
90-
values[i++]=ObjectIdGetDatum(InvalidOid);/* typanalyze */
91-
values[i++]=CharGetDatum('i');/* typalign */
92-
values[i++]=CharGetDatum('p');/* typstorage */
93-
values[i++]=BoolGetDatum(false);/* typnotnull */
94-
values[i++]=ObjectIdGetDatum(InvalidOid);/* typbasetype */
95-
values[i++]=Int32GetDatum(-1);/* typtypmod */
96-
values[i++]=Int32GetDatum(0);/* typndims */
87+
values[i++]=Int16GetDatum(sizeof(int4));/* typlen */
88+
values[i++]=BoolGetDatum(true);/* typbyval */
89+
values[i++]=CharGetDatum('p');/* typtype */
90+
values[i++]=BoolGetDatum(false);/* typisdefined */
91+
values[i++]=CharGetDatum(DEFAULT_TYPDELIM);/* typdelim */
92+
values[i++]=ObjectIdGetDatum(InvalidOid);/* typrelid */
93+
values[i++]=ObjectIdGetDatum(InvalidOid);/* typelem */
94+
values[i++]=ObjectIdGetDatum(F_SHELL_IN);/* typinput */
95+
values[i++]=ObjectIdGetDatum(F_SHELL_OUT);/* typoutput */
96+
values[i++]=ObjectIdGetDatum(InvalidOid);/* typreceive */
97+
values[i++]=ObjectIdGetDatum(InvalidOid);/* typsend */
98+
values[i++]=ObjectIdGetDatum(InvalidOid);/* typanalyze */
99+
values[i++]=CharGetDatum('i');/* typalign */
100+
values[i++]=CharGetDatum('p');/* typstorage */
101+
values[i++]=BoolGetDatum(false);/* typnotnull */
102+
values[i++]=ObjectIdGetDatum(InvalidOid);/* typbasetype */
103+
values[i++]=Int32GetDatum(-1);/* typtypmod */
104+
values[i++]=Int32GetDatum(0);/* typndims */
97105
nulls[i++]='n';/* typdefaultbin */
98106
nulls[i++]='n';/* typdefault */
99107

@@ -118,8 +126,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
118126
InvalidOid,
119127
0,
120128
GetUserId(),
121-
InvalidOid,
122-
InvalidOid,
129+
F_SHELL_IN,
130+
F_SHELL_OUT,
123131
InvalidOid,
124132
InvalidOid,
125133
InvalidOid,
@@ -289,7 +297,13 @@ TypeCreate(const char *typeName,
289297
errmsg("type \"%s\" already exists",typeName)));
290298

291299
/*
292-
* Okay to update existing "shell" type tuple
300+
* shell type must have been created by same owner
301+
*/
302+
if (((Form_pg_type)GETSTRUCT(tup))->typowner!=GetUserId())
303+
aclcheck_error(ACLCHECK_NOT_OWNER,ACL_KIND_TYPE,typeName);
304+
305+
/*
306+
* Okay to update existing shell type tuple
293307
*/
294308
tup=heap_modifytuple(tup,
295309
RelationGetDescr(pg_type_desc),
@@ -350,8 +364,6 @@ TypeCreate(const char *typeName,
350364
* If rebuild is true, we remove existing dependencies and rebuild them
351365
* from scratch. This is needed for ALTER TYPE, and also when replacing
352366
* a shell type.
353-
*
354-
* NOTE: a shell type will have a dependency to its namespace, and no others.
355367
*/
356368
void
357369
GenerateTypeDependencies(OidtypeNamespace,

‎src/backend/commands/typecmds.c

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.86 2006/01/13 18:06:45 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.87 2006/02/28 22:37:26 tgl Exp $
1212
*
1313
* DESCRIPTION
1414
* The "DefineFoo" routines take the parse tree and pick out the
@@ -138,6 +138,37 @@ DefineType(List *names, List *parameters)
138138
errmsg("type names must be %d characters or less",
139139
NAMEDATALEN-2)));
140140

141+
/*
142+
* Look to see if type already exists (presumably as a shell; if not,
143+
* TypeCreate will complain). If it doesn't, create it as a shell, so
144+
* that the OID is known for use in the I/O function definitions.
145+
*/
146+
typoid=GetSysCacheOid(TYPENAMENSP,
147+
CStringGetDatum(typeName),
148+
ObjectIdGetDatum(typeNamespace),
149+
0,0);
150+
if (!OidIsValid(typoid))
151+
{
152+
typoid=TypeShellMake(typeName,typeNamespace);
153+
/* Make new shell type visible for modification below */
154+
CommandCounterIncrement();
155+
156+
/*
157+
* If the command was a parameterless CREATE TYPE, we're done ---
158+
* creating the shell type was all we're supposed to do.
159+
*/
160+
if (parameters==NIL)
161+
return;
162+
}
163+
else
164+
{
165+
/* Complain if dummy CREATE TYPE and entry already exists */
166+
if (parameters==NIL)
167+
ereport(ERROR,
168+
(errcode(ERRCODE_DUPLICATE_OBJECT),
169+
errmsg("type \"%s\" already exists",typeName)));
170+
}
171+
141172
foreach(pl,parameters)
142173
{
143174
DefElem*defel= (DefElem*)lfirst(pl);
@@ -240,22 +271,6 @@ DefineType(List *names, List *parameters)
240271
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
241272
errmsg("type output function must be specified")));
242273

243-
/*
244-
* Look to see if type already exists (presumably as a shell; if not,
245-
* TypeCreate will complain). If it doesn't, create it as a shell, so
246-
* that the OID is known for use in the I/O function definitions.
247-
*/
248-
typoid=GetSysCacheOid(TYPENAMENSP,
249-
CStringGetDatum(typeName),
250-
ObjectIdGetDatum(typeNamespace),
251-
0,0);
252-
if (!OidIsValid(typoid))
253-
{
254-
typoid=TypeShellMake(typeName,typeNamespace);
255-
/* Make new shell type visible for modification below */
256-
CommandCounterIncrement();
257-
}
258-
259274
/*
260275
* Convert I/O proc names to OIDs
261276
*/

‎src/backend/parser/gram.y

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.530 2006/02/19 00:04:27 neilc Exp $
14+
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.531 2006/02/28 22:37:26 tgl Exp $
1515
*
1616
* HISTORY
1717
* AUTHORDATEMAJOR EVENT
@@ -2690,6 +2690,15 @@ DefineStmt:
26902690
n->definition =$4;
26912691
$$ = (Node *)n;
26922692
}
2693+
|CREATETYPE_Pany_name
2694+
{
2695+
/* Shell type (identified by lack of definition)*/
2696+
DefineStmt *n = makeNode(DefineStmt);
2697+
n->kind = OBJECT_TYPE;
2698+
n->defnames =$3;
2699+
n->definition = NIL;
2700+
$$ = (Node *)n;
2701+
}
26932702
|CREATETYPE_Pany_nameAS'('TableFuncElementList')'
26942703
{
26952704
CompositeTypeStmt *n = makeNode(CompositeTypeStmt);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp