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