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