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