1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_type relation
6 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.104 2005/10/15 02:49:14 momjian Exp $
13 *-------------------------------------------------------------------------
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"
29 /* ----------------------------------------------------------------
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.
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 * ----------------------------------------------------------------
43 TypeShellMake(const char *typeName, Oid typeNamespace)
45 Relation pg_type_desc;
49 Datum values[Natts_pg_type];
50 char nulls[Natts_pg_type];
54 Assert(PointerIsValid(typeName));
59 pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
60 tupDesc = pg_type_desc->rd_att;
63 * initialize our *nulls and *values arrays
65 for (i = 0; i < Natts_pg_type; ++i)
68 values[i] = (Datum) NULL; /* redundant, but safe */
72 * initialize *values with the type name and dummy values
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 */
101 * create a new type tuple
103 tup = heap_formtuple(tupDesc, values, nulls);
106 * insert the tuple in the relation and get the tuple's oid.
108 typoid = simple_heap_insert(pg_type_desc, tup);
110 CatalogUpdateIndexes(pg_type_desc, tup);
113 * Create dependencies. We can/must skip this in bootstrap mode.
115 if (!IsBootstrapProcessingMode())
116 GenerateTypeDependencies(typeNamespace,
132 * clean up and return the type-oid
135 heap_close(pg_type_desc, RowExclusiveLock);
140 /* ----------------------------------------------------------------
143 * This does all the necessary work needed to define a new type.
145 * Returns the OID assigned to the new type.
146 * ----------------------------------------------------------------
149 TypeCreate(const char *typeName,
151 Oid relationOid, /* only for 'c'atalog types */
152 char relationKind, /* ditto */
158 Oid receiveProcedure,
160 Oid analyzeProcedure,
163 const char *defaultTypeValue, /* human readable rep */
164 char *defaultTypeBin, /* cooked rep */
169 int32 typNDims, /* Array dimensions for baseType */
172 Relation pg_type_desc;
174 bool rebuildDeps = false;
176 char nulls[Natts_pg_type];
177 char replaces[Natts_pg_type];
178 Datum values[Natts_pg_type];
183 * We assume that the caller validated the arguments individually, but did
184 * not check for bad combinations.
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).
190 if (!(internalSize > 0 ||
191 internalSize == -1 ||
194 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
195 errmsg("invalid type internal size %d",
198 (internalSize <= 0 || internalSize > (int16) sizeof(Datum)))
200 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
201 errmsg("internal size %d is invalid for passed-by-value type",
204 /* Only varlena types can be toasted */
205 if (storage != 'p' && internalSize != -1)
207 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
208 errmsg("fixed-size types must have storage PLAIN")));
211 * initialize arrays needed for heap_formtuple or heap_modifytuple
213 for (i = 0; i < Natts_pg_type; ++i)
217 values[i] = (Datum) 0;
221 * initialize the *values information
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 */
248 * initialize the default binary value for this type. Check for nulls of
252 values[i] = DirectFunctionCall1(textin,
253 CStringGetDatum(defaultTypeBin));
256 i++; /* typdefaultbin */
259 * initialize the default value for this type.
261 if (defaultTypeValue)
262 values[i] = DirectFunctionCall1(textin,
263 CStringGetDatum(defaultTypeValue));
266 i++; /* typdefault */
269 * open pg_type and prepare to insert or update a row.
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.
274 pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
276 tup = SearchSysCacheCopy(TYPENAMENSP,
277 CStringGetDatum(typeName),
278 ObjectIdGetDatum(typeNamespace),
280 if (HeapTupleIsValid(tup))
283 * check that the type is not already defined. It may exist as a
284 * shell type, however.
286 if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
288 (errcode(ERRCODE_DUPLICATE_OBJECT),
289 errmsg("type \"%s\" already exists", typeName)));
292 * Okay to update existing "shell" type tuple
294 tup = heap_modifytuple(tup,
295 RelationGetDescr(pg_type_desc),
300 simple_heap_update(pg_type_desc, &tup->t_self, tup);
302 typeObjectId = HeapTupleGetOid(tup);
304 rebuildDeps = true; /* get rid of shell type's dependencies */
308 tup = heap_formtuple(RelationGetDescr(pg_type_desc),
312 typeObjectId = simple_heap_insert(pg_type_desc, tup);
316 CatalogUpdateIndexes(pg_type_desc, tup);
319 * Create dependencies. We can/must skip this in bootstrap mode.
321 if (!IsBootstrapProcessingMode())
322 GenerateTypeDependencies(typeNamespace,
335 stringToNode(defaultTypeBin) :
342 heap_close(pg_type_desc, RowExclusiveLock);
348 * GenerateTypeDependencies: build the dependencies needed for a type
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
354 * NOTE: a shell type will have a dependency to its namespace, and no others.
357 GenerateTypeDependencies(Oid typeNamespace,
359 Oid relationOid, /* only for 'c'atalog types */
360 char relationKind, /* ditto */
364 Oid receiveProcedure,
366 Oid analyzeProcedure,
372 ObjectAddress myself,
377 deleteDependencyRecordsFor(TypeRelationId, typeObjectId);
378 deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId);
381 myself.classId = TypeRelationId;
382 myself.objectId = typeObjectId;
383 myself.objectSubId = 0;
385 /* dependency on namespace */
386 /* skip for relation rowtype, since we have indirect dependency */
387 if (!OidIsValid(relationOid))
389 referenced.classId = NamespaceRelationId;
390 referenced.objectId = typeNamespace;
391 referenced.objectSubId = 0;
392 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
395 /* Normal dependencies on the I/O functions */
396 if (OidIsValid(inputProcedure))
398 referenced.classId = ProcedureRelationId;
399 referenced.objectId = inputProcedure;
400 referenced.objectSubId = 0;
401 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
404 if (OidIsValid(outputProcedure))
406 referenced.classId = ProcedureRelationId;
407 referenced.objectId = outputProcedure;
408 referenced.objectSubId = 0;
409 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
412 if (OidIsValid(receiveProcedure))
414 referenced.classId = ProcedureRelationId;
415 referenced.objectId = receiveProcedure;
416 referenced.objectSubId = 0;
417 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
420 if (OidIsValid(sendProcedure))
422 referenced.classId = ProcedureRelationId;
423 referenced.objectId = sendProcedure;
424 referenced.objectSubId = 0;
425 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
428 if (OidIsValid(analyzeProcedure))
430 referenced.classId = ProcedureRelationId;
431 referenced.objectId = analyzeProcedure;
432 referenced.objectSubId = 0;
433 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
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.
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
445 if (OidIsValid(relationOid))
447 referenced.classId = RelationRelationId;
448 referenced.objectId = relationOid;
449 referenced.objectSubId = 0;
451 if (relationKind != RELKIND_COMPOSITE_TYPE)
452 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
454 recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
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.)
463 if (OidIsValid(elementType))
465 referenced.classId = TypeRelationId;
466 referenced.objectId = elementType;
467 referenced.objectSubId = 0;
468 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
471 /* Normal dependency from a domain to its base type. */
472 if (OidIsValid(baseType))
474 referenced.classId = TypeRelationId;
475 referenced.objectId = baseType;
476 referenced.objectSubId = 0;
477 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
480 /* Normal dependency on the default expression. */
482 recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
484 /* Shared dependency on owner. */
485 recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
490 * This renames a type
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.
497 TypeRename(const char *oldTypeName, Oid typeNamespace,
498 const char *newTypeName)
500 Relation pg_type_desc;
503 pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
505 tuple = SearchSysCacheCopy(TYPENAMENSP,
506 CStringGetDatum(oldTypeName),
507 ObjectIdGetDatum(typeNamespace),
509 if (!HeapTupleIsValid(tuple))
511 (errcode(ERRCODE_UNDEFINED_OBJECT),
512 errmsg("type \"%s\" does not exist", oldTypeName)));
514 if (SearchSysCacheExists(TYPENAMENSP,
515 CStringGetDatum(newTypeName),
516 ObjectIdGetDatum(typeNamespace),
519 (errcode(ERRCODE_DUPLICATE_OBJECT),
520 errmsg("type \"%s\" already exists", newTypeName)));
522 namestrcpy(&(((Form_pg_type) GETSTRUCT(tuple))->typname), newTypeName);
524 simple_heap_update(pg_type_desc, &tuple->t_self, tuple);
526 /* update the system catalog indexes */
527 CatalogUpdateIndexes(pg_type_desc, tuple);
529 heap_freetuple(tuple);
530 heap_close(pg_type_desc, RowExclusiveLock);
534 * makeArrayTypeName(typeName);
535 * - given a base type name, make an array of type name out of it
537 * the caller is responsible for pfreeing the result
540 makeArrayTypeName(const char *typeName)
546 arr = palloc(NAMEDATALEN);
547 snprintf(arr, NAMEDATALEN,
548 "_%.*s", NAMEDATALEN - 2, typeName);