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