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