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