1 /*-------------------------------------------------------------------------
2 *
3 * pg_type.c
4 * routines to support manipulation of the pg_type relation
5 *
6 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/catalog/pg_type.c
12 *
13 *-------------------------------------------------------------------------
14 */
15 #include "postgres.h"
16
17 #include "access/htup_details.h"
18 #include "access/table.h"
19 #include "access/xact.h"
20 #include "catalog/catalog.h"
21 #include "catalog/binary_upgrade.h"
22 #include "catalog/dependency.h"
23 #include "catalog/indexing.h"
24 #include "catalog/objectaccess.h"
25 #include "catalog/pg_collation.h"
26 #include "catalog/pg_namespace.h"
27 #include "catalog/pg_proc.h"
28 #include "catalog/pg_type.h"
29 #include "commands/typecmds.h"
30 #include "miscadmin.h"
31 #include "parser/scansup.h"
32 #include "utils/acl.h"
33 #include "utils/builtins.h"
34 #include "utils/fmgroids.h"
35 #include "utils/lsyscache.h"
36 #include "utils/rel.h"
37 #include "utils/syscache.h"
38
39 /* Potentially set by pg_upgrade_support functions */
40 Oid binary_upgrade_next_pg_type_oid = InvalidOid;
41
42 /* ----------------------------------------------------------------
43 * TypeShellMake
44 *
45 * This procedure inserts a "shell" tuple into the pg_type relation.
46 * The type tuple inserted has valid but dummy values, and its
47 * "typisdefined" field is false indicating it's not really defined.
48 *
49 * This is used so that a tuple exists in the catalogs. The I/O
50 * functions for the type will link to this tuple. When the full
51 * CREATE TYPE command is issued, the bogus values will be replaced
52 * with correct ones, and "typisdefined" will be set to true.
53 * ----------------------------------------------------------------
54 */
55 ObjectAddress
TypeShellMake(const char * typeName,Oid typeNamespace,Oid ownerId)56 TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
57 {
58 Relation pg_type_desc;
59 TupleDesc tupDesc;
60 int i;
61 HeapTuple tup;
62 Datum values[Natts_pg_type];
63 bool nulls[Natts_pg_type];
64 Oid typoid;
65 NameData name;
66 ObjectAddress address;
67
68 Assert(PointerIsValid(typeName));
69
70 /*
71 * open pg_type
72 */
73 pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
74 tupDesc = pg_type_desc->rd_att;
75
76 /*
77 * initialize our *nulls and *values arrays
78 */
79 for (i = 0; i < Natts_pg_type; ++i)
80 {
81 nulls[i] = false;
82 values[i] = (Datum) NULL; /* redundant, but safe */
83 }
84
85 /*
86 * initialize *values with the type name and dummy values
87 *
88 * The representational details are the same as int4 ... it doesn't really
89 * matter what they are so long as they are consistent. Also note that we
90 * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
91 * mistaken for a usable type.
92 */
93 namestrcpy(&name, typeName);
94 values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
95 values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
96 values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
97 values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32));
98 values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true);
99 values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO);
100 values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE);
101 values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false);
102 values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false);
103 values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM);
104 values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid);
105 values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid);
106 values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid);
107 values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN);
108 values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT);
109 values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid);
110 values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid);
111 values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid);
112 values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid);
113 values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid);
114 values[Anum_pg_type_typalign - 1] = CharGetDatum('i');
115 values[Anum_pg_type_typstorage - 1] = CharGetDatum('p');
116 values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false);
117 values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid);
118 values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
119 values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
120 values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
121 nulls[Anum_pg_type_typdefaultbin - 1] = true;
122 nulls[Anum_pg_type_typdefault - 1] = true;
123 nulls[Anum_pg_type_typacl - 1] = true;
124
125 /* Use binary-upgrade override for pg_type.oid? */
126 if (IsBinaryUpgrade)
127 {
128 if (!OidIsValid(binary_upgrade_next_pg_type_oid))
129 ereport(ERROR,
130 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
131 errmsg("pg_type OID value not set when in binary upgrade mode")));
132
133 typoid = binary_upgrade_next_pg_type_oid;
134 binary_upgrade_next_pg_type_oid = InvalidOid;
135 }
136 else
137 {
138 typoid = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
139 Anum_pg_type_oid);
140 }
141
142 values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typoid);
143
144 /*
145 * create a new type tuple
146 */
147 tup = heap_form_tuple(tupDesc, values, nulls);
148
149 /*
150 * insert the tuple in the relation and get the tuple's oid.
151 */
152 CatalogTupleInsert(pg_type_desc, tup);
153
154 /*
155 * Create dependencies. We can/must skip this in bootstrap mode.
156 */
157 if (!IsBootstrapProcessingMode())
158 GenerateTypeDependencies(typoid,
159 (Form_pg_type) GETSTRUCT(tup),
160 NULL,
161 NULL,
162 0,
163 false,
164 false,
165 false);
166
167 /* Post creation hook for new shell type */
168 InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
169
170 ObjectAddressSet(address, TypeRelationId, typoid);
171
172 /*
173 * clean up and return the type-oid
174 */
175 heap_freetuple(tup);
176 table_close(pg_type_desc, RowExclusiveLock);
177
178 return address;
179 }
180
181 /* ----------------------------------------------------------------
182 * TypeCreate
183 *
184 * This does all the necessary work needed to define a new type.
185 *
186 * Returns the ObjectAddress assigned to the new type.
187 * If newTypeOid is zero (the normal case), a new OID is created;
188 * otherwise we use exactly that OID.
189 * ----------------------------------------------------------------
190 */
191 ObjectAddress
TypeCreate(Oid newTypeOid,const char * typeName,Oid typeNamespace,Oid relationOid,char relationKind,Oid ownerId,int16 internalSize,char typeType,char typeCategory,bool typePreferred,char typDelim,Oid inputProcedure,Oid outputProcedure,Oid receiveProcedure,Oid sendProcedure,Oid typmodinProcedure,Oid typmodoutProcedure,Oid analyzeProcedure,Oid elementType,bool isImplicitArray,Oid arrayType,Oid baseType,const char * defaultTypeValue,char * defaultTypeBin,bool passedByValue,char alignment,char storage,int32 typeMod,int32 typNDims,bool typeNotNull,Oid typeCollation)192 TypeCreate(Oid newTypeOid,
193 const char *typeName,
194 Oid typeNamespace,
195 Oid relationOid, /* only for relation rowtypes */
196 char relationKind, /* ditto */
197 Oid ownerId,
198 int16 internalSize,
199 char typeType,
200 char typeCategory,
201 bool typePreferred,
202 char typDelim,
203 Oid inputProcedure,
204 Oid outputProcedure,
205 Oid receiveProcedure,
206 Oid sendProcedure,
207 Oid typmodinProcedure,
208 Oid typmodoutProcedure,
209 Oid analyzeProcedure,
210 Oid elementType,
211 bool isImplicitArray,
212 Oid arrayType,
213 Oid baseType,
214 const char *defaultTypeValue, /* human readable rep */
215 char *defaultTypeBin, /* cooked rep */
216 bool passedByValue,
217 char alignment,
218 char storage,
219 int32 typeMod,
220 int32 typNDims, /* Array dimensions for baseType */
221 bool typeNotNull,
222 Oid typeCollation)
223 {
224 Relation pg_type_desc;
225 Oid typeObjectId;
226 bool isDependentType;
227 bool rebuildDeps = false;
228 Acl *typacl;
229 HeapTuple tup;
230 bool nulls[Natts_pg_type];
231 bool replaces[Natts_pg_type];
232 Datum values[Natts_pg_type];
233 NameData name;
234 int i;
235 ObjectAddress address;
236
237 /*
238 * We assume that the caller validated the arguments individually, but did
239 * not check for bad combinations.
240 *
241 * Validate size specifications: either positive (fixed-length) or -1
242 * (varlena) or -2 (cstring).
243 */
244 if (!(internalSize > 0 ||
245 internalSize == -1 ||
246 internalSize == -2))
247 ereport(ERROR,
248 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
249 errmsg("invalid type internal size %d",
250 internalSize)));
251
252 if (passedByValue)
253 {
254 /*
255 * Pass-by-value types must have a fixed length that is one of the
256 * values supported by fetch_att() and store_att_byval(); and the
257 * alignment had better agree, too. All this code must match
258 * access/tupmacs.h!
259 */
260 if (internalSize == (int16) sizeof(char))
261 {
262 if (alignment != 'c')
263 ereport(ERROR,
264 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
265 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
266 alignment, internalSize)));
267 }
268 else if (internalSize == (int16) sizeof(int16))
269 {
270 if (alignment != 's')
271 ereport(ERROR,
272 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
273 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
274 alignment, internalSize)));
275 }
276 else if (internalSize == (int16) sizeof(int32))
277 {
278 if (alignment != 'i')
279 ereport(ERROR,
280 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
281 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
282 alignment, internalSize)));
283 }
284 #if SIZEOF_DATUM == 8
285 else if (internalSize == (int16) sizeof(Datum))
286 {
287 if (alignment != 'd')
288 ereport(ERROR,
289 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
290 errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
291 alignment, internalSize)));
292 }
293 #endif
294 else
295 ereport(ERROR,
296 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
297 errmsg("internal size %d is invalid for passed-by-value type",
298 internalSize)));
299 }
300 else
301 {
302 /* varlena types must have int align or better */
303 if (internalSize == -1 && !(alignment == 'i' || alignment == 'd'))
304 ereport(ERROR,
305 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
306 errmsg("alignment \"%c\" is invalid for variable-length type",
307 alignment)));
308 /* cstring must have char alignment */
309 if (internalSize == -2 && !(alignment == 'c'))
310 ereport(ERROR,
311 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
312 errmsg("alignment \"%c\" is invalid for variable-length type",
313 alignment)));
314 }
315
316 /* Only varlena types can be toasted */
317 if (storage != 'p' && internalSize != -1)
318 ereport(ERROR,
319 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
320 errmsg("fixed-size types must have storage PLAIN")));
321
322 /*
323 * This is a dependent type if it's an implicitly-created array type, or
324 * if it's a relation rowtype that's not a composite type. For such types
325 * we'll leave the ACL empty, and we'll skip creating some dependency
326 * records because there will be a dependency already through the
327 * depended-on type or relation. (Caution: this is closely intertwined
328 * with some behavior in GenerateTypeDependencies.)
329 */
330 isDependentType = isImplicitArray ||
331 (OidIsValid(relationOid) && relationKind != RELKIND_COMPOSITE_TYPE);
332
333 /*
334 * initialize arrays needed for heap_form_tuple or heap_modify_tuple
335 */
336 for (i = 0; i < Natts_pg_type; ++i)
337 {
338 nulls[i] = false;
339 replaces[i] = true;
340 values[i] = (Datum) 0;
341 }
342
343 /*
344 * insert data values
345 */
346 namestrcpy(&name, typeName);
347 values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
348 values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
349 values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
350 values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize);
351 values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue);
352 values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType);
353 values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory);
354 values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred);
355 values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true);
356 values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim);
357 values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid);
358 values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType);
359 values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType);
360 values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure);
361 values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure);
362 values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure);
363 values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure);
364 values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure);
365 values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure);
366 values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure);
367 values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment);
368 values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage);
369 values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull);
370 values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType);
371 values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
372 values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
373 values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation);
374
375 /*
376 * initialize the default binary value for this type. Check for nulls of
377 * course.
378 */
379 if (defaultTypeBin)
380 values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin);
381 else
382 nulls[Anum_pg_type_typdefaultbin - 1] = true;
383
384 /*
385 * initialize the default value for this type.
386 */
387 if (defaultTypeValue)
388 values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue);
389 else
390 nulls[Anum_pg_type_typdefault - 1] = true;
391
392 /*
393 * Initialize the type's ACL, too. But dependent types don't get one.
394 */
395 if (isDependentType)
396 typacl = NULL;
397 else
398 typacl = get_user_default_acl(OBJECT_TYPE, ownerId,
399 typeNamespace);
400 if (typacl != NULL)
401 values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
402 else
403 nulls[Anum_pg_type_typacl - 1] = true;
404
405 /*
406 * open pg_type and prepare to insert or update a row.
407 *
408 * NOTE: updating will not work correctly in bootstrap mode; but we don't
409 * expect to be overwriting any shell types in bootstrap mode.
410 */
411 pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
412
413 tup = SearchSysCacheCopy2(TYPENAMENSP,
414 CStringGetDatum(typeName),
415 ObjectIdGetDatum(typeNamespace));
416 if (HeapTupleIsValid(tup))
417 {
418 Form_pg_type typform = (Form_pg_type) GETSTRUCT(tup);
419
420 /*
421 * check that the type is not already defined. It may exist as a
422 * shell type, however.
423 */
424 if (typform->typisdefined)
425 ereport(ERROR,
426 (errcode(ERRCODE_DUPLICATE_OBJECT),
427 errmsg("type \"%s\" already exists", typeName)));
428
429 /*
430 * shell type must have been created by same owner
431 */
432 if (typform->typowner != ownerId)
433 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TYPE, typeName);
434
435 /* trouble if caller wanted to force the OID */
436 if (OidIsValid(newTypeOid))
437 elog(ERROR, "cannot assign new OID to existing shell type");
438
439 replaces[Anum_pg_type_oid - 1] = false;
440
441 /*
442 * Okay to update existing shell type tuple
443 */
444 tup = heap_modify_tuple(tup,
445 RelationGetDescr(pg_type_desc),
446 values,
447 nulls,
448 replaces);
449
450 CatalogTupleUpdate(pg_type_desc, &tup->t_self, tup);
451
452 typeObjectId = typform->oid;
453
454 rebuildDeps = true; /* get rid of shell type's dependencies */
455 }
456 else
457 {
458 /* Force the OID if requested by caller */
459 if (OidIsValid(newTypeOid))
460 typeObjectId = newTypeOid;
461 /* Use binary-upgrade override for pg_type.oid, if supplied. */
462 else if (IsBinaryUpgrade)
463 {
464 if (!OidIsValid(binary_upgrade_next_pg_type_oid))
465 ereport(ERROR,
466 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
467 errmsg("pg_type OID value not set when in binary upgrade mode")));
468
469 typeObjectId = binary_upgrade_next_pg_type_oid;
470 binary_upgrade_next_pg_type_oid = InvalidOid;
471 }
472 else
473 {
474 typeObjectId = GetNewOidWithIndex(pg_type_desc, TypeOidIndexId,
475 Anum_pg_type_oid);
476 }
477
478 values[Anum_pg_type_oid - 1] = ObjectIdGetDatum(typeObjectId);
479
480 tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
481 values, nulls);
482
483 CatalogTupleInsert(pg_type_desc, tup);
484 }
485
486 /*
487 * Create dependencies. We can/must skip this in bootstrap mode.
488 */
489 if (!IsBootstrapProcessingMode())
490 GenerateTypeDependencies(typeObjectId,
491 (Form_pg_type) GETSTRUCT(tup),
492 (defaultTypeBin ?
493 stringToNode(defaultTypeBin) :
494 NULL),
495 typacl,
496 relationKind,
497 isImplicitArray,
498 isDependentType,
499 rebuildDeps);
500
501 /* Post creation hook for new type */
502 InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
503
504 ObjectAddressSet(address, TypeRelationId, typeObjectId);
505
506 /*
507 * finish up
508 */
509 table_close(pg_type_desc, RowExclusiveLock);
510
511 return address;
512 }
513
514 /*
515 * GenerateTypeDependencies: build the dependencies needed for a type
516 *
517 * Most of what this function needs to know about the type is passed as the
518 * new pg_type row, typeForm. But we can't get at the varlena fields through
519 * that, so defaultExpr and typacl are passed separately. (typacl is really
520 * "Acl *", but we declare it "void *" to avoid including acl.h in pg_type.h.)
521 *
522 * relationKind and isImplicitArray aren't visible in the pg_type row either,
523 * so they're also passed separately.
524 *
525 * isDependentType is true if this is an implicit array or relation rowtype;
526 * that means it doesn't need its own dependencies on owner etc.
527 *
528 * If rebuild is true, we remove existing dependencies and rebuild them
529 * from scratch. This is needed for ALTER TYPE, and also when replacing
530 * a shell type. We don't remove an existing extension dependency, though.
531 * (That means an extension can't absorb a shell type created in another
532 * extension, nor ALTER a type created by another extension. Also, if it
533 * replaces a free-standing shell type or ALTERs a free-standing type,
534 * that type will become a member of the extension.)
535 */
536 void
GenerateTypeDependencies(Oid typeObjectId,Form_pg_type typeForm,Node * defaultExpr,void * typacl,char relationKind,bool isImplicitArray,bool isDependentType,bool rebuild)537 GenerateTypeDependencies(Oid typeObjectId,
538 Form_pg_type typeForm,
539 Node *defaultExpr,
540 void *typacl,
541 char relationKind, /* only for relation rowtypes */
542 bool isImplicitArray,
543 bool isDependentType,
544 bool rebuild)
545 {
546 ObjectAddress myself,
547 referenced;
548
549 /* If rebuild, first flush old dependencies, except extension deps */
550 if (rebuild)
551 {
552 deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
553 deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
554 }
555
556 myself.classId = TypeRelationId;
557 myself.objectId = typeObjectId;
558 myself.objectSubId = 0;
559
560 /*
561 * Make dependencies on namespace, owner, ACL, extension.
562 *
563 * Skip these for a dependent type, since it will have such dependencies
564 * indirectly through its depended-on type or relation.
565 */
566 if (!isDependentType)
567 {
568 referenced.classId = NamespaceRelationId;
569 referenced.objectId = typeForm->typnamespace;
570 referenced.objectSubId = 0;
571 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
572
573 recordDependencyOnOwner(TypeRelationId, typeObjectId,
574 typeForm->typowner);
575
576 recordDependencyOnNewAcl(TypeRelationId, typeObjectId, 0,
577 typeForm->typowner, typacl);
578
579 recordDependencyOnCurrentExtension(&myself, rebuild);
580 }
581
582 /* Normal dependencies on the I/O functions */
583 if (OidIsValid(typeForm->typinput))
584 {
585 referenced.classId = ProcedureRelationId;
586 referenced.objectId = typeForm->typinput;
587 referenced.objectSubId = 0;
588 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
589 }
590
591 if (OidIsValid(typeForm->typoutput))
592 {
593 referenced.classId = ProcedureRelationId;
594 referenced.objectId = typeForm->typoutput;
595 referenced.objectSubId = 0;
596 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
597 }
598
599 if (OidIsValid(typeForm->typreceive))
600 {
601 referenced.classId = ProcedureRelationId;
602 referenced.objectId = typeForm->typreceive;
603 referenced.objectSubId = 0;
604 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
605 }
606
607 if (OidIsValid(typeForm->typsend))
608 {
609 referenced.classId = ProcedureRelationId;
610 referenced.objectId = typeForm->typsend;
611 referenced.objectSubId = 0;
612 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
613 }
614
615 if (OidIsValid(typeForm->typmodin))
616 {
617 referenced.classId = ProcedureRelationId;
618 referenced.objectId = typeForm->typmodin;
619 referenced.objectSubId = 0;
620 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
621 }
622
623 if (OidIsValid(typeForm->typmodout))
624 {
625 referenced.classId = ProcedureRelationId;
626 referenced.objectId = typeForm->typmodout;
627 referenced.objectSubId = 0;
628 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
629 }
630
631 if (OidIsValid(typeForm->typanalyze))
632 {
633 referenced.classId = ProcedureRelationId;
634 referenced.objectId = typeForm->typanalyze;
635 referenced.objectSubId = 0;
636 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
637 }
638
639 /*
640 * If the type is a rowtype for a relation, mark it as internally
641 * dependent on the relation, *unless* it is a stand-alone composite type
642 * relation. For the latter case, we have to reverse the dependency.
643 *
644 * In the former case, this allows the type to be auto-dropped when the
645 * relation is, and not otherwise. And in the latter, of course we get the
646 * opposite effect.
647 */
648 if (OidIsValid(typeForm->typrelid))
649 {
650 referenced.classId = RelationRelationId;
651 referenced.objectId = typeForm->typrelid;
652 referenced.objectSubId = 0;
653
654 if (relationKind != RELKIND_COMPOSITE_TYPE)
655 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
656 else
657 recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
658 }
659
660 /*
661 * If the type is an implicitly-created array type, mark it as internally
662 * dependent on the element type. Otherwise, if it has an element type,
663 * the dependency is a normal one.
664 */
665 if (OidIsValid(typeForm->typelem))
666 {
667 referenced.classId = TypeRelationId;
668 referenced.objectId = typeForm->typelem;
669 referenced.objectSubId = 0;
670 recordDependencyOn(&myself, &referenced,
671 isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
672 }
673
674 /* Normal dependency from a domain to its base type. */
675 if (OidIsValid(typeForm->typbasetype))
676 {
677 referenced.classId = TypeRelationId;
678 referenced.objectId = typeForm->typbasetype;
679 referenced.objectSubId = 0;
680 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
681 }
682
683 /* Normal dependency from a domain to its collation. */
684 /* We know the default collation is pinned, so don't bother recording it */
685 if (OidIsValid(typeForm->typcollation) &&
686 typeForm->typcollation != DEFAULT_COLLATION_OID)
687 {
688 referenced.classId = CollationRelationId;
689 referenced.objectId = typeForm->typcollation;
690 referenced.objectSubId = 0;
691 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
692 }
693
694 /* Normal dependency on the default expression. */
695 if (defaultExpr)
696 recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
697 }
698
699 /*
700 * RenameTypeInternal
701 * This renames a type, as well as any associated array type.
702 *
703 * Caller must have already checked privileges.
704 *
705 * Currently this is used for renaming table rowtypes and for
706 * ALTER TYPE RENAME TO command.
707 */
708 void
RenameTypeInternal(Oid typeOid,const char * newTypeName,Oid typeNamespace)709 RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
710 {
711 Relation pg_type_desc;
712 HeapTuple tuple;
713 Form_pg_type typ;
714 Oid arrayOid;
715 Oid oldTypeOid;
716
717 pg_type_desc = table_open(TypeRelationId, RowExclusiveLock);
718
719 tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
720 if (!HeapTupleIsValid(tuple))
721 elog(ERROR, "cache lookup failed for type %u", typeOid);
722 typ = (Form_pg_type) GETSTRUCT(tuple);
723
724 /* We are not supposed to be changing schemas here */
725 Assert(typeNamespace == typ->typnamespace);
726
727 arrayOid = typ->typarray;
728
729 /* Check for a conflicting type name. */
730 oldTypeOid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
731 CStringGetDatum(newTypeName),
732 ObjectIdGetDatum(typeNamespace));
733
734 /*
735 * If there is one, see if it's an autogenerated array type, and if so
736 * rename it out of the way. (But we must skip that for a shell type
737 * because moveArrayTypeName will do the wrong thing in that case.)
738 * Otherwise, we can at least give a more friendly error than unique-index
739 * violation.
740 */
741 if (OidIsValid(oldTypeOid))
742 {
743 if (get_typisdefined(oldTypeOid) &&
744 moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace))
745 /* successfully dodged the problem */ ;
746 else
747 ereport(ERROR,
748 (errcode(ERRCODE_DUPLICATE_OBJECT),
749 errmsg("type \"%s\" already exists", newTypeName)));
750 }
751
752 /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
753 namestrcpy(&(typ->typname), newTypeName);
754
755 CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple);
756
757 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
758
759 heap_freetuple(tuple);
760 table_close(pg_type_desc, RowExclusiveLock);
761
762 /*
763 * If the type has an array type, recurse to handle that. But we don't
764 * need to do anything more if we already renamed that array type above
765 * (which would happen when, eg, renaming "foo" to "_foo").
766 */
767 if (OidIsValid(arrayOid) && arrayOid != oldTypeOid)
768 {
769 char *arrname = makeArrayTypeName(newTypeName, typeNamespace);
770
771 RenameTypeInternal(arrayOid, arrname, typeNamespace);
772 pfree(arrname);
773 }
774 }
775
776
777 /*
778 * makeArrayTypeName
779 * - given a base type name, make an array type name for it
780 *
781 * the caller is responsible for pfreeing the result
782 */
783 char *
makeArrayTypeName(const char * typeName,Oid typeNamespace)784 makeArrayTypeName(const char *typeName, Oid typeNamespace)
785 {
786 char *arr = (char *) palloc(NAMEDATALEN);
787 int namelen = strlen(typeName);
788 Relation pg_type_desc;
789 int i;
790
791 /*
792 * The idea is to prepend underscores as needed until we make a name that
793 * doesn't collide with anything...
794 */
795 pg_type_desc = table_open(TypeRelationId, AccessShareLock);
796
797 for (i = 1; i < NAMEDATALEN - 1; i++)
798 {
799 arr[i - 1] = '_';
800 if (i + namelen < NAMEDATALEN)
801 strcpy(arr + i, typeName);
802 else
803 {
804 memcpy(arr + i, typeName, NAMEDATALEN - i);
805 truncate_identifier(arr, NAMEDATALEN, false);
806 }
807 if (!SearchSysCacheExists2(TYPENAMENSP,
808 CStringGetDatum(arr),
809 ObjectIdGetDatum(typeNamespace)))
810 break;
811 }
812
813 table_close(pg_type_desc, AccessShareLock);
814
815 if (i >= NAMEDATALEN - 1)
816 ereport(ERROR,
817 (errcode(ERRCODE_DUPLICATE_OBJECT),
818 errmsg("could not form array type name for type \"%s\"",
819 typeName)));
820
821 return arr;
822 }
823
824
825 /*
826 * moveArrayTypeName
827 * - try to reassign an array type name that the user wants to use.
828 *
829 * The given type name has been discovered to already exist (with the given
830 * OID). If it is an autogenerated array type, change the array type's name
831 * to not conflict. This allows the user to create type "foo" followed by
832 * type "_foo" without problems. (Of course, there are race conditions if
833 * two backends try to create similarly-named types concurrently, but the
834 * worst that can happen is an unnecessary failure --- anything we do here
835 * will be rolled back if the type creation fails due to conflicting names.)
836 *
837 * Note that this must be called *before* calling makeArrayTypeName to
838 * determine the new type's own array type name; else the latter will
839 * certainly pick the same name.
840 *
841 * Returns true if successfully moved the type, false if not.
842 *
843 * We also return true if the given type is a shell type. In this case
844 * the type has not been renamed out of the way, but nonetheless it can
845 * be expected that TypeCreate will succeed. This behavior is convenient
846 * for most callers --- those that need to distinguish the shell-type case
847 * must do their own typisdefined test.
848 */
849 bool
moveArrayTypeName(Oid typeOid,const char * typeName,Oid typeNamespace)850 moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
851 {
852 Oid elemOid;
853 char *newname;
854
855 /* We need do nothing if it's a shell type. */
856 if (!get_typisdefined(typeOid))
857 return true;
858
859 /* Can't change it if it's not an autogenerated array type. */
860 elemOid = get_element_type(typeOid);
861 if (!OidIsValid(elemOid) ||
862 get_array_type(elemOid) != typeOid)
863 return false;
864
865 /*
866 * OK, use makeArrayTypeName to pick an unused modification of the name.
867 * Note that since makeArrayTypeName is an iterative process, this will
868 * produce a name that it might have produced the first time, had the
869 * conflicting type we are about to create already existed.
870 */
871 newname = makeArrayTypeName(typeName, typeNamespace);
872
873 /* Apply the rename */
874 RenameTypeInternal(typeOid, newname, typeNamespace);
875
876 /*
877 * We must bump the command counter so that any subsequent use of
878 * makeArrayTypeName sees what we just did and doesn't pick the same name.
879 */
880 CommandCounterIncrement();
881
882 pfree(newname);
883
884 return true;
885 }
886