1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_type relation
6 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/pg_type.c
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "access/xact.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/objectaccess.h"
22 #include "catalog/pg_namespace.h"
23 #include "catalog/pg_proc.h"
24 #include "catalog/pg_type.h"
25 #include "catalog/pg_type_fn.h"
26 #include "commands/typecmds.h"
27 #include "miscadmin.h"
28 #include "parser/scansup.h"
29 #include "utils/acl.h"
30 #include "utils/builtins.h"
31 #include "utils/fmgroids.h"
32 #include "utils/lsyscache.h"
33 #include "utils/rel.h"
34 #include "utils/syscache.h"
36 /* Potentially set by contrib/pg_upgrade_support functions */
37 Oid binary_upgrade_next_pg_type_oid = InvalidOid;
39 /* ----------------------------------------------------------------
42 * This procedure inserts a "shell" tuple into the pg_type relation.
43 * The type tuple inserted has valid but dummy values, and its
44 * "typisdefined" field is false indicating it's not really defined.
46 * This is used so that a tuple exists in the catalogs. The I/O
47 * functions for the type will link to this tuple. When the full
48 * CREATE TYPE command is issued, the bogus values will be replaced
49 * with correct ones, and "typisdefined" will be set to true.
50 * ----------------------------------------------------------------
53 TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
55 Relation pg_type_desc;
59 Datum values[Natts_pg_type];
60 bool nulls[Natts_pg_type];
64 Assert(PointerIsValid(typeName));
69 pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
70 tupDesc = pg_type_desc->rd_att;
73 * initialize our *nulls and *values arrays
75 for (i = 0; i < Natts_pg_type; ++i)
78 values[i] = (Datum) NULL; /* redundant, but safe */
82 * initialize *values with the type name and dummy values
84 * The representational details are the same as int4 ... it doesn't really
85 * matter what they are so long as they are consistent. Also note that we
86 * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
87 * mistaken for a usable type.
90 namestrcpy(&name, typeName);
91 values[i++] = NameGetDatum(&name); /* typname */
92 values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
93 values[i++] = ObjectIdGetDatum(ownerId); /* typowner */
94 values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */
95 values[i++] = BoolGetDatum(true); /* typbyval */
96 values[i++] = CharGetDatum(TYPTYPE_PSEUDO); /* typtype */
97 values[i++] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE); /* typcategory */
98 values[i++] = BoolGetDatum(false); /* typispreferred */
99 values[i++] = BoolGetDatum(false); /* typisdefined */
100 values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
101 values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
102 values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */
103 values[i++] = ObjectIdGetDatum(InvalidOid); /* typarray */
104 values[i++] = ObjectIdGetDatum(F_SHELL_IN); /* typinput */
105 values[i++] = ObjectIdGetDatum(F_SHELL_OUT); /* typoutput */
106 values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */
107 values[i++] = ObjectIdGetDatum(InvalidOid); /* typsend */
108 values[i++] = ObjectIdGetDatum(InvalidOid); /* typmodin */
109 values[i++] = ObjectIdGetDatum(InvalidOid); /* typmodout */
110 values[i++] = ObjectIdGetDatum(InvalidOid); /* typanalyze */
111 values[i++] = CharGetDatum('i'); /* typalign */
112 values[i++] = CharGetDatum('p'); /* typstorage */
113 values[i++] = BoolGetDatum(false); /* typnotnull */
114 values[i++] = ObjectIdGetDatum(InvalidOid); /* typbasetype */
115 values[i++] = Int32GetDatum(-1); /* typtypmod */
116 values[i++] = Int32GetDatum(0); /* typndims */
117 values[i++] = ObjectIdGetDatum(InvalidOid); /* typcollation */
118 nulls[i++] = true; /* typdefaultbin */
119 nulls[i++] = true; /* typdefault */
122 * create a new type tuple
124 tup = heap_form_tuple(tupDesc, values, nulls);
126 /* Use binary-upgrade override for pg_type.oid, if supplied. */
127 if (OidIsValid(binary_upgrade_next_pg_type_oid))
129 HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
130 binary_upgrade_next_pg_type_oid = InvalidOid;
134 * insert the tuple in the relation and get the tuple's oid.
136 typoid = simple_heap_insert(pg_type_desc, tup);
138 CatalogUpdateIndexes(pg_type_desc, tup);
141 * Create dependencies. We can/must skip this in bootstrap mode.
143 if (!IsBootstrapProcessingMode())
144 GenerateTypeDependencies(typeNamespace,
162 /* Post creation hook for new shell type */
163 InvokeObjectAccessHook(OAT_POST_CREATE, TypeRelationId, typoid, 0);
166 * clean up and return the type-oid
169 heap_close(pg_type_desc, RowExclusiveLock);
174 /* ----------------------------------------------------------------
177 * This does all the necessary work needed to define a new type.
179 * Returns the OID assigned to the new type. If newTypeOid is
180 * zero (the normal case), a new OID is created; otherwise we
181 * use exactly that OID.
182 * ----------------------------------------------------------------
185 TypeCreate(Oid newTypeOid,
186 const char *typeName,
188 Oid relationOid, /* only for relation rowtypes */
189 char relationKind, /* ditto */
198 Oid receiveProcedure,
200 Oid typmodinProcedure,
201 Oid typmodoutProcedure,
202 Oid analyzeProcedure,
204 bool isImplicitArray,
207 const char *defaultTypeValue, /* human readable rep */
208 char *defaultTypeBin, /* cooked rep */
213 int32 typNDims, /* Array dimensions for baseType */
217 Relation pg_type_desc;
219 bool rebuildDeps = false;
221 bool nulls[Natts_pg_type];
222 bool replaces[Natts_pg_type];
223 Datum values[Natts_pg_type];
228 * We assume that the caller validated the arguments individually, but did
229 * not check for bad combinations.
231 * Validate size specifications: either positive (fixed-length) or -1
232 * (varlena) or -2 (cstring).
234 if (!(internalSize > 0 ||
235 internalSize == -1 ||
238 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
239 errmsg("invalid type internal size %d",
245 * Pass-by-value types must have a fixed length that is one of the
246 * values supported by fetch_att() and store_att_byval(); and the
247 * alignment had better agree, too. All this code must match
250 if (internalSize == (int16) sizeof(char))
252 if (alignment != 'c')
254 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
255 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
256 alignment, internalSize)));
258 else if (internalSize == (int16) sizeof(int16))
260 if (alignment != 's')
262 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
263 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
264 alignment, internalSize)));
266 else if (internalSize == (int16) sizeof(int32))
268 if (alignment != 'i')
270 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
271 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
272 alignment, internalSize)));
274 #if SIZEOF_DATUM == 8
275 else if (internalSize == (int16) sizeof(Datum))
277 if (alignment != 'd')
279 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
280 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
281 alignment, internalSize)));
286 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
287 errmsg("internal size %d is invalid for passed-by-value type",
292 /* varlena types must have int align or better */
293 if (internalSize == -1 && !(alignment == 'i' || alignment == 'd'))
295 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
296 errmsg("alignment \"%c\" is invalid for variable-length type",
298 /* cstring must have char alignment */
299 if (internalSize == -2 && !(alignment == 'c'))
301 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
302 errmsg("alignment \"%c\" is invalid for variable-length type",
306 /* Only varlena types can be toasted */
307 if (storage != 'p' && internalSize != -1)
309 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
310 errmsg("fixed-size types must have storage PLAIN")));
313 * initialize arrays needed for heap_form_tuple or heap_modify_tuple
315 for (i = 0; i < Natts_pg_type; ++i)
319 values[i] = (Datum) 0;
323 * initialize the *values information
326 namestrcpy(&name, typeName);
327 values[i++] = NameGetDatum(&name); /* typname */
328 values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
329 values[i++] = ObjectIdGetDatum(ownerId); /* typowner */
330 values[i++] = Int16GetDatum(internalSize); /* typlen */
331 values[i++] = BoolGetDatum(passedByValue); /* typbyval */
332 values[i++] = CharGetDatum(typeType); /* typtype */
333 values[i++] = CharGetDatum(typeCategory); /* typcategory */
334 values[i++] = BoolGetDatum(typePreferred); /* typispreferred */
335 values[i++] = BoolGetDatum(true); /* typisdefined */
336 values[i++] = CharGetDatum(typDelim); /* typdelim */
337 values[i++] = ObjectIdGetDatum(relationOid); /* typrelid */
338 values[i++] = ObjectIdGetDatum(elementType); /* typelem */
339 values[i++] = ObjectIdGetDatum(arrayType); /* typarray */
340 values[i++] = ObjectIdGetDatum(inputProcedure); /* typinput */
341 values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */
342 values[i++] = ObjectIdGetDatum(receiveProcedure); /* typreceive */
343 values[i++] = ObjectIdGetDatum(sendProcedure); /* typsend */
344 values[i++] = ObjectIdGetDatum(typmodinProcedure); /* typmodin */
345 values[i++] = ObjectIdGetDatum(typmodoutProcedure); /* typmodout */
346 values[i++] = ObjectIdGetDatum(analyzeProcedure); /* typanalyze */
347 values[i++] = CharGetDatum(alignment); /* typalign */
348 values[i++] = CharGetDatum(storage); /* typstorage */
349 values[i++] = BoolGetDatum(typeNotNull); /* typnotnull */
350 values[i++] = ObjectIdGetDatum(baseType); /* typbasetype */
351 values[i++] = Int32GetDatum(typeMod); /* typtypmod */
352 values[i++] = Int32GetDatum(typNDims); /* typndims */
353 values[i++] = ObjectIdGetDatum(typeCollation); /* typcollation */
356 * initialize the default binary value for this type. Check for nulls of
360 values[i] = CStringGetTextDatum(defaultTypeBin);
363 i++; /* typdefaultbin */
366 * initialize the default value for this type.
368 if (defaultTypeValue)
369 values[i] = CStringGetTextDatum(defaultTypeValue);
372 i++; /* typdefault */
375 * open pg_type and prepare to insert or update a row.
377 * NOTE: updating will not work correctly in bootstrap mode; but we don't
378 * expect to be overwriting any shell types in bootstrap mode.
380 pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
382 tup = SearchSysCacheCopy2(TYPENAMENSP,
383 CStringGetDatum(typeName),
384 ObjectIdGetDatum(typeNamespace));
385 if (HeapTupleIsValid(tup))
388 * check that the type is not already defined. It may exist as a
389 * shell type, however.
391 if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
393 (errcode(ERRCODE_DUPLICATE_OBJECT),
394 errmsg("type \"%s\" already exists", typeName)));
397 * shell type must have been created by same owner
399 if (((Form_pg_type) GETSTRUCT(tup))->typowner != ownerId)
400 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName);
402 /* trouble if caller wanted to force the OID */
403 if (OidIsValid(newTypeOid))
404 elog(ERROR, "cannot assign new OID to existing shell type");
407 * Okay to update existing shell type tuple
409 tup = heap_modify_tuple(tup,
410 RelationGetDescr(pg_type_desc),
415 simple_heap_update(pg_type_desc, &tup->t_self, tup);
417 typeObjectId = HeapTupleGetOid(tup);
419 rebuildDeps = true; /* get rid of shell type's dependencies */
423 tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
427 /* Force the OID if requested by caller */
428 if (OidIsValid(newTypeOid))
429 HeapTupleSetOid(tup, newTypeOid);
430 /* Use binary-upgrade override for pg_type.oid, if supplied. */
431 else if (OidIsValid(binary_upgrade_next_pg_type_oid))
433 HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
434 binary_upgrade_next_pg_type_oid = InvalidOid;
436 /* else allow system to assign oid */
438 typeObjectId = simple_heap_insert(pg_type_desc, tup);
442 CatalogUpdateIndexes(pg_type_desc, tup);
445 * Create dependencies. We can/must skip this in bootstrap mode.
447 if (!IsBootstrapProcessingMode())
448 GenerateTypeDependencies(typeNamespace,
464 stringToNode(defaultTypeBin) :
468 /* Post creation hook for new type */
469 InvokeObjectAccessHook(OAT_POST_CREATE, TypeRelationId, typeObjectId, 0);
474 heap_close(pg_type_desc, RowExclusiveLock);
480 * GenerateTypeDependencies: build the dependencies needed for a type
482 * If rebuild is true, we remove existing dependencies and rebuild them
483 * from scratch. This is needed for ALTER TYPE, and also when replacing
487 GenerateTypeDependencies(Oid typeNamespace,
489 Oid relationOid, /* only for relation rowtypes */
490 char relationKind, /* ditto */
494 Oid receiveProcedure,
496 Oid typmodinProcedure,
497 Oid typmodoutProcedure,
498 Oid analyzeProcedure,
500 bool isImplicitArray,
505 ObjectAddress myself,
510 deleteDependencyRecordsFor(TypeRelationId, typeObjectId);
511 deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
514 myself.classId = TypeRelationId;
515 myself.objectId = typeObjectId;
516 myself.objectSubId = 0;
519 * Make dependency on namespace and shared dependency on owner.
521 * For a relation rowtype (that's not a composite type), we should skip
522 * these because we'll depend on them indirectly through the pg_class
523 * entry. Likewise, skip for implicit arrays since we'll depend on them
524 * through the element type.
526 if ((!OidIsValid(relationOid) || relationKind == RELKIND_COMPOSITE_TYPE) &&
529 referenced.classId = NamespaceRelationId;
530 referenced.objectId = typeNamespace;
531 referenced.objectSubId = 0;
532 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
534 recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);
537 /* Normal dependencies on the I/O functions */
538 if (OidIsValid(inputProcedure))
540 referenced.classId = ProcedureRelationId;
541 referenced.objectId = inputProcedure;
542 referenced.objectSubId = 0;
543 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
546 if (OidIsValid(outputProcedure))
548 referenced.classId = ProcedureRelationId;
549 referenced.objectId = outputProcedure;
550 referenced.objectSubId = 0;
551 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
554 if (OidIsValid(receiveProcedure))
556 referenced.classId = ProcedureRelationId;
557 referenced.objectId = receiveProcedure;
558 referenced.objectSubId = 0;
559 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
562 if (OidIsValid(sendProcedure))
564 referenced.classId = ProcedureRelationId;
565 referenced.objectId = sendProcedure;
566 referenced.objectSubId = 0;
567 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
570 if (OidIsValid(typmodinProcedure))
572 referenced.classId = ProcedureRelationId;
573 referenced.objectId = typmodinProcedure;
574 referenced.objectSubId = 0;
575 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
578 if (OidIsValid(typmodoutProcedure))
580 referenced.classId = ProcedureRelationId;
581 referenced.objectId = typmodoutProcedure;
582 referenced.objectSubId = 0;
583 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
586 if (OidIsValid(analyzeProcedure))
588 referenced.classId = ProcedureRelationId;
589 referenced.objectId = analyzeProcedure;
590 referenced.objectSubId = 0;
591 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
595 * If the type is a rowtype for a relation, mark it as internally
596 * dependent on the relation, *unless* it is a stand-alone composite type
597 * relation. For the latter case, we have to reverse the dependency.
599 * In the former case, this allows the type to be auto-dropped when the
600 * relation is, and not otherwise. And in the latter, of course we get the
603 if (OidIsValid(relationOid))
605 referenced.classId = RelationRelationId;
606 referenced.objectId = relationOid;
607 referenced.objectSubId = 0;
609 if (relationKind != RELKIND_COMPOSITE_TYPE)
610 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
612 recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
616 * If the type is an implicitly-created array type, mark it as internally
617 * dependent on the element type. Otherwise, if it has an element type,
618 * the dependency is a normal one.
620 if (OidIsValid(elementType))
622 referenced.classId = TypeRelationId;
623 referenced.objectId = elementType;
624 referenced.objectSubId = 0;
625 recordDependencyOn(&myself, &referenced,
626 isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
629 /* Normal dependency from a domain to its base type. */
630 if (OidIsValid(baseType))
632 referenced.classId = TypeRelationId;
633 referenced.objectId = baseType;
634 referenced.objectSubId = 0;
635 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
638 /* Normal dependency on the default expression. */
640 recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
645 * This renames a type, as well as any associated array type.
647 * Caller must have already checked privileges.
649 * Currently this is used for renaming table rowtypes and for
650 * ALTER TYPE RENAME TO command.
653 RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
655 Relation pg_type_desc;
660 pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
662 tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
663 if (!HeapTupleIsValid(tuple))
664 elog(ERROR, "cache lookup failed for type %u", typeOid);
665 typ = (Form_pg_type) GETSTRUCT(tuple);
667 /* We are not supposed to be changing schemas here */
668 Assert(typeNamespace == typ->typnamespace);
670 arrayOid = typ->typarray;
672 /* Just to give a more friendly error than unique-index violation */
673 if (SearchSysCacheExists2(TYPENAMENSP,
674 CStringGetDatum(newTypeName),
675 ObjectIdGetDatum(typeNamespace)))
677 (errcode(ERRCODE_DUPLICATE_OBJECT),
678 errmsg("type \"%s\" already exists", newTypeName)));
680 /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
681 namestrcpy(&(typ->typname), newTypeName);
683 simple_heap_update(pg_type_desc, &tuple->t_self, tuple);
685 /* update the system catalog indexes */
686 CatalogUpdateIndexes(pg_type_desc, tuple);
688 heap_freetuple(tuple);
689 heap_close(pg_type_desc, RowExclusiveLock);
691 /* If the type has an array type, recurse to handle that */
692 if (OidIsValid(arrayOid))
694 char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
696 RenameTypeInternal(arrayOid, arrname, typeNamespace);
704 * - given a base type name, make an array type name for it
706 * the caller is responsible for pfreeing the result
709 makeArrayTypeName(const char *typeName, Oid typeNamespace)
711 char *arr = (char *) palloc(NAMEDATALEN);
712 int namelen = strlen(typeName);
713 Relation pg_type_desc;
717 * The idea is to prepend underscores as needed until we make a name that
718 * doesn't collide with anything...
720 pg_type_desc = heap_open(TypeRelationId, AccessShareLock);
722 for (i = 1; i < NAMEDATALEN - 1; i++)
725 if (i + namelen < NAMEDATALEN)
726 strcpy(arr + i, typeName);
729 memcpy(arr + i, typeName, NAMEDATALEN - i);
730 truncate_identifier(arr, NAMEDATALEN, false);
732 if (!SearchSysCacheExists2(TYPENAMENSP,
733 CStringGetDatum(arr),
734 ObjectIdGetDatum(typeNamespace)))
738 heap_close(pg_type_desc, AccessShareLock);
740 if (i >= NAMEDATALEN - 1)
742 (errcode(ERRCODE_DUPLICATE_OBJECT),
743 errmsg("could not form array type name for type \"%s\"",
752 * - try to reassign an array type name that the user wants to use.
754 * The given type name has been discovered to already exist (with the given
755 * OID). If it is an autogenerated array type, change the array type's name
756 * to not conflict. This allows the user to create type "foo" followed by
757 * type "_foo" without problems. (Of course, there are race conditions if
758 * two backends try to create similarly-named types concurrently, but the
759 * worst that can happen is an unnecessary failure --- anything we do here
760 * will be rolled back if the type creation fails due to conflicting names.)
762 * Note that this must be called *before* calling makeArrayTypeName to
763 * determine the new type's own array type name; else the latter will
764 * certainly pick the same name.
766 * Returns TRUE if successfully moved the type, FALSE if not.
768 * We also return TRUE if the given type is a shell type. In this case
769 * the type has not been renamed out of the way, but nonetheless it can
770 * be expected that TypeCreate will succeed. This behavior is convenient
771 * for most callers --- those that need to distinguish the shell-type case
772 * must do their own typisdefined test.
775 moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
780 /* We need do nothing if it's a shell type. */
781 if (!get_typisdefined(typeOid))
784 /* Can't change it if it's not an autogenerated array type. */
785 elemOid = get_element_type(typeOid);
786 if (!OidIsValid(elemOid) ||
787 get_array_type(elemOid) != typeOid)
791 * OK, use makeArrayTypeName to pick an unused modification of the name.
792 * Note that since makeArrayTypeName is an iterative process, this will
793 * produce a name that it might have produced the first time, had the
794 * conflicting type we are about to create already existed.
796 newname = makeArrayTypeName(typeName, typeNamespace);
798 /* Apply the rename */
799 RenameTypeInternal(typeOid, newname, typeNamespace);
802 * We must bump the command counter so that any subsequent use of
803 * makeArrayTypeName sees what we just did and doesn't pick the same name.
805 CommandCounterIncrement();