]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_type.c
Standard pgindent run for 8.1.
[postgresql] / src / backend / catalog / pg_type.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_type.c
4  *        routines to support manipulation of the pg_type relation
5  *
6  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.104 2005/10/15 02:49:14 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/heapam.h"
18 #include "catalog/dependency.h"
19 #include "catalog/indexing.h"
20 #include "catalog/pg_namespace.h"
21 #include "catalog/pg_proc.h"
22 #include "catalog/pg_type.h"
23 #include "miscadmin.h"
24 #include "utils/builtins.h"
25 #include "utils/lsyscache.h"
26 #include "utils/syscache.h"
27
28
29 /* ----------------------------------------------------------------
30  *              TypeShellMake
31  *
32  *              This procedure inserts a "shell" tuple into the type
33  *              relation.  The type tuple inserted has invalid values
34  *              and in particular, the "typisdefined" field is false.
35  *
36  *              This is used so that a tuple exists in the catalogs.
37  *              The invalid fields should be fixed up sometime after
38  *              this routine is called, and then the "typeisdefined"
39  *              field is set to true. -cim 6/15/90
40  * ----------------------------------------------------------------
41  */
42 Oid
43 TypeShellMake(const char *typeName, Oid typeNamespace)
44 {
45         Relation        pg_type_desc;
46         TupleDesc       tupDesc;
47         int                     i;
48         HeapTuple       tup;
49         Datum           values[Natts_pg_type];
50         char            nulls[Natts_pg_type];
51         Oid                     typoid;
52         NameData        name;
53
54         Assert(PointerIsValid(typeName));
55
56         /*
57          * open pg_type
58          */
59         pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
60         tupDesc = pg_type_desc->rd_att;
61
62         /*
63          * initialize our *nulls and *values arrays
64          */
65         for (i = 0; i < Natts_pg_type; ++i)
66         {
67                 nulls[i] = ' ';
68                 values[i] = (Datum) NULL;               /* redundant, but safe */
69         }
70
71         /*
72          * initialize *values with the type name and dummy values
73          */
74         i = 0;
75         namestrcpy(&name, typeName);
76         values[i++] = NameGetDatum(&name);      /* typname */
77         values[i++] = ObjectIdGetDatum(typeNamespace);          /* typnamespace */
78         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 */
97         nulls[i++] = 'n';                       /* typdefaultbin */
98         nulls[i++] = 'n';                       /* typdefault */
99
100         /*
101          * create a new type tuple
102          */
103         tup = heap_formtuple(tupDesc, values, nulls);
104
105         /*
106          * insert the tuple in the relation and get the tuple's oid.
107          */
108         typoid = simple_heap_insert(pg_type_desc, tup);
109
110         CatalogUpdateIndexes(pg_type_desc, tup);
111
112         /*
113          * Create dependencies.  We can/must skip this in bootstrap mode.
114          */
115         if (!IsBootstrapProcessingMode())
116                 GenerateTypeDependencies(typeNamespace,
117                                                                  typoid,
118                                                                  InvalidOid,
119                                                                  0,
120                                                                  GetUserId(),
121                                                                  InvalidOid,
122                                                                  InvalidOid,
123                                                                  InvalidOid,
124                                                                  InvalidOid,
125                                                                  InvalidOid,
126                                                                  InvalidOid,
127                                                                  InvalidOid,
128                                                                  NULL,
129                                                                  false);
130
131         /*
132          * clean up and return the type-oid
133          */
134         heap_freetuple(tup);
135         heap_close(pg_type_desc, RowExclusiveLock);
136
137         return typoid;
138 }
139
140 /* ----------------------------------------------------------------
141  *              TypeCreate
142  *
143  *              This does all the necessary work needed to define a new type.
144  *
145  *              Returns the OID assigned to the new type.
146  * ----------------------------------------------------------------
147  */
148 Oid
149 TypeCreate(const char *typeName,
150                    Oid typeNamespace,
151                    Oid relationOid,             /* only for 'c'atalog types */
152                    char relationKind,   /* ditto */
153                    int16 internalSize,
154                    char typeType,
155                    char typDelim,
156                    Oid inputProcedure,
157                    Oid outputProcedure,
158                    Oid receiveProcedure,
159                    Oid sendProcedure,
160                    Oid analyzeProcedure,
161                    Oid elementType,
162                    Oid baseType,
163                    const char *defaultTypeValue,                /* human readable rep */
164                    char *defaultTypeBin,        /* cooked rep */
165                    bool passedByValue,
166                    char alignment,
167                    char storage,
168                    int32 typeMod,
169                    int32 typNDims,              /* Array dimensions for baseType */
170                    bool typeNotNull)
171 {
172         Relation        pg_type_desc;
173         Oid                     typeObjectId;
174         bool            rebuildDeps = false;
175         HeapTuple       tup;
176         char            nulls[Natts_pg_type];
177         char            replaces[Natts_pg_type];
178         Datum           values[Natts_pg_type];
179         NameData        name;
180         int                     i;
181
182         /*
183          * We assume that the caller validated the arguments individually, but did
184          * not check for bad combinations.
185          *
186          * Validate size specifications: either positive (fixed-length) or -1
187          * (varlena) or -2 (cstring).  Pass-by-value types must have a fixed
188          * length not more than sizeof(Datum).
189          */
190         if (!(internalSize > 0 ||
191                   internalSize == -1 ||
192                   internalSize == -2))
193                 ereport(ERROR,
194                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
195                                  errmsg("invalid type internal size %d",
196                                                 internalSize)));
197         if (passedByValue &&
198                 (internalSize <= 0 || internalSize > (int16) sizeof(Datum)))
199                 ereport(ERROR,
200                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
201                            errmsg("internal size %d is invalid for passed-by-value type",
202                                           internalSize)));
203
204         /* Only varlena types can be toasted */
205         if (storage != 'p' && internalSize != -1)
206                 ereport(ERROR,
207                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
208                                  errmsg("fixed-size types must have storage PLAIN")));
209
210         /*
211          * initialize arrays needed for heap_formtuple or heap_modifytuple
212          */
213         for (i = 0; i < Natts_pg_type; ++i)
214         {
215                 nulls[i] = ' ';
216                 replaces[i] = 'r';
217                 values[i] = (Datum) 0;
218         }
219
220         /*
221          * initialize the *values information
222          */
223         i = 0;
224         namestrcpy(&name, typeName);
225         values[i++] = NameGetDatum(&name);      /* typname */
226         values[i++] = ObjectIdGetDatum(typeNamespace);          /* typnamespace */
227         values[i++] = ObjectIdGetDatum(GetUserId());            /* typowner */
228         values[i++] = Int16GetDatum(internalSize);      /* typlen */
229         values[i++] = BoolGetDatum(passedByValue);      /* typbyval */
230         values[i++] = CharGetDatum(typeType);           /* typtype */
231         values[i++] = BoolGetDatum(true);       /* typisdefined */
232         values[i++] = CharGetDatum(typDelim);           /* typdelim */
233         values[i++] = ObjectIdGetDatum(typeType == 'c' ? relationOid : InvalidOid); /* typrelid */
234         values[i++] = ObjectIdGetDatum(elementType);            /* typelem */
235         values[i++] = ObjectIdGetDatum(inputProcedure);         /* typinput */
236         values[i++] = ObjectIdGetDatum(outputProcedure);        /* typoutput */
237         values[i++] = ObjectIdGetDatum(receiveProcedure);       /* typreceive */
238         values[i++] = ObjectIdGetDatum(sendProcedure);          /* typsend */
239         values[i++] = ObjectIdGetDatum(analyzeProcedure);       /* typanalyze */
240         values[i++] = CharGetDatum(alignment);          /* typalign */
241         values[i++] = CharGetDatum(storage);            /* typstorage */
242         values[i++] = BoolGetDatum(typeNotNull);        /* typnotnull */
243         values[i++] = ObjectIdGetDatum(baseType);       /* typbasetype */
244         values[i++] = Int32GetDatum(typeMod);           /* typtypmod */
245         values[i++] = Int32GetDatum(typNDims);          /* typndims */
246
247         /*
248          * initialize the default binary value for this type.  Check for nulls of
249          * course.
250          */
251         if (defaultTypeBin)
252                 values[i] = DirectFunctionCall1(textin,
253                                                                                 CStringGetDatum(defaultTypeBin));
254         else
255                 nulls[i] = 'n';
256         i++;                                            /* typdefaultbin */
257
258         /*
259          * initialize the default value for this type.
260          */
261         if (defaultTypeValue)
262                 values[i] = DirectFunctionCall1(textin,
263                                                                                 CStringGetDatum(defaultTypeValue));
264         else
265                 nulls[i] = 'n';
266         i++;                                            /* typdefault */
267
268         /*
269          * open pg_type and prepare to insert or update a row.
270          *
271          * NOTE: updating will not work correctly in bootstrap mode; but we don't
272          * expect to be overwriting any shell types in bootstrap mode.
273          */
274         pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
275
276         tup = SearchSysCacheCopy(TYPENAMENSP,
277                                                          CStringGetDatum(typeName),
278                                                          ObjectIdGetDatum(typeNamespace),
279                                                          0, 0);
280         if (HeapTupleIsValid(tup))
281         {
282                 /*
283                  * check that the type is not already defined.  It may exist as a
284                  * shell type, however.
285                  */
286                 if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
287                         ereport(ERROR,
288                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
289                                          errmsg("type \"%s\" already exists", typeName)));
290
291                 /*
292                  * Okay to update existing "shell" type tuple
293                  */
294                 tup = heap_modifytuple(tup,
295                                                            RelationGetDescr(pg_type_desc),
296                                                            values,
297                                                            nulls,
298                                                            replaces);
299
300                 simple_heap_update(pg_type_desc, &tup->t_self, tup);
301
302                 typeObjectId = HeapTupleGetOid(tup);
303
304                 rebuildDeps = true;             /* get rid of shell type's dependencies */
305         }
306         else
307         {
308                 tup = heap_formtuple(RelationGetDescr(pg_type_desc),
309                                                          values,
310                                                          nulls);
311
312                 typeObjectId = simple_heap_insert(pg_type_desc, tup);
313         }
314
315         /* Update indexes */
316         CatalogUpdateIndexes(pg_type_desc, tup);
317
318         /*
319          * Create dependencies.  We can/must skip this in bootstrap mode.
320          */
321         if (!IsBootstrapProcessingMode())
322                 GenerateTypeDependencies(typeNamespace,
323                                                                  typeObjectId,
324                                                                  relationOid,
325                                                                  relationKind,
326                                                                  GetUserId(),
327                                                                  inputProcedure,
328                                                                  outputProcedure,
329                                                                  receiveProcedure,
330                                                                  sendProcedure,
331                                                                  analyzeProcedure,
332                                                                  elementType,
333                                                                  baseType,
334                                                                  (defaultTypeBin ?
335                                                                   stringToNode(defaultTypeBin) :
336                                                                   NULL),
337                                                                  rebuildDeps);
338
339         /*
340          * finish up
341          */
342         heap_close(pg_type_desc, RowExclusiveLock);
343
344         return typeObjectId;
345 }
346
347 /*
348  * GenerateTypeDependencies: build the dependencies needed for a type
349  *
350  * If rebuild is true, we remove existing dependencies and rebuild them
351  * from scratch.  This is needed for ALTER TYPE, and also when replacing
352  * a shell type.
353  *
354  * NOTE: a shell type will have a dependency to its namespace, and no others.
355  */
356 void
357 GenerateTypeDependencies(Oid typeNamespace,
358                                                  Oid typeObjectId,
359                                                  Oid relationOid,               /* only for 'c'atalog types */
360                                                  char relationKind,             /* ditto */
361                                                  Oid owner,
362                                                  Oid inputProcedure,
363                                                  Oid outputProcedure,
364                                                  Oid receiveProcedure,
365                                                  Oid sendProcedure,
366                                                  Oid analyzeProcedure,
367                                                  Oid elementType,
368                                                  Oid baseType,
369                                                  Node *defaultExpr,
370                                                  bool rebuild)
371 {
372         ObjectAddress myself,
373                                 referenced;
374
375         if (rebuild)
376         {
377                 deleteDependencyRecordsFor(TypeRelationId, typeObjectId);
378                 deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId);
379         }
380
381         myself.classId = TypeRelationId;
382         myself.objectId = typeObjectId;
383         myself.objectSubId = 0;
384
385         /* dependency on namespace */
386         /* skip for relation rowtype, since we have indirect dependency */
387         if (!OidIsValid(relationOid))
388         {
389                 referenced.classId = NamespaceRelationId;
390                 referenced.objectId = typeNamespace;
391                 referenced.objectSubId = 0;
392                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
393         }
394
395         /* Normal dependencies on the I/O functions */
396         if (OidIsValid(inputProcedure))
397         {
398                 referenced.classId = ProcedureRelationId;
399                 referenced.objectId = inputProcedure;
400                 referenced.objectSubId = 0;
401                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
402         }
403
404         if (OidIsValid(outputProcedure))
405         {
406                 referenced.classId = ProcedureRelationId;
407                 referenced.objectId = outputProcedure;
408                 referenced.objectSubId = 0;
409                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
410         }
411
412         if (OidIsValid(receiveProcedure))
413         {
414                 referenced.classId = ProcedureRelationId;
415                 referenced.objectId = receiveProcedure;
416                 referenced.objectSubId = 0;
417                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
418         }
419
420         if (OidIsValid(sendProcedure))
421         {
422                 referenced.classId = ProcedureRelationId;
423                 referenced.objectId = sendProcedure;
424                 referenced.objectSubId = 0;
425                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
426         }
427
428         if (OidIsValid(analyzeProcedure))
429         {
430                 referenced.classId = ProcedureRelationId;
431                 referenced.objectId = analyzeProcedure;
432                 referenced.objectSubId = 0;
433                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
434         }
435
436         /*
437          * If the type is a rowtype for a relation, mark it as internally
438          * dependent on the relation, *unless* it is a stand-alone composite type
439          * relation. For the latter case, we have to reverse the dependency.
440          *
441          * In the former case, this allows the type to be auto-dropped when the
442          * relation is, and not otherwise. And in the latter, of course we get the
443          * opposite effect.
444          */
445         if (OidIsValid(relationOid))
446         {
447                 referenced.classId = RelationRelationId;
448                 referenced.objectId = relationOid;
449                 referenced.objectSubId = 0;
450
451                 if (relationKind != RELKIND_COMPOSITE_TYPE)
452                         recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
453                 else
454                         recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
455         }
456
457         /*
458          * If the type is an array type, mark it auto-dependent on the base type.
459          * (This is a compromise between the typical case where the array type is
460          * automatically generated and the case where it is manually created: we'd
461          * prefer INTERNAL for the former case and NORMAL for the latter.)
462          */
463         if (OidIsValid(elementType))
464         {
465                 referenced.classId = TypeRelationId;
466                 referenced.objectId = elementType;
467                 referenced.objectSubId = 0;
468                 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
469         }
470
471         /* Normal dependency from a domain to its base type. */
472         if (OidIsValid(baseType))
473         {
474                 referenced.classId = TypeRelationId;
475                 referenced.objectId = baseType;
476                 referenced.objectSubId = 0;
477                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
478         }
479
480         /* Normal dependency on the default expression. */
481         if (defaultExpr)
482                 recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
483
484         /* Shared dependency on owner. */
485         recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
486 }
487
488 /*
489  * TypeRename
490  *              This renames a type
491  *
492  * Note: any associated array type is *not* renamed; caller must make
493  * another call to handle that case.  Currently this is only used for
494  * renaming types associated with tables, for which there are no arrays.
495  */
496 void
497 TypeRename(const char *oldTypeName, Oid typeNamespace,
498                    const char *newTypeName)
499 {
500         Relation        pg_type_desc;
501         HeapTuple       tuple;
502
503         pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
504
505         tuple = SearchSysCacheCopy(TYPENAMENSP,
506                                                            CStringGetDatum(oldTypeName),
507                                                            ObjectIdGetDatum(typeNamespace),
508                                                            0, 0);
509         if (!HeapTupleIsValid(tuple))
510                 ereport(ERROR,
511                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
512                                  errmsg("type \"%s\" does not exist", oldTypeName)));
513
514         if (SearchSysCacheExists(TYPENAMENSP,
515                                                          CStringGetDatum(newTypeName),
516                                                          ObjectIdGetDatum(typeNamespace),
517                                                          0, 0))
518                 ereport(ERROR,
519                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
520                                  errmsg("type \"%s\" already exists", newTypeName)));
521
522         namestrcpy(&(((Form_pg_type) GETSTRUCT(tuple))->typname), newTypeName);
523
524         simple_heap_update(pg_type_desc, &tuple->t_self, tuple);
525
526         /* update the system catalog indexes */
527         CatalogUpdateIndexes(pg_type_desc, tuple);
528
529         heap_freetuple(tuple);
530         heap_close(pg_type_desc, RowExclusiveLock);
531 }
532
533 /*
534  * makeArrayTypeName(typeName);
535  *        - given a base type name, make an array of type name out of it
536  *
537  * the caller is responsible for pfreeing the result
538  */
539 char *
540 makeArrayTypeName(const char *typeName)
541 {
542         char       *arr;
543
544         if (!typeName)
545                 return NULL;
546         arr = palloc(NAMEDATALEN);
547         snprintf(arr, NAMEDATALEN,
548                          "_%.*s", NAMEDATALEN - 2, typeName);
549         return arr;
550 }