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