1 /*-------------------------------------------------------------------------
2  *
3  * typecmds.c
4  *	  Routines for SQL commands that manipulate types (and domains).
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/commands/typecmds.c
12  *
13  * DESCRIPTION
14  *	  The "DefineFoo" routines take the parse tree and pick out the
15  *	  appropriate arguments/flags, passing the results to the
16  *	  corresponding "FooDefine" routines (in src/catalog) that do
17  *	  the actual catalog-munging.  These routines also verify permission
18  *	  of the user to execute the command.
19  *
20  * NOTES
21  *	  These things must be defined and committed in the following order:
22  *		"create function":
23  *				input/output, recv/send functions
24  *		"create type":
25  *				type
26  *		"create operator":
27  *				operators
28  *
29  *
30  *-------------------------------------------------------------------------
31  */
32 #include "postgres.h"
33 
34 #include "access/htup_details.h"
35 #include "access/xact.h"
36 #include "catalog/binary_upgrade.h"
37 #include "catalog/catalog.h"
38 #include "catalog/heap.h"
39 #include "catalog/objectaccess.h"
40 #include "catalog/pg_am.h"
41 #include "catalog/pg_authid.h"
42 #include "catalog/pg_collation.h"
43 #include "catalog/pg_constraint.h"
44 #include "catalog/pg_constraint_fn.h"
45 #include "catalog/pg_depend.h"
46 #include "catalog/pg_enum.h"
47 #include "catalog/pg_language.h"
48 #include "catalog/pg_namespace.h"
49 #include "catalog/pg_proc.h"
50 #include "catalog/pg_proc_fn.h"
51 #include "catalog/pg_range.h"
52 #include "catalog/pg_type.h"
53 #include "catalog/pg_type_fn.h"
54 #include "commands/defrem.h"
55 #include "commands/tablecmds.h"
56 #include "commands/typecmds.h"
57 #include "executor/executor.h"
58 #include "miscadmin.h"
59 #include "nodes/makefuncs.h"
60 #include "optimizer/var.h"
61 #include "parser/parse_coerce.h"
62 #include "parser/parse_collate.h"
63 #include "parser/parse_expr.h"
64 #include "parser/parse_func.h"
65 #include "parser/parse_type.h"
66 #include "utils/builtins.h"
67 #include "utils/fmgroids.h"
68 #include "utils/lsyscache.h"
69 #include "utils/memutils.h"
70 #include "utils/rel.h"
71 #include "utils/ruleutils.h"
72 #include "utils/snapmgr.h"
73 #include "utils/syscache.h"
74 
75 
76 /* result structure for get_rels_with_domain() */
77 typedef struct
78 {
79 	Relation	rel;			/* opened and locked relation */
80 	int			natts;			/* number of attributes of interest */
81 	int		   *atts;			/* attribute numbers */
82 	/* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
83 } RelToCheck;
84 
85 /* Potentially set by pg_upgrade_support functions */
86 Oid			binary_upgrade_next_array_pg_type_oid = InvalidOid;
87 
88 static void makeRangeConstructors(const char *name, Oid namespace,
89 					  Oid rangeOid, Oid subtype);
90 static Oid	findTypeInputFunction(List *procname, Oid typeOid);
91 static Oid	findTypeOutputFunction(List *procname, Oid typeOid);
92 static Oid	findTypeReceiveFunction(List *procname, Oid typeOid);
93 static Oid	findTypeSendFunction(List *procname, Oid typeOid);
94 static Oid	findTypeTypmodinFunction(List *procname);
95 static Oid	findTypeTypmodoutFunction(List *procname);
96 static Oid	findTypeAnalyzeFunction(List *procname, Oid typeOid);
97 static Oid	findRangeSubOpclass(List *opcname, Oid subtype);
98 static Oid	findRangeCanonicalFunction(List *procname, Oid typeOid);
99 static Oid	findRangeSubtypeDiffFunction(List *procname, Oid subtype);
100 static void validateDomainConstraint(Oid domainoid, char *ccbin);
101 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
102 static void checkEnumOwner(HeapTuple tup);
103 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
104 					Oid baseTypeOid,
105 					int typMod, Constraint *constr,
106 					char *domainName, ObjectAddress *constrAddr);
107 
108 
109 /*
110  * DefineType
111  *		Registers a new base type.
112  */
113 ObjectAddress
DefineType(List * names,List * parameters)114 DefineType(List *names, List *parameters)
115 {
116 	char	   *typeName;
117 	Oid			typeNamespace;
118 	int16		internalLength = -1;	/* default: variable-length */
119 	List	   *inputName = NIL;
120 	List	   *outputName = NIL;
121 	List	   *receiveName = NIL;
122 	List	   *sendName = NIL;
123 	List	   *typmodinName = NIL;
124 	List	   *typmodoutName = NIL;
125 	List	   *analyzeName = NIL;
126 	char		category = TYPCATEGORY_USER;
127 	bool		preferred = false;
128 	char		delimiter = DEFAULT_TYPDELIM;
129 	Oid			elemType = InvalidOid;
130 	char	   *defaultValue = NULL;
131 	bool		byValue = false;
132 	char		alignment = 'i';	/* default alignment */
133 	char		storage = 'p';	/* default TOAST storage method */
134 	Oid			collation = InvalidOid;
135 	DefElem    *likeTypeEl = NULL;
136 	DefElem    *internalLengthEl = NULL;
137 	DefElem    *inputNameEl = NULL;
138 	DefElem    *outputNameEl = NULL;
139 	DefElem    *receiveNameEl = NULL;
140 	DefElem    *sendNameEl = NULL;
141 	DefElem    *typmodinNameEl = NULL;
142 	DefElem    *typmodoutNameEl = NULL;
143 	DefElem    *analyzeNameEl = NULL;
144 	DefElem    *categoryEl = NULL;
145 	DefElem    *preferredEl = NULL;
146 	DefElem    *delimiterEl = NULL;
147 	DefElem    *elemTypeEl = NULL;
148 	DefElem    *defaultValueEl = NULL;
149 	DefElem    *byValueEl = NULL;
150 	DefElem    *alignmentEl = NULL;
151 	DefElem    *storageEl = NULL;
152 	DefElem    *collatableEl = NULL;
153 	Oid			inputOid;
154 	Oid			outputOid;
155 	Oid			receiveOid = InvalidOid;
156 	Oid			sendOid = InvalidOid;
157 	Oid			typmodinOid = InvalidOid;
158 	Oid			typmodoutOid = InvalidOid;
159 	Oid			analyzeOid = InvalidOid;
160 	char	   *array_type;
161 	Oid			array_oid;
162 	Oid			typoid;
163 	Oid			resulttype;
164 	ListCell   *pl;
165 	ObjectAddress address;
166 
167 	/*
168 	 * As of Postgres 8.4, we require superuser privilege to create a base
169 	 * type.  This is simple paranoia: there are too many ways to mess up the
170 	 * system with an incorrect type definition (for instance, representation
171 	 * parameters that don't match what the C code expects).  In practice it
172 	 * takes superuser privilege to create the I/O functions, and so the
173 	 * former requirement that you own the I/O functions pretty much forced
174 	 * superuserness anyway.  We're just making doubly sure here.
175 	 *
176 	 * XXX re-enable NOT_USED code sections below if you remove this test.
177 	 */
178 	if (!superuser())
179 		ereport(ERROR,
180 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
181 				 errmsg("must be superuser to create a base type")));
182 
183 	/* Convert list of names to a name and namespace */
184 	typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
185 
186 #ifdef NOT_USED
187 	/* XXX this is unnecessary given the superuser check above */
188 	/* Check we have creation rights in target namespace */
189 	aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
190 	if (aclresult != ACLCHECK_OK)
191 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
192 					   get_namespace_name(typeNamespace));
193 #endif
194 
195 	/*
196 	 * Look to see if type already exists (presumably as a shell; if not,
197 	 * TypeCreate will complain).
198 	 */
199 	typoid = GetSysCacheOid2(TYPENAMENSP,
200 							 CStringGetDatum(typeName),
201 							 ObjectIdGetDatum(typeNamespace));
202 
203 	/*
204 	 * If it's not a shell, see if it's an autogenerated array type, and if so
205 	 * rename it out of the way.
206 	 */
207 	if (OidIsValid(typoid) && get_typisdefined(typoid))
208 	{
209 		if (moveArrayTypeName(typoid, typeName, typeNamespace))
210 			typoid = InvalidOid;
211 	}
212 
213 	/*
214 	 * If it doesn't exist, create it as a shell, so that the OID is known for
215 	 * use in the I/O function definitions.
216 	 */
217 	if (!OidIsValid(typoid))
218 	{
219 		address = TypeShellMake(typeName, typeNamespace, GetUserId());
220 		typoid = address.objectId;
221 		/* Make new shell type visible for modification below */
222 		CommandCounterIncrement();
223 
224 		/*
225 		 * If the command was a parameterless CREATE TYPE, we're done ---
226 		 * creating the shell type was all we're supposed to do.
227 		 */
228 		if (parameters == NIL)
229 			return address;
230 	}
231 	else
232 	{
233 		/* Complain if dummy CREATE TYPE and entry already exists */
234 		if (parameters == NIL)
235 			ereport(ERROR,
236 					(errcode(ERRCODE_DUPLICATE_OBJECT),
237 					 errmsg("type \"%s\" already exists", typeName)));
238 	}
239 
240 	/* Extract the parameters from the parameter list */
241 	foreach(pl, parameters)
242 	{
243 		DefElem    *defel = (DefElem *) lfirst(pl);
244 		DefElem   **defelp;
245 
246 		if (pg_strcasecmp(defel->defname, "like") == 0)
247 			defelp = &likeTypeEl;
248 		else if (pg_strcasecmp(defel->defname, "internallength") == 0)
249 			defelp = &internalLengthEl;
250 		else if (pg_strcasecmp(defel->defname, "input") == 0)
251 			defelp = &inputNameEl;
252 		else if (pg_strcasecmp(defel->defname, "output") == 0)
253 			defelp = &outputNameEl;
254 		else if (pg_strcasecmp(defel->defname, "receive") == 0)
255 			defelp = &receiveNameEl;
256 		else if (pg_strcasecmp(defel->defname, "send") == 0)
257 			defelp = &sendNameEl;
258 		else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
259 			defelp = &typmodinNameEl;
260 		else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
261 			defelp = &typmodoutNameEl;
262 		else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
263 				 pg_strcasecmp(defel->defname, "analyse") == 0)
264 			defelp = &analyzeNameEl;
265 		else if (pg_strcasecmp(defel->defname, "category") == 0)
266 			defelp = &categoryEl;
267 		else if (pg_strcasecmp(defel->defname, "preferred") == 0)
268 			defelp = &preferredEl;
269 		else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
270 			defelp = &delimiterEl;
271 		else if (pg_strcasecmp(defel->defname, "element") == 0)
272 			defelp = &elemTypeEl;
273 		else if (pg_strcasecmp(defel->defname, "default") == 0)
274 			defelp = &defaultValueEl;
275 		else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
276 			defelp = &byValueEl;
277 		else if (pg_strcasecmp(defel->defname, "alignment") == 0)
278 			defelp = &alignmentEl;
279 		else if (pg_strcasecmp(defel->defname, "storage") == 0)
280 			defelp = &storageEl;
281 		else if (pg_strcasecmp(defel->defname, "collatable") == 0)
282 			defelp = &collatableEl;
283 		else
284 		{
285 			/* WARNING, not ERROR, for historical backwards-compatibility */
286 			ereport(WARNING,
287 					(errcode(ERRCODE_SYNTAX_ERROR),
288 					 errmsg("type attribute \"%s\" not recognized",
289 							defel->defname)));
290 			continue;
291 		}
292 		if (*defelp != NULL)
293 			ereport(ERROR,
294 					(errcode(ERRCODE_SYNTAX_ERROR),
295 					 errmsg("conflicting or redundant options")));
296 		*defelp = defel;
297 	}
298 
299 	/*
300 	 * Now interpret the options; we do this separately so that LIKE can be
301 	 * overridden by other options regardless of the ordering in the parameter
302 	 * list.
303 	 */
304 	if (likeTypeEl)
305 	{
306 		Type		likeType;
307 		Form_pg_type likeForm;
308 
309 		likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
310 		likeForm = (Form_pg_type) GETSTRUCT(likeType);
311 		internalLength = likeForm->typlen;
312 		byValue = likeForm->typbyval;
313 		alignment = likeForm->typalign;
314 		storage = likeForm->typstorage;
315 		ReleaseSysCache(likeType);
316 	}
317 	if (internalLengthEl)
318 		internalLength = defGetTypeLength(internalLengthEl);
319 	if (inputNameEl)
320 		inputName = defGetQualifiedName(inputNameEl);
321 	if (outputNameEl)
322 		outputName = defGetQualifiedName(outputNameEl);
323 	if (receiveNameEl)
324 		receiveName = defGetQualifiedName(receiveNameEl);
325 	if (sendNameEl)
326 		sendName = defGetQualifiedName(sendNameEl);
327 	if (typmodinNameEl)
328 		typmodinName = defGetQualifiedName(typmodinNameEl);
329 	if (typmodoutNameEl)
330 		typmodoutName = defGetQualifiedName(typmodoutNameEl);
331 	if (analyzeNameEl)
332 		analyzeName = defGetQualifiedName(analyzeNameEl);
333 	if (categoryEl)
334 	{
335 		char	   *p = defGetString(categoryEl);
336 
337 		category = p[0];
338 		/* restrict to non-control ASCII */
339 		if (category < 32 || category > 126)
340 			ereport(ERROR,
341 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
342 				 errmsg("invalid type category \"%s\": must be simple ASCII",
343 						p)));
344 	}
345 	if (preferredEl)
346 		preferred = defGetBoolean(preferredEl);
347 	if (delimiterEl)
348 	{
349 		char	   *p = defGetString(delimiterEl);
350 
351 		delimiter = p[0];
352 		/* XXX shouldn't we restrict the delimiter? */
353 	}
354 	if (elemTypeEl)
355 	{
356 		elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
357 		/* disallow arrays of pseudotypes */
358 		if (get_typtype(elemType) == TYPTYPE_PSEUDO)
359 			ereport(ERROR,
360 					(errcode(ERRCODE_DATATYPE_MISMATCH),
361 					 errmsg("array element type cannot be %s",
362 							format_type_be(elemType))));
363 	}
364 	if (defaultValueEl)
365 		defaultValue = defGetString(defaultValueEl);
366 	if (byValueEl)
367 		byValue = defGetBoolean(byValueEl);
368 	if (alignmentEl)
369 	{
370 		char	   *a = defGetString(alignmentEl);
371 
372 		/*
373 		 * Note: if argument was an unquoted identifier, parser will have
374 		 * applied translations to it, so be prepared to recognize translated
375 		 * type names as well as the nominal form.
376 		 */
377 		if (pg_strcasecmp(a, "double") == 0 ||
378 			pg_strcasecmp(a, "float8") == 0 ||
379 			pg_strcasecmp(a, "pg_catalog.float8") == 0)
380 			alignment = 'd';
381 		else if (pg_strcasecmp(a, "int4") == 0 ||
382 				 pg_strcasecmp(a, "pg_catalog.int4") == 0)
383 			alignment = 'i';
384 		else if (pg_strcasecmp(a, "int2") == 0 ||
385 				 pg_strcasecmp(a, "pg_catalog.int2") == 0)
386 			alignment = 's';
387 		else if (pg_strcasecmp(a, "char") == 0 ||
388 				 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
389 			alignment = 'c';
390 		else
391 			ereport(ERROR,
392 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
393 					 errmsg("alignment \"%s\" not recognized", a)));
394 	}
395 	if (storageEl)
396 	{
397 		char	   *a = defGetString(storageEl);
398 
399 		if (pg_strcasecmp(a, "plain") == 0)
400 			storage = 'p';
401 		else if (pg_strcasecmp(a, "external") == 0)
402 			storage = 'e';
403 		else if (pg_strcasecmp(a, "extended") == 0)
404 			storage = 'x';
405 		else if (pg_strcasecmp(a, "main") == 0)
406 			storage = 'm';
407 		else
408 			ereport(ERROR,
409 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
410 					 errmsg("storage \"%s\" not recognized", a)));
411 	}
412 	if (collatableEl)
413 		collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
414 
415 	/*
416 	 * make sure we have our required definitions
417 	 */
418 	if (inputName == NIL)
419 		ereport(ERROR,
420 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
421 				 errmsg("type input function must be specified")));
422 	if (outputName == NIL)
423 		ereport(ERROR,
424 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
425 				 errmsg("type output function must be specified")));
426 
427 	if (typmodinName == NIL && typmodoutName != NIL)
428 		ereport(ERROR,
429 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
430 				 errmsg("type modifier output function is useless without a type modifier input function")));
431 
432 	/*
433 	 * Convert I/O proc names to OIDs
434 	 */
435 	inputOid = findTypeInputFunction(inputName, typoid);
436 	outputOid = findTypeOutputFunction(outputName, typoid);
437 	if (receiveName)
438 		receiveOid = findTypeReceiveFunction(receiveName, typoid);
439 	if (sendName)
440 		sendOid = findTypeSendFunction(sendName, typoid);
441 
442 	/*
443 	 * Verify that I/O procs return the expected thing.  If we see OPAQUE,
444 	 * complain and change it to the correct type-safe choice.
445 	 */
446 	resulttype = get_func_rettype(inputOid);
447 	if (resulttype != typoid)
448 	{
449 		if (resulttype == OPAQUEOID)
450 		{
451 			/* backwards-compatibility hack */
452 			ereport(WARNING,
453 				 (errmsg("changing return type of function %s from %s to %s",
454 						 NameListToString(inputName), "opaque", typeName)));
455 			SetFunctionReturnType(inputOid, typoid);
456 		}
457 		else
458 			ereport(ERROR,
459 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
460 					 errmsg("type input function %s must return type %s",
461 							NameListToString(inputName), typeName)));
462 	}
463 	resulttype = get_func_rettype(outputOid);
464 	if (resulttype != CSTRINGOID)
465 	{
466 		if (resulttype == OPAQUEOID)
467 		{
468 			/* backwards-compatibility hack */
469 			ereport(WARNING,
470 				 (errmsg("changing return type of function %s from %s to %s",
471 						 NameListToString(outputName), "opaque", "cstring")));
472 			SetFunctionReturnType(outputOid, CSTRINGOID);
473 		}
474 		else
475 			ereport(ERROR,
476 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
477 					 errmsg("type output function %s must return type %s",
478 							NameListToString(outputName), "cstring")));
479 	}
480 	if (receiveOid)
481 	{
482 		resulttype = get_func_rettype(receiveOid);
483 		if (resulttype != typoid)
484 			ereport(ERROR,
485 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
486 					 errmsg("type receive function %s must return type %s",
487 							NameListToString(receiveName), typeName)));
488 	}
489 	if (sendOid)
490 	{
491 		resulttype = get_func_rettype(sendOid);
492 		if (resulttype != BYTEAOID)
493 			ereport(ERROR,
494 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
495 					 errmsg("type send function %s must return type %s",
496 							NameListToString(sendName), "bytea")));
497 	}
498 
499 	/*
500 	 * Convert typmodin/out function proc names to OIDs.
501 	 */
502 	if (typmodinName)
503 		typmodinOid = findTypeTypmodinFunction(typmodinName);
504 	if (typmodoutName)
505 		typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
506 
507 	/*
508 	 * Convert analysis function proc name to an OID. If no analysis function
509 	 * is specified, we'll use zero to select the built-in default algorithm.
510 	 */
511 	if (analyzeName)
512 		analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
513 
514 	/*
515 	 * Check permissions on functions.  We choose to require the creator/owner
516 	 * of a type to also own the underlying functions.  Since creating a type
517 	 * is tantamount to granting public execute access on the functions, the
518 	 * minimum sane check would be for execute-with-grant-option.  But we
519 	 * don't have a way to make the type go away if the grant option is
520 	 * revoked, so ownership seems better.
521 	 */
522 #ifdef NOT_USED
523 	/* XXX this is unnecessary given the superuser check above */
524 	if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
525 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
526 					   NameListToString(inputName));
527 	if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
528 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
529 					   NameListToString(outputName));
530 	if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
531 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
532 					   NameListToString(receiveName));
533 	if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
534 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
535 					   NameListToString(sendName));
536 	if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
537 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
538 					   NameListToString(typmodinName));
539 	if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
540 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
541 					   NameListToString(typmodoutName));
542 	if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
543 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
544 					   NameListToString(analyzeName));
545 #endif
546 
547 	/*
548 	 * Print warnings if any of the type's I/O functions are marked volatile.
549 	 * There is a general assumption that I/O functions are stable or
550 	 * immutable; this allows us for example to mark record_in/record_out
551 	 * stable rather than volatile.  Ideally we would throw errors not just
552 	 * warnings here; but since this check is new as of 9.5, and since the
553 	 * volatility marking might be just an error-of-omission and not a true
554 	 * indication of how the function behaves, we'll let it pass as a warning
555 	 * for now.
556 	 */
557 	if (inputOid && func_volatile(inputOid) == PROVOLATILE_VOLATILE)
558 		ereport(WARNING,
559 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
560 				 errmsg("type input function %s should not be volatile",
561 						NameListToString(inputName))));
562 	if (outputOid && func_volatile(outputOid) == PROVOLATILE_VOLATILE)
563 		ereport(WARNING,
564 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
565 				 errmsg("type output function %s should not be volatile",
566 						NameListToString(outputName))));
567 	if (receiveOid && func_volatile(receiveOid) == PROVOLATILE_VOLATILE)
568 		ereport(WARNING,
569 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
570 				 errmsg("type receive function %s should not be volatile",
571 						NameListToString(receiveName))));
572 	if (sendOid && func_volatile(sendOid) == PROVOLATILE_VOLATILE)
573 		ereport(WARNING,
574 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
575 				 errmsg("type send function %s should not be volatile",
576 						NameListToString(sendName))));
577 	if (typmodinOid && func_volatile(typmodinOid) == PROVOLATILE_VOLATILE)
578 		ereport(WARNING,
579 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
580 			 errmsg("type modifier input function %s should not be volatile",
581 					NameListToString(typmodinName))));
582 	if (typmodoutOid && func_volatile(typmodoutOid) == PROVOLATILE_VOLATILE)
583 		ereport(WARNING,
584 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
585 			errmsg("type modifier output function %s should not be volatile",
586 				   NameListToString(typmodoutName))));
587 
588 	/*
589 	 * OK, we're done checking, time to make the type.  We must assign the
590 	 * array type OID ahead of calling TypeCreate, since the base type and
591 	 * array type each refer to the other.
592 	 */
593 	array_oid = AssignTypeArrayOid();
594 
595 	/*
596 	 * now have TypeCreate do all the real work.
597 	 *
598 	 * Note: the pg_type.oid is stored in user tables as array elements (base
599 	 * types) in ArrayType and in composite types in DatumTupleFields.  This
600 	 * oid must be preserved by binary upgrades.
601 	 */
602 	address =
603 		TypeCreate(InvalidOid,	/* no predetermined type OID */
604 				   typeName,	/* type name */
605 				   typeNamespace,		/* namespace */
606 				   InvalidOid,	/* relation oid (n/a here) */
607 				   0,			/* relation kind (ditto) */
608 				   GetUserId(), /* owner's ID */
609 				   internalLength,		/* internal size */
610 				   TYPTYPE_BASE,	/* type-type (base type) */
611 				   category,	/* type-category */
612 				   preferred,	/* is it a preferred type? */
613 				   delimiter,	/* array element delimiter */
614 				   inputOid,	/* input procedure */
615 				   outputOid,	/* output procedure */
616 				   receiveOid,	/* receive procedure */
617 				   sendOid,		/* send procedure */
618 				   typmodinOid, /* typmodin procedure */
619 				   typmodoutOid,	/* typmodout procedure */
620 				   analyzeOid,	/* analyze procedure */
621 				   elemType,	/* element type ID */
622 				   false,		/* this is not an array type */
623 				   array_oid,	/* array type we are about to create */
624 				   InvalidOid,	/* base type ID (only for domains) */
625 				   defaultValue,	/* default type value */
626 				   NULL,		/* no binary form available */
627 				   byValue,		/* passed by value */
628 				   alignment,	/* required alignment */
629 				   storage,		/* TOAST strategy */
630 				   -1,			/* typMod (Domains only) */
631 				   0,			/* Array Dimensions of typbasetype */
632 				   false,		/* Type NOT NULL */
633 				   collation);	/* type's collation */
634 	Assert(typoid == address.objectId);
635 
636 	/*
637 	 * Create the array type that goes with it.
638 	 */
639 	array_type = makeArrayTypeName(typeName, typeNamespace);
640 
641 	/* alignment must be 'i' or 'd' for arrays */
642 	alignment = (alignment == 'd') ? 'd' : 'i';
643 
644 	TypeCreate(array_oid,		/* force assignment of this type OID */
645 			   array_type,		/* type name */
646 			   typeNamespace,	/* namespace */
647 			   InvalidOid,		/* relation oid (n/a here) */
648 			   0,				/* relation kind (ditto) */
649 			   GetUserId(),		/* owner's ID */
650 			   -1,				/* internal size (always varlena) */
651 			   TYPTYPE_BASE,	/* type-type (base type) */
652 			   TYPCATEGORY_ARRAY,		/* type-category (array) */
653 			   false,			/* array types are never preferred */
654 			   delimiter,		/* array element delimiter */
655 			   F_ARRAY_IN,		/* input procedure */
656 			   F_ARRAY_OUT,		/* output procedure */
657 			   F_ARRAY_RECV,	/* receive procedure */
658 			   F_ARRAY_SEND,	/* send procedure */
659 			   typmodinOid,		/* typmodin procedure */
660 			   typmodoutOid,	/* typmodout procedure */
661 			   F_ARRAY_TYPANALYZE,		/* analyze procedure */
662 			   typoid,			/* element type ID */
663 			   true,			/* yes this is an array type */
664 			   InvalidOid,		/* no further array type */
665 			   InvalidOid,		/* base type ID */
666 			   NULL,			/* never a default type value */
667 			   NULL,			/* binary default isn't sent either */
668 			   false,			/* never passed by value */
669 			   alignment,		/* see above */
670 			   'x',				/* ARRAY is always toastable */
671 			   -1,				/* typMod (Domains only) */
672 			   0,				/* Array dimensions of typbasetype */
673 			   false,			/* Type NOT NULL */
674 			   collation);		/* type's collation */
675 
676 	pfree(array_type);
677 
678 	return address;
679 }
680 
681 /*
682  * Guts of type deletion.
683  */
684 void
RemoveTypeById(Oid typeOid)685 RemoveTypeById(Oid typeOid)
686 {
687 	Relation	relation;
688 	HeapTuple	tup;
689 
690 	relation = heap_open(TypeRelationId, RowExclusiveLock);
691 
692 	tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
693 	if (!HeapTupleIsValid(tup))
694 		elog(ERROR, "cache lookup failed for type %u", typeOid);
695 
696 	simple_heap_delete(relation, &tup->t_self);
697 
698 	/*
699 	 * If it is an enum, delete the pg_enum entries too; we don't bother with
700 	 * making dependency entries for those, so it has to be done "by hand"
701 	 * here.
702 	 */
703 	if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
704 		EnumValuesDelete(typeOid);
705 
706 	/*
707 	 * If it is a range type, delete the pg_range entry too; we don't bother
708 	 * with making a dependency entry for that, so it has to be done "by hand"
709 	 * here.
710 	 */
711 	if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
712 		RangeDelete(typeOid);
713 
714 	ReleaseSysCache(tup);
715 
716 	heap_close(relation, RowExclusiveLock);
717 }
718 
719 
720 /*
721  * DefineDomain
722  *		Registers a new domain.
723  */
724 ObjectAddress
DefineDomain(CreateDomainStmt * stmt)725 DefineDomain(CreateDomainStmt *stmt)
726 {
727 	char	   *domainName;
728 	Oid			domainNamespace;
729 	AclResult	aclresult;
730 	int16		internalLength;
731 	Oid			inputProcedure;
732 	Oid			outputProcedure;
733 	Oid			receiveProcedure;
734 	Oid			sendProcedure;
735 	Oid			analyzeProcedure;
736 	bool		byValue;
737 	char		category;
738 	char		delimiter;
739 	char		alignment;
740 	char		storage;
741 	char		typtype;
742 	Datum		datum;
743 	bool		isnull;
744 	char	   *defaultValue = NULL;
745 	char	   *defaultValueBin = NULL;
746 	bool		saw_default = false;
747 	bool		typNotNull = false;
748 	bool		nullDefined = false;
749 	int32		typNDims = list_length(stmt->typeName->arrayBounds);
750 	HeapTuple	typeTup;
751 	List	   *schema = stmt->constraints;
752 	ListCell   *listptr;
753 	Oid			basetypeoid;
754 	Oid			old_type_oid;
755 	Oid			domaincoll;
756 	Form_pg_type baseType;
757 	int32		basetypeMod;
758 	Oid			baseColl;
759 	ObjectAddress address;
760 
761 	/* Convert list of names to a name and namespace */
762 	domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
763 														&domainName);
764 
765 	/* Check we have creation rights in target namespace */
766 	aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
767 									  ACL_CREATE);
768 	if (aclresult != ACLCHECK_OK)
769 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
770 					   get_namespace_name(domainNamespace));
771 
772 	/*
773 	 * Check for collision with an existing type name.  If there is one and
774 	 * it's an autogenerated array, we can rename it out of the way.
775 	 */
776 	old_type_oid = GetSysCacheOid2(TYPENAMENSP,
777 								   CStringGetDatum(domainName),
778 								   ObjectIdGetDatum(domainNamespace));
779 	if (OidIsValid(old_type_oid))
780 	{
781 		if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
782 			ereport(ERROR,
783 					(errcode(ERRCODE_DUPLICATE_OBJECT),
784 					 errmsg("type \"%s\" already exists", domainName)));
785 	}
786 
787 	/*
788 	 * Look up the base type.
789 	 */
790 	typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
791 	baseType = (Form_pg_type) GETSTRUCT(typeTup);
792 	basetypeoid = HeapTupleGetOid(typeTup);
793 
794 	/*
795 	 * Base type must be a plain base type, another domain, an enum or a range
796 	 * type. Domains over pseudotypes would create a security hole.  Domains
797 	 * over composite types might be made to work in the future, but not
798 	 * today.
799 	 */
800 	typtype = baseType->typtype;
801 	if (typtype != TYPTYPE_BASE &&
802 		typtype != TYPTYPE_DOMAIN &&
803 		typtype != TYPTYPE_ENUM &&
804 		typtype != TYPTYPE_RANGE)
805 		ereport(ERROR,
806 				(errcode(ERRCODE_DATATYPE_MISMATCH),
807 				 errmsg("\"%s\" is not a valid base type for a domain",
808 						TypeNameToString(stmt->typeName))));
809 
810 	aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
811 	if (aclresult != ACLCHECK_OK)
812 		aclcheck_error_type(aclresult, basetypeoid);
813 
814 	/*
815 	 * Identify the collation if any
816 	 */
817 	baseColl = baseType->typcollation;
818 	if (stmt->collClause)
819 		domaincoll = get_collation_oid(stmt->collClause->collname, false);
820 	else
821 		domaincoll = baseColl;
822 
823 	/* Complain if COLLATE is applied to an uncollatable type */
824 	if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
825 		ereport(ERROR,
826 				(errcode(ERRCODE_DATATYPE_MISMATCH),
827 				 errmsg("collations are not supported by type %s",
828 						format_type_be(basetypeoid))));
829 
830 	/* passed by value */
831 	byValue = baseType->typbyval;
832 
833 	/* Required Alignment */
834 	alignment = baseType->typalign;
835 
836 	/* TOAST Strategy */
837 	storage = baseType->typstorage;
838 
839 	/* Storage Length */
840 	internalLength = baseType->typlen;
841 
842 	/* Type Category */
843 	category = baseType->typcategory;
844 
845 	/* Array element Delimiter */
846 	delimiter = baseType->typdelim;
847 
848 	/* I/O Functions */
849 	inputProcedure = F_DOMAIN_IN;
850 	outputProcedure = baseType->typoutput;
851 	receiveProcedure = F_DOMAIN_RECV;
852 	sendProcedure = baseType->typsend;
853 
854 	/* Domains never accept typmods, so no typmodin/typmodout needed */
855 
856 	/* Analysis function */
857 	analyzeProcedure = baseType->typanalyze;
858 
859 	/* Inherited default value */
860 	datum = SysCacheGetAttr(TYPEOID, typeTup,
861 							Anum_pg_type_typdefault, &isnull);
862 	if (!isnull)
863 		defaultValue = TextDatumGetCString(datum);
864 
865 	/* Inherited default binary value */
866 	datum = SysCacheGetAttr(TYPEOID, typeTup,
867 							Anum_pg_type_typdefaultbin, &isnull);
868 	if (!isnull)
869 		defaultValueBin = TextDatumGetCString(datum);
870 
871 	/*
872 	 * Run through constraints manually to avoid the additional processing
873 	 * conducted by DefineRelation() and friends.
874 	 */
875 	foreach(listptr, schema)
876 	{
877 		Constraint *constr = lfirst(listptr);
878 
879 		if (!IsA(constr, Constraint))
880 			elog(ERROR, "unrecognized node type: %d",
881 				 (int) nodeTag(constr));
882 		switch (constr->contype)
883 		{
884 			case CONSTR_DEFAULT:
885 
886 				/*
887 				 * The inherited default value may be overridden by the user
888 				 * with the DEFAULT <expr> clause ... but only once.
889 				 */
890 				if (saw_default)
891 					ereport(ERROR,
892 							(errcode(ERRCODE_SYNTAX_ERROR),
893 							 errmsg("multiple default expressions")));
894 				saw_default = true;
895 
896 				if (constr->raw_expr)
897 				{
898 					ParseState *pstate;
899 					Node	   *defaultExpr;
900 
901 					/* Create a dummy ParseState for transformExpr */
902 					pstate = make_parsestate(NULL);
903 
904 					/*
905 					 * Cook the constr->raw_expr into an expression; copy it
906 					 * in case the input is in plan cache.  Note: name is used
907 					 * only for error messages.
908 					 */
909 					defaultExpr = cookDefault(pstate,
910 											  copyObject(constr->raw_expr),
911 											  basetypeoid,
912 											  basetypeMod,
913 											  domainName);
914 
915 					/*
916 					 * If the expression is just a NULL constant, we treat it
917 					 * like not having a default.
918 					 *
919 					 * Note that if the basetype is another domain, we'll see
920 					 * a CoerceToDomain expr here and not discard the default.
921 					 * This is critical because the domain default needs to be
922 					 * retained to override any default that the base domain
923 					 * might have.
924 					 */
925 					if (defaultExpr == NULL ||
926 						(IsA(defaultExpr, Const) &&
927 						 ((Const *) defaultExpr)->constisnull))
928 					{
929 						defaultValue = NULL;
930 						defaultValueBin = NULL;
931 					}
932 					else
933 					{
934 						/*
935 						 * Expression must be stored as a nodeToString result,
936 						 * but we also require a valid textual representation
937 						 * (mainly to make life easier for pg_dump).
938 						 */
939 						defaultValue =
940 							deparse_expression(defaultExpr,
941 											   NIL, false, false);
942 						defaultValueBin = nodeToString(defaultExpr);
943 					}
944 				}
945 				else
946 				{
947 					/* No default (can this still happen?) */
948 					defaultValue = NULL;
949 					defaultValueBin = NULL;
950 				}
951 				break;
952 
953 			case CONSTR_NOTNULL:
954 				if (nullDefined && !typNotNull)
955 					ereport(ERROR,
956 							(errcode(ERRCODE_SYNTAX_ERROR),
957 						   errmsg("conflicting NULL/NOT NULL constraints")));
958 				typNotNull = true;
959 				nullDefined = true;
960 				break;
961 
962 			case CONSTR_NULL:
963 				if (nullDefined && typNotNull)
964 					ereport(ERROR,
965 							(errcode(ERRCODE_SYNTAX_ERROR),
966 						   errmsg("conflicting NULL/NOT NULL constraints")));
967 				typNotNull = false;
968 				nullDefined = true;
969 				break;
970 
971 			case CONSTR_CHECK:
972 
973 				/*
974 				 * Check constraints are handled after domain creation, as
975 				 * they require the Oid of the domain; at this point we can
976 				 * only check that they're not marked NO INHERIT, because that
977 				 * would be bogus.
978 				 */
979 				if (constr->is_no_inherit)
980 					ereport(ERROR,
981 							(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
982 							 errmsg("check constraints for domains cannot be marked NO INHERIT")));
983 				break;
984 
985 				/*
986 				 * All else are error cases
987 				 */
988 			case CONSTR_UNIQUE:
989 				ereport(ERROR,
990 						(errcode(ERRCODE_SYNTAX_ERROR),
991 					 errmsg("unique constraints not possible for domains")));
992 				break;
993 
994 			case CONSTR_PRIMARY:
995 				ereport(ERROR,
996 						(errcode(ERRCODE_SYNTAX_ERROR),
997 				errmsg("primary key constraints not possible for domains")));
998 				break;
999 
1000 			case CONSTR_EXCLUSION:
1001 				ereport(ERROR,
1002 						(errcode(ERRCODE_SYNTAX_ERROR),
1003 				  errmsg("exclusion constraints not possible for domains")));
1004 				break;
1005 
1006 			case CONSTR_FOREIGN:
1007 				ereport(ERROR,
1008 						(errcode(ERRCODE_SYNTAX_ERROR),
1009 				errmsg("foreign key constraints not possible for domains")));
1010 				break;
1011 
1012 			case CONSTR_ATTR_DEFERRABLE:
1013 			case CONSTR_ATTR_NOT_DEFERRABLE:
1014 			case CONSTR_ATTR_DEFERRED:
1015 			case CONSTR_ATTR_IMMEDIATE:
1016 				ereport(ERROR,
1017 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1018 						 errmsg("specifying constraint deferrability not supported for domains")));
1019 				break;
1020 
1021 			default:
1022 				elog(ERROR, "unrecognized constraint subtype: %d",
1023 					 (int) constr->contype);
1024 				break;
1025 		}
1026 	}
1027 
1028 	/*
1029 	 * Have TypeCreate do all the real work.
1030 	 */
1031 	address =
1032 		TypeCreate(InvalidOid,	/* no predetermined type OID */
1033 				   domainName,	/* type name */
1034 				   domainNamespace,		/* namespace */
1035 				   InvalidOid,	/* relation oid (n/a here) */
1036 				   0,			/* relation kind (ditto) */
1037 				   GetUserId(), /* owner's ID */
1038 				   internalLength,		/* internal size */
1039 				   TYPTYPE_DOMAIN,		/* type-type (domain type) */
1040 				   category,	/* type-category */
1041 				   false,		/* domain types are never preferred */
1042 				   delimiter,	/* array element delimiter */
1043 				   inputProcedure,		/* input procedure */
1044 				   outputProcedure,		/* output procedure */
1045 				   receiveProcedure,	/* receive procedure */
1046 				   sendProcedure,		/* send procedure */
1047 				   InvalidOid,	/* typmodin procedure - none */
1048 				   InvalidOid,	/* typmodout procedure - none */
1049 				   analyzeProcedure,	/* analyze procedure */
1050 				   InvalidOid,	/* no array element type */
1051 				   false,		/* this isn't an array */
1052 				   InvalidOid,	/* no arrays for domains (yet) */
1053 				   basetypeoid, /* base type ID */
1054 				   defaultValue,	/* default type value (text) */
1055 				   defaultValueBin,		/* default type value (binary) */
1056 				   byValue,		/* passed by value */
1057 				   alignment,	/* required alignment */
1058 				   storage,		/* TOAST strategy */
1059 				   basetypeMod, /* typeMod value */
1060 				   typNDims,	/* Array dimensions for base type */
1061 				   typNotNull,	/* Type NOT NULL */
1062 				   domaincoll); /* type's collation */
1063 
1064 	/*
1065 	 * Process constraints which refer to the domain ID returned by TypeCreate
1066 	 */
1067 	foreach(listptr, schema)
1068 	{
1069 		Constraint *constr = lfirst(listptr);
1070 
1071 		/* it must be a Constraint, per check above */
1072 
1073 		switch (constr->contype)
1074 		{
1075 			case CONSTR_CHECK:
1076 				domainAddConstraint(address.objectId, domainNamespace,
1077 									basetypeoid, basetypeMod,
1078 									constr, domainName, NULL);
1079 				break;
1080 
1081 				/* Other constraint types were fully processed above */
1082 
1083 			default:
1084 				break;
1085 		}
1086 
1087 		/* CCI so we can detect duplicate constraint names */
1088 		CommandCounterIncrement();
1089 	}
1090 
1091 	/*
1092 	 * Now we can clean up.
1093 	 */
1094 	ReleaseSysCache(typeTup);
1095 
1096 	return address;
1097 }
1098 
1099 
1100 /*
1101  * DefineEnum
1102  *		Registers a new enum.
1103  */
1104 ObjectAddress
DefineEnum(CreateEnumStmt * stmt)1105 DefineEnum(CreateEnumStmt *stmt)
1106 {
1107 	char	   *enumName;
1108 	char	   *enumArrayName;
1109 	Oid			enumNamespace;
1110 	AclResult	aclresult;
1111 	Oid			old_type_oid;
1112 	Oid			enumArrayOid;
1113 	ObjectAddress enumTypeAddr;
1114 
1115 	/* Convert list of names to a name and namespace */
1116 	enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1117 													  &enumName);
1118 
1119 	/* Check we have creation rights in target namespace */
1120 	aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1121 	if (aclresult != ACLCHECK_OK)
1122 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1123 					   get_namespace_name(enumNamespace));
1124 
1125 	/*
1126 	 * Check for collision with an existing type name.  If there is one and
1127 	 * it's an autogenerated array, we can rename it out of the way.
1128 	 */
1129 	old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1130 								   CStringGetDatum(enumName),
1131 								   ObjectIdGetDatum(enumNamespace));
1132 	if (OidIsValid(old_type_oid))
1133 	{
1134 		if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1135 			ereport(ERROR,
1136 					(errcode(ERRCODE_DUPLICATE_OBJECT),
1137 					 errmsg("type \"%s\" already exists", enumName)));
1138 	}
1139 
1140 	enumArrayOid = AssignTypeArrayOid();
1141 
1142 	/* Create the pg_type entry */
1143 	enumTypeAddr =
1144 		TypeCreate(InvalidOid,	/* no predetermined type OID */
1145 				   enumName,	/* type name */
1146 				   enumNamespace,		/* namespace */
1147 				   InvalidOid,	/* relation oid (n/a here) */
1148 				   0,			/* relation kind (ditto) */
1149 				   GetUserId(), /* owner's ID */
1150 				   sizeof(Oid), /* internal size */
1151 				   TYPTYPE_ENUM,	/* type-type (enum type) */
1152 				   TYPCATEGORY_ENUM,	/* type-category (enum type) */
1153 				   false,		/* enum types are never preferred */
1154 				   DEFAULT_TYPDELIM,	/* array element delimiter */
1155 				   F_ENUM_IN,	/* input procedure */
1156 				   F_ENUM_OUT,	/* output procedure */
1157 				   F_ENUM_RECV, /* receive procedure */
1158 				   F_ENUM_SEND, /* send procedure */
1159 				   InvalidOid,	/* typmodin procedure - none */
1160 				   InvalidOid,	/* typmodout procedure - none */
1161 				   InvalidOid,	/* analyze procedure - default */
1162 				   InvalidOid,	/* element type ID */
1163 				   false,		/* this is not an array type */
1164 				   enumArrayOid,	/* array type we are about to create */
1165 				   InvalidOid,	/* base type ID (only for domains) */
1166 				   NULL,		/* never a default type value */
1167 				   NULL,		/* binary default isn't sent either */
1168 				   true,		/* always passed by value */
1169 				   'i',			/* int alignment */
1170 				   'p',			/* TOAST strategy always plain */
1171 				   -1,			/* typMod (Domains only) */
1172 				   0,			/* Array dimensions of typbasetype */
1173 				   false,		/* Type NOT NULL */
1174 				   InvalidOid); /* type's collation */
1175 
1176 	/* Enter the enum's values into pg_enum */
1177 	EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
1178 
1179 	/*
1180 	 * Create the array type that goes with it.
1181 	 */
1182 	enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1183 
1184 	TypeCreate(enumArrayOid,	/* force assignment of this type OID */
1185 			   enumArrayName,	/* type name */
1186 			   enumNamespace,	/* namespace */
1187 			   InvalidOid,		/* relation oid (n/a here) */
1188 			   0,				/* relation kind (ditto) */
1189 			   GetUserId(),		/* owner's ID */
1190 			   -1,				/* internal size (always varlena) */
1191 			   TYPTYPE_BASE,	/* type-type (base type) */
1192 			   TYPCATEGORY_ARRAY,		/* type-category (array) */
1193 			   false,			/* array types are never preferred */
1194 			   DEFAULT_TYPDELIM,	/* array element delimiter */
1195 			   F_ARRAY_IN,		/* input procedure */
1196 			   F_ARRAY_OUT,		/* output procedure */
1197 			   F_ARRAY_RECV,	/* receive procedure */
1198 			   F_ARRAY_SEND,	/* send procedure */
1199 			   InvalidOid,		/* typmodin procedure - none */
1200 			   InvalidOid,		/* typmodout procedure - none */
1201 			   F_ARRAY_TYPANALYZE,		/* analyze procedure */
1202 			   enumTypeAddr.objectId,	/* element type ID */
1203 			   true,			/* yes this is an array type */
1204 			   InvalidOid,		/* no further array type */
1205 			   InvalidOid,		/* base type ID */
1206 			   NULL,			/* never a default type value */
1207 			   NULL,			/* binary default isn't sent either */
1208 			   false,			/* never passed by value */
1209 			   'i',				/* enums have align i, so do their arrays */
1210 			   'x',				/* ARRAY is always toastable */
1211 			   -1,				/* typMod (Domains only) */
1212 			   0,				/* Array dimensions of typbasetype */
1213 			   false,			/* Type NOT NULL */
1214 			   InvalidOid);		/* type's collation */
1215 
1216 	pfree(enumArrayName);
1217 
1218 	return enumTypeAddr;
1219 }
1220 
1221 /*
1222  * AlterEnum
1223  *		Adds a new label to an existing enum.
1224  */
1225 ObjectAddress
AlterEnum(AlterEnumStmt * stmt,bool isTopLevel)1226 AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
1227 {
1228 	Oid			enum_type_oid;
1229 	TypeName   *typename;
1230 	HeapTuple	tup;
1231 	ObjectAddress address;
1232 
1233 	/* Make a TypeName so we can use standard type lookup machinery */
1234 	typename = makeTypeNameFromNameList(stmt->typeName);
1235 	enum_type_oid = typenameTypeId(NULL, typename);
1236 
1237 	tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1238 	if (!HeapTupleIsValid(tup))
1239 		elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1240 
1241 	/*
1242 	 * Ordinarily we disallow adding values within transaction blocks, because
1243 	 * we can't cope with enum OID values getting into indexes and then having
1244 	 * their defining pg_enum entries go away.  However, it's okay if the enum
1245 	 * type was created in the current transaction, since then there can be no
1246 	 * such indexes that wouldn't themselves go away on rollback.  (We support
1247 	 * this case because pg_dump --binary-upgrade needs it.)  We test this by
1248 	 * seeing if the pg_type row has xmin == current XID and is not
1249 	 * HEAP_UPDATED.  If it is HEAP_UPDATED, we can't be sure whether the type
1250 	 * was created or only modified in this xact.  So we are disallowing some
1251 	 * cases that could theoretically be safe; but fortunately pg_dump only
1252 	 * needs the simplest case.
1253 	 */
1254 	if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
1255 		!(tup->t_data->t_infomask & HEAP_UPDATED))
1256 		 /* safe to do inside transaction block */ ;
1257 	else
1258 		PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
1259 
1260 	/* Check it's an enum and check user has permission to ALTER the enum */
1261 	checkEnumOwner(tup);
1262 
1263 	/* Add the new label */
1264 	AddEnumLabel(enum_type_oid, stmt->newVal,
1265 				 stmt->newValNeighbor, stmt->newValIsAfter,
1266 				 stmt->skipIfExists);
1267 
1268 	InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1269 
1270 	ObjectAddressSet(address, TypeRelationId, enum_type_oid);
1271 
1272 	ReleaseSysCache(tup);
1273 
1274 	return address;
1275 }
1276 
1277 
1278 /*
1279  * checkEnumOwner
1280  *
1281  * Check that the type is actually an enum and that the current user
1282  * has permission to do ALTER TYPE on it.  Throw an error if not.
1283  */
1284 static void
checkEnumOwner(HeapTuple tup)1285 checkEnumOwner(HeapTuple tup)
1286 {
1287 	Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1288 
1289 	/* Check that this is actually an enum */
1290 	if (typTup->typtype != TYPTYPE_ENUM)
1291 		ereport(ERROR,
1292 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1293 				 errmsg("%s is not an enum",
1294 						format_type_be(HeapTupleGetOid(tup)))));
1295 
1296 	/* Permission check: must own type */
1297 	if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1298 		aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
1299 }
1300 
1301 
1302 /*
1303  * DefineRange
1304  *		Registers a new range type.
1305  */
1306 ObjectAddress
DefineRange(CreateRangeStmt * stmt)1307 DefineRange(CreateRangeStmt *stmt)
1308 {
1309 	char	   *typeName;
1310 	Oid			typeNamespace;
1311 	Oid			typoid;
1312 	char	   *rangeArrayName;
1313 	Oid			rangeArrayOid;
1314 	Oid			rangeSubtype = InvalidOid;
1315 	List	   *rangeSubOpclassName = NIL;
1316 	List	   *rangeCollationName = NIL;
1317 	List	   *rangeCanonicalName = NIL;
1318 	List	   *rangeSubtypeDiffName = NIL;
1319 	Oid			rangeSubOpclass;
1320 	Oid			rangeCollation;
1321 	regproc		rangeCanonical;
1322 	regproc		rangeSubtypeDiff;
1323 	int16		subtyplen;
1324 	bool		subtypbyval;
1325 	char		subtypalign;
1326 	char		alignment;
1327 	AclResult	aclresult;
1328 	ListCell   *lc;
1329 	ObjectAddress address;
1330 
1331 	/* Convert list of names to a name and namespace */
1332 	typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1333 													  &typeName);
1334 
1335 	/* Check we have creation rights in target namespace */
1336 	aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1337 	if (aclresult != ACLCHECK_OK)
1338 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1339 					   get_namespace_name(typeNamespace));
1340 
1341 	/*
1342 	 * Look to see if type already exists.
1343 	 */
1344 	typoid = GetSysCacheOid2(TYPENAMENSP,
1345 							 CStringGetDatum(typeName),
1346 							 ObjectIdGetDatum(typeNamespace));
1347 
1348 	/*
1349 	 * If it's not a shell, see if it's an autogenerated array type, and if so
1350 	 * rename it out of the way.
1351 	 */
1352 	if (OidIsValid(typoid) && get_typisdefined(typoid))
1353 	{
1354 		if (moveArrayTypeName(typoid, typeName, typeNamespace))
1355 			typoid = InvalidOid;
1356 		else
1357 			ereport(ERROR,
1358 					(errcode(ERRCODE_DUPLICATE_OBJECT),
1359 					 errmsg("type \"%s\" already exists", typeName)));
1360 	}
1361 
1362 	/*
1363 	 * If it doesn't exist, create it as a shell, so that the OID is known for
1364 	 * use in the range function definitions.
1365 	 */
1366 	if (!OidIsValid(typoid))
1367 	{
1368 		address = TypeShellMake(typeName, typeNamespace, GetUserId());
1369 		typoid = address.objectId;
1370 		/* Make new shell type visible for modification below */
1371 		CommandCounterIncrement();
1372 	}
1373 
1374 	/* Extract the parameters from the parameter list */
1375 	foreach(lc, stmt->params)
1376 	{
1377 		DefElem    *defel = (DefElem *) lfirst(lc);
1378 
1379 		if (pg_strcasecmp(defel->defname, "subtype") == 0)
1380 		{
1381 			if (OidIsValid(rangeSubtype))
1382 				ereport(ERROR,
1383 						(errcode(ERRCODE_SYNTAX_ERROR),
1384 						 errmsg("conflicting or redundant options")));
1385 			/* we can look up the subtype name immediately */
1386 			rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1387 		}
1388 		else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
1389 		{
1390 			if (rangeSubOpclassName != NIL)
1391 				ereport(ERROR,
1392 						(errcode(ERRCODE_SYNTAX_ERROR),
1393 						 errmsg("conflicting or redundant options")));
1394 			rangeSubOpclassName = defGetQualifiedName(defel);
1395 		}
1396 		else if (pg_strcasecmp(defel->defname, "collation") == 0)
1397 		{
1398 			if (rangeCollationName != NIL)
1399 				ereport(ERROR,
1400 						(errcode(ERRCODE_SYNTAX_ERROR),
1401 						 errmsg("conflicting or redundant options")));
1402 			rangeCollationName = defGetQualifiedName(defel);
1403 		}
1404 		else if (pg_strcasecmp(defel->defname, "canonical") == 0)
1405 		{
1406 			if (rangeCanonicalName != NIL)
1407 				ereport(ERROR,
1408 						(errcode(ERRCODE_SYNTAX_ERROR),
1409 						 errmsg("conflicting or redundant options")));
1410 			rangeCanonicalName = defGetQualifiedName(defel);
1411 		}
1412 		else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
1413 		{
1414 			if (rangeSubtypeDiffName != NIL)
1415 				ereport(ERROR,
1416 						(errcode(ERRCODE_SYNTAX_ERROR),
1417 						 errmsg("conflicting or redundant options")));
1418 			rangeSubtypeDiffName = defGetQualifiedName(defel);
1419 		}
1420 		else
1421 			ereport(ERROR,
1422 					(errcode(ERRCODE_SYNTAX_ERROR),
1423 					 errmsg("type attribute \"%s\" not recognized",
1424 							defel->defname)));
1425 	}
1426 
1427 	/* Must have a subtype */
1428 	if (!OidIsValid(rangeSubtype))
1429 		ereport(ERROR,
1430 				(errcode(ERRCODE_SYNTAX_ERROR),
1431 				 errmsg("type attribute \"subtype\" is required")));
1432 	/* disallow ranges of pseudotypes */
1433 	if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1434 		ereport(ERROR,
1435 				(errcode(ERRCODE_DATATYPE_MISMATCH),
1436 				 errmsg("range subtype cannot be %s",
1437 						format_type_be(rangeSubtype))));
1438 
1439 	/* Identify subopclass */
1440 	rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1441 
1442 	/* Identify collation to use, if any */
1443 	if (type_is_collatable(rangeSubtype))
1444 	{
1445 		if (rangeCollationName != NIL)
1446 			rangeCollation = get_collation_oid(rangeCollationName, false);
1447 		else
1448 			rangeCollation = get_typcollation(rangeSubtype);
1449 	}
1450 	else
1451 	{
1452 		if (rangeCollationName != NIL)
1453 			ereport(ERROR,
1454 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1455 					 errmsg("range collation specified but subtype does not support collation")));
1456 		rangeCollation = InvalidOid;
1457 	}
1458 
1459 	/* Identify support functions, if provided */
1460 	if (rangeCanonicalName != NIL)
1461 		rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1462 													typoid);
1463 	else
1464 		rangeCanonical = InvalidOid;
1465 
1466 	if (rangeSubtypeDiffName != NIL)
1467 		rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1468 														rangeSubtype);
1469 	else
1470 		rangeSubtypeDiff = InvalidOid;
1471 
1472 	get_typlenbyvalalign(rangeSubtype,
1473 						 &subtyplen, &subtypbyval, &subtypalign);
1474 
1475 	/* alignment must be 'i' or 'd' for ranges */
1476 	alignment = (subtypalign == 'd') ? 'd' : 'i';
1477 
1478 	/* Allocate OID for array type */
1479 	rangeArrayOid = AssignTypeArrayOid();
1480 
1481 	/* Create the pg_type entry */
1482 	address =
1483 		TypeCreate(InvalidOid,	/* no predetermined type OID */
1484 				   typeName,	/* type name */
1485 				   typeNamespace,		/* namespace */
1486 				   InvalidOid,	/* relation oid (n/a here) */
1487 				   0,			/* relation kind (ditto) */
1488 				   GetUserId(), /* owner's ID */
1489 				   -1,			/* internal size (always varlena) */
1490 				   TYPTYPE_RANGE,		/* type-type (range type) */
1491 				   TYPCATEGORY_RANGE,	/* type-category (range type) */
1492 				   false,		/* range types are never preferred */
1493 				   DEFAULT_TYPDELIM,	/* array element delimiter */
1494 				   F_RANGE_IN,	/* input procedure */
1495 				   F_RANGE_OUT, /* output procedure */
1496 				   F_RANGE_RECV,	/* receive procedure */
1497 				   F_RANGE_SEND,	/* send procedure */
1498 				   InvalidOid,	/* typmodin procedure - none */
1499 				   InvalidOid,	/* typmodout procedure - none */
1500 				   F_RANGE_TYPANALYZE,	/* analyze procedure */
1501 				   InvalidOid,	/* element type ID - none */
1502 				   false,		/* this is not an array type */
1503 				   rangeArrayOid,		/* array type we are about to create */
1504 				   InvalidOid,	/* base type ID (only for domains) */
1505 				   NULL,		/* never a default type value */
1506 				   NULL,		/* no binary form available either */
1507 				   false,		/* never passed by value */
1508 				   alignment,	/* alignment */
1509 				   'x',			/* TOAST strategy (always extended) */
1510 				   -1,			/* typMod (Domains only) */
1511 				   0,			/* Array dimensions of typbasetype */
1512 				   false,		/* Type NOT NULL */
1513 				   InvalidOid); /* type's collation (ranges never have one) */
1514 	Assert(typoid == address.objectId);
1515 
1516 	/* Create the entry in pg_range */
1517 	RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1518 				rangeCanonical, rangeSubtypeDiff);
1519 
1520 	/*
1521 	 * Create the array type that goes with it.
1522 	 */
1523 	rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1524 
1525 	TypeCreate(rangeArrayOid,	/* force assignment of this type OID */
1526 			   rangeArrayName,	/* type name */
1527 			   typeNamespace,	/* namespace */
1528 			   InvalidOid,		/* relation oid (n/a here) */
1529 			   0,				/* relation kind (ditto) */
1530 			   GetUserId(),		/* owner's ID */
1531 			   -1,				/* internal size (always varlena) */
1532 			   TYPTYPE_BASE,	/* type-type (base type) */
1533 			   TYPCATEGORY_ARRAY,		/* type-category (array) */
1534 			   false,			/* array types are never preferred */
1535 			   DEFAULT_TYPDELIM,	/* array element delimiter */
1536 			   F_ARRAY_IN,		/* input procedure */
1537 			   F_ARRAY_OUT,		/* output procedure */
1538 			   F_ARRAY_RECV,	/* receive procedure */
1539 			   F_ARRAY_SEND,	/* send procedure */
1540 			   InvalidOid,		/* typmodin procedure - none */
1541 			   InvalidOid,		/* typmodout procedure - none */
1542 			   F_ARRAY_TYPANALYZE,		/* analyze procedure */
1543 			   typoid,			/* element type ID */
1544 			   true,			/* yes this is an array type */
1545 			   InvalidOid,		/* no further array type */
1546 			   InvalidOid,		/* base type ID */
1547 			   NULL,			/* never a default type value */
1548 			   NULL,			/* binary default isn't sent either */
1549 			   false,			/* never passed by value */
1550 			   alignment,		/* alignment - same as range's */
1551 			   'x',				/* ARRAY is always toastable */
1552 			   -1,				/* typMod (Domains only) */
1553 			   0,				/* Array dimensions of typbasetype */
1554 			   false,			/* Type NOT NULL */
1555 			   InvalidOid);		/* typcollation */
1556 
1557 	pfree(rangeArrayName);
1558 
1559 	/* And create the constructor functions for this range type */
1560 	makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1561 
1562 	return address;
1563 }
1564 
1565 /*
1566  * Because there may exist several range types over the same subtype, the
1567  * range type can't be uniquely determined from the subtype.  So it's
1568  * impossible to define a polymorphic constructor; we have to generate new
1569  * constructor functions explicitly for each range type.
1570  *
1571  * We actually define 4 functions, with 0 through 3 arguments.  This is just
1572  * to offer more convenience for the user.
1573  */
1574 static void
makeRangeConstructors(const char * name,Oid namespace,Oid rangeOid,Oid subtype)1575 makeRangeConstructors(const char *name, Oid namespace,
1576 					  Oid rangeOid, Oid subtype)
1577 {
1578 	static const char *const prosrc[2] = {"range_constructor2",
1579 	"range_constructor3"};
1580 	static const int pronargs[2] = {2, 3};
1581 
1582 	Oid			constructorArgTypes[3];
1583 	ObjectAddress myself,
1584 				referenced;
1585 	int			i;
1586 
1587 	constructorArgTypes[0] = subtype;
1588 	constructorArgTypes[1] = subtype;
1589 	constructorArgTypes[2] = TEXTOID;
1590 
1591 	referenced.classId = TypeRelationId;
1592 	referenced.objectId = rangeOid;
1593 	referenced.objectSubId = 0;
1594 
1595 	for (i = 0; i < lengthof(prosrc); i++)
1596 	{
1597 		oidvector  *constructorArgTypesVector;
1598 
1599 		constructorArgTypesVector = buildoidvector(constructorArgTypes,
1600 												   pronargs[i]);
1601 
1602 		myself = ProcedureCreate(name,	/* name: same as range type */
1603 								 namespace,		/* namespace */
1604 								 false, /* replace */
1605 								 false, /* returns set */
1606 								 rangeOid,		/* return type */
1607 								 BOOTSTRAP_SUPERUSERID, /* proowner */
1608 								 INTERNALlanguageId,	/* language */
1609 								 F_FMGR_INTERNAL_VALIDATOR,		/* language validator */
1610 								 prosrc[i],		/* prosrc */
1611 								 NULL,	/* probin */
1612 								 false, /* isAgg */
1613 								 false, /* isWindowFunc */
1614 								 false, /* security_definer */
1615 								 false, /* leakproof */
1616 								 false, /* isStrict */
1617 								 PROVOLATILE_IMMUTABLE, /* volatility */
1618 								 PROPARALLEL_SAFE,		/* parallel safety */
1619 								 constructorArgTypesVector,		/* parameterTypes */
1620 								 PointerGetDatum(NULL), /* allParameterTypes */
1621 								 PointerGetDatum(NULL), /* parameterModes */
1622 								 PointerGetDatum(NULL), /* parameterNames */
1623 								 NIL,	/* parameterDefaults */
1624 								 PointerGetDatum(NULL), /* trftypes */
1625 								 PointerGetDatum(NULL), /* proconfig */
1626 								 1.0,	/* procost */
1627 								 0.0);	/* prorows */
1628 
1629 		/*
1630 		 * Make the constructors internally-dependent on the range type so
1631 		 * that they go away silently when the type is dropped.  Note that
1632 		 * pg_dump depends on this choice to avoid dumping the constructors.
1633 		 */
1634 		recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1635 	}
1636 }
1637 
1638 
1639 /*
1640  * Find suitable I/O functions for a type.
1641  *
1642  * typeOid is the type's OID (which will already exist, if only as a shell
1643  * type).
1644  */
1645 
1646 static Oid
findTypeInputFunction(List * procname,Oid typeOid)1647 findTypeInputFunction(List *procname, Oid typeOid)
1648 {
1649 	Oid			argList[3];
1650 	int			nmatches = 0;
1651 	Oid			procOid;
1652 	Oid			procOid2;
1653 	Oid			procOid3;
1654 	Oid			procOid4;
1655 
1656 	/*
1657 	 * Input functions can take a single argument of type CSTRING, or three
1658 	 * arguments (string, typioparam OID, typmod).
1659 	 *
1660 	 * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1661 	 * see this, we issue a warning and fix up the pg_proc entry.
1662 	 *
1663 	 * Whine about ambiguity if multiple forms exist.
1664 	 */
1665 	argList[0] = CSTRINGOID;
1666 	argList[1] = OIDOID;
1667 	argList[2] = INT4OID;
1668 
1669 	procOid = LookupFuncName(procname, 1, argList, true);
1670 	if (OidIsValid(procOid))
1671 		nmatches++;
1672 	procOid2 = LookupFuncName(procname, 3, argList, true);
1673 	if (OidIsValid(procOid2))
1674 		nmatches++;
1675 
1676 	argList[0] = OPAQUEOID;
1677 
1678 	procOid3 = LookupFuncName(procname, 1, argList, true);
1679 	if (OidIsValid(procOid3))
1680 		nmatches++;
1681 	procOid4 = LookupFuncName(procname, 3, argList, true);
1682 	if (OidIsValid(procOid4))
1683 		nmatches++;
1684 
1685 	if (nmatches > 1)
1686 		ereport(ERROR,
1687 				(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
1688 				 errmsg("type input function %s has multiple matches",
1689 						NameListToString(procname))));
1690 
1691 	if (OidIsValid(procOid))
1692 		return procOid;
1693 	if (OidIsValid(procOid2))
1694 		return procOid2;
1695 
1696 	/* Cases with OPAQUE need adjustment */
1697 	if (OidIsValid(procOid3))
1698 		procOid = procOid3;
1699 	else
1700 		procOid = procOid4;
1701 
1702 	if (OidIsValid(procOid))
1703 	{
1704 		/* Found, but must complain and fix the pg_proc entry */
1705 		ereport(WARNING,
1706 				(errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1707 						NameListToString(procname))));
1708 		SetFunctionArgType(procOid, 0, CSTRINGOID);
1709 
1710 		/*
1711 		 * Need CommandCounterIncrement since DefineType will likely try to
1712 		 * alter the pg_proc tuple again.
1713 		 */
1714 		CommandCounterIncrement();
1715 
1716 		return procOid;
1717 	}
1718 
1719 	/* Use CSTRING (preferred) in the error message */
1720 	argList[0] = CSTRINGOID;
1721 
1722 	ereport(ERROR,
1723 			(errcode(ERRCODE_UNDEFINED_FUNCTION),
1724 			 errmsg("function %s does not exist",
1725 					func_signature_string(procname, 1, NIL, argList))));
1726 
1727 	return InvalidOid;			/* keep compiler quiet */
1728 }
1729 
1730 static Oid
findTypeOutputFunction(List * procname,Oid typeOid)1731 findTypeOutputFunction(List *procname, Oid typeOid)
1732 {
1733 	Oid			argList[1];
1734 	Oid			procOid;
1735 
1736 	/*
1737 	 * Output functions can take a single argument of the type.
1738 	 *
1739 	 * For backwards compatibility we allow OPAQUE in place of the actual type
1740 	 * name; if we see this, we issue a warning and fix up the pg_proc entry.
1741 	 */
1742 	argList[0] = typeOid;
1743 
1744 	procOid = LookupFuncName(procname, 1, argList, true);
1745 	if (OidIsValid(procOid))
1746 		return procOid;
1747 
1748 	/* No luck, try it with OPAQUE */
1749 	argList[0] = OPAQUEOID;
1750 
1751 	procOid = LookupFuncName(procname, 1, argList, true);
1752 
1753 	if (OidIsValid(procOid))
1754 	{
1755 		/* Found, but must complain and fix the pg_proc entry */
1756 		ereport(WARNING,
1757 		(errmsg("changing argument type of function %s from \"opaque\" to %s",
1758 				NameListToString(procname), format_type_be(typeOid))));
1759 		SetFunctionArgType(procOid, 0, typeOid);
1760 
1761 		/*
1762 		 * Need CommandCounterIncrement since DefineType will likely try to
1763 		 * alter the pg_proc tuple again.
1764 		 */
1765 		CommandCounterIncrement();
1766 
1767 		return procOid;
1768 	}
1769 
1770 	/* Use type name, not OPAQUE, in the failure message. */
1771 	argList[0] = typeOid;
1772 
1773 	ereport(ERROR,
1774 			(errcode(ERRCODE_UNDEFINED_FUNCTION),
1775 			 errmsg("function %s does not exist",
1776 					func_signature_string(procname, 1, NIL, argList))));
1777 
1778 	return InvalidOid;			/* keep compiler quiet */
1779 }
1780 
1781 static Oid
findTypeReceiveFunction(List * procname,Oid typeOid)1782 findTypeReceiveFunction(List *procname, Oid typeOid)
1783 {
1784 	Oid			argList[3];
1785 	Oid			procOid;
1786 	Oid			procOid2;
1787 
1788 	/*
1789 	 * Receive functions can take a single argument of type INTERNAL, or three
1790 	 * arguments (internal, typioparam OID, typmod).  Whine about ambiguity if
1791 	 * both forms exist.
1792 	 */
1793 	argList[0] = INTERNALOID;
1794 	argList[1] = OIDOID;
1795 	argList[2] = INT4OID;
1796 
1797 	procOid = LookupFuncName(procname, 1, argList, true);
1798 	procOid2 = LookupFuncName(procname, 3, argList, true);
1799 	if (OidIsValid(procOid))
1800 	{
1801 		if (OidIsValid(procOid2))
1802 			ereport(ERROR,
1803 					(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
1804 					 errmsg("type receive function %s has multiple matches",
1805 							NameListToString(procname))));
1806 		return procOid;
1807 	}
1808 	else if (OidIsValid(procOid2))
1809 		return procOid2;
1810 
1811 	/* If not found, reference the 1-argument signature in error msg */
1812 	ereport(ERROR,
1813 			(errcode(ERRCODE_UNDEFINED_FUNCTION),
1814 			 errmsg("function %s does not exist",
1815 					func_signature_string(procname, 1, NIL, argList))));
1816 
1817 	return InvalidOid;			/* keep compiler quiet */
1818 }
1819 
1820 static Oid
findTypeSendFunction(List * procname,Oid typeOid)1821 findTypeSendFunction(List *procname, Oid typeOid)
1822 {
1823 	Oid			argList[1];
1824 	Oid			procOid;
1825 
1826 	/*
1827 	 * Send functions can take a single argument of the type.
1828 	 */
1829 	argList[0] = typeOid;
1830 
1831 	procOid = LookupFuncName(procname, 1, argList, true);
1832 	if (OidIsValid(procOid))
1833 		return procOid;
1834 
1835 	ereport(ERROR,
1836 			(errcode(ERRCODE_UNDEFINED_FUNCTION),
1837 			 errmsg("function %s does not exist",
1838 					func_signature_string(procname, 1, NIL, argList))));
1839 
1840 	return InvalidOid;			/* keep compiler quiet */
1841 }
1842 
1843 static Oid
findTypeTypmodinFunction(List * procname)1844 findTypeTypmodinFunction(List *procname)
1845 {
1846 	Oid			argList[1];
1847 	Oid			procOid;
1848 
1849 	/*
1850 	 * typmodin functions always take one cstring[] argument and return int4.
1851 	 */
1852 	argList[0] = CSTRINGARRAYOID;
1853 
1854 	procOid = LookupFuncName(procname, 1, argList, true);
1855 	if (!OidIsValid(procOid))
1856 		ereport(ERROR,
1857 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
1858 				 errmsg("function %s does not exist",
1859 						func_signature_string(procname, 1, NIL, argList))));
1860 
1861 	if (get_func_rettype(procOid) != INT4OID)
1862 		ereport(ERROR,
1863 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1864 				 errmsg("typmod_in function %s must return type %s",
1865 						NameListToString(procname), "integer")));
1866 
1867 	return procOid;
1868 }
1869 
1870 static Oid
findTypeTypmodoutFunction(List * procname)1871 findTypeTypmodoutFunction(List *procname)
1872 {
1873 	Oid			argList[1];
1874 	Oid			procOid;
1875 
1876 	/*
1877 	 * typmodout functions always take one int4 argument and return cstring.
1878 	 */
1879 	argList[0] = INT4OID;
1880 
1881 	procOid = LookupFuncName(procname, 1, argList, true);
1882 	if (!OidIsValid(procOid))
1883 		ereport(ERROR,
1884 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
1885 				 errmsg("function %s does not exist",
1886 						func_signature_string(procname, 1, NIL, argList))));
1887 
1888 	if (get_func_rettype(procOid) != CSTRINGOID)
1889 		ereport(ERROR,
1890 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1891 				 errmsg("typmod_out function %s must return type %s",
1892 						NameListToString(procname), "cstring")));
1893 
1894 	return procOid;
1895 }
1896 
1897 static Oid
findTypeAnalyzeFunction(List * procname,Oid typeOid)1898 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1899 {
1900 	Oid			argList[1];
1901 	Oid			procOid;
1902 
1903 	/*
1904 	 * Analyze functions always take one INTERNAL argument and return bool.
1905 	 */
1906 	argList[0] = INTERNALOID;
1907 
1908 	procOid = LookupFuncName(procname, 1, argList, true);
1909 	if (!OidIsValid(procOid))
1910 		ereport(ERROR,
1911 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
1912 				 errmsg("function %s does not exist",
1913 						func_signature_string(procname, 1, NIL, argList))));
1914 
1915 	if (get_func_rettype(procOid) != BOOLOID)
1916 		ereport(ERROR,
1917 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1918 				 errmsg("type analyze function %s must return type %s",
1919 						NameListToString(procname), "boolean")));
1920 
1921 	return procOid;
1922 }
1923 
1924 /*
1925  * Find suitable support functions and opclasses for a range type.
1926  */
1927 
1928 /*
1929  * Find named btree opclass for subtype, or default btree opclass if
1930  * opcname is NIL.
1931  */
1932 static Oid
findRangeSubOpclass(List * opcname,Oid subtype)1933 findRangeSubOpclass(List *opcname, Oid subtype)
1934 {
1935 	Oid			opcid;
1936 	Oid			opInputType;
1937 
1938 	if (opcname != NIL)
1939 	{
1940 		opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1941 
1942 		/*
1943 		 * Verify that the operator class accepts this datatype. Note we will
1944 		 * accept binary compatibility.
1945 		 */
1946 		opInputType = get_opclass_input_type(opcid);
1947 		if (!IsBinaryCoercible(subtype, opInputType))
1948 			ereport(ERROR,
1949 					(errcode(ERRCODE_DATATYPE_MISMATCH),
1950 				 errmsg("operator class \"%s\" does not accept data type %s",
1951 						NameListToString(opcname),
1952 						format_type_be(subtype))));
1953 	}
1954 	else
1955 	{
1956 		opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1957 		if (!OidIsValid(opcid))
1958 		{
1959 			/* We spell the error message identically to GetIndexOpClass */
1960 			ereport(ERROR,
1961 					(errcode(ERRCODE_UNDEFINED_OBJECT),
1962 					 errmsg("data type %s has no default operator class for access method \"%s\"",
1963 							format_type_be(subtype), "btree"),
1964 					 errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
1965 		}
1966 	}
1967 
1968 	return opcid;
1969 }
1970 
1971 static Oid
findRangeCanonicalFunction(List * procname,Oid typeOid)1972 findRangeCanonicalFunction(List *procname, Oid typeOid)
1973 {
1974 	Oid			argList[1];
1975 	Oid			procOid;
1976 	AclResult	aclresult;
1977 
1978 	/*
1979 	 * Range canonical functions must take and return the range type, and must
1980 	 * be immutable.
1981 	 */
1982 	argList[0] = typeOid;
1983 
1984 	procOid = LookupFuncName(procname, 1, argList, true);
1985 
1986 	if (!OidIsValid(procOid))
1987 		ereport(ERROR,
1988 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
1989 				 errmsg("function %s does not exist",
1990 						func_signature_string(procname, 1, NIL, argList))));
1991 
1992 	if (get_func_rettype(procOid) != typeOid)
1993 		ereport(ERROR,
1994 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1995 				 errmsg("range canonical function %s must return range type",
1996 						func_signature_string(procname, 1, NIL, argList))));
1997 
1998 	if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1999 		ereport(ERROR,
2000 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2001 				 errmsg("range canonical function %s must be immutable",
2002 						func_signature_string(procname, 1, NIL, argList))));
2003 
2004 	/* Also, range type's creator must have permission to call function */
2005 	aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
2006 	if (aclresult != ACLCHECK_OK)
2007 		aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
2008 
2009 	return procOid;
2010 }
2011 
2012 static Oid
findRangeSubtypeDiffFunction(List * procname,Oid subtype)2013 findRangeSubtypeDiffFunction(List *procname, Oid subtype)
2014 {
2015 	Oid			argList[2];
2016 	Oid			procOid;
2017 	AclResult	aclresult;
2018 
2019 	/*
2020 	 * Range subtype diff functions must take two arguments of the subtype,
2021 	 * must return float8, and must be immutable.
2022 	 */
2023 	argList[0] = subtype;
2024 	argList[1] = subtype;
2025 
2026 	procOid = LookupFuncName(procname, 2, argList, true);
2027 
2028 	if (!OidIsValid(procOid))
2029 		ereport(ERROR,
2030 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
2031 				 errmsg("function %s does not exist",
2032 						func_signature_string(procname, 2, NIL, argList))));
2033 
2034 	if (get_func_rettype(procOid) != FLOAT8OID)
2035 		ereport(ERROR,
2036 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2037 				 errmsg("range subtype diff function %s must return type %s",
2038 						func_signature_string(procname, 2, NIL, argList),
2039 						"double precision")));
2040 
2041 	if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2042 		ereport(ERROR,
2043 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2044 				 errmsg("range subtype diff function %s must be immutable",
2045 						func_signature_string(procname, 2, NIL, argList))));
2046 
2047 	/* Also, range type's creator must have permission to call function */
2048 	aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
2049 	if (aclresult != ACLCHECK_OK)
2050 		aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
2051 
2052 	return procOid;
2053 }
2054 
2055 /*
2056  *	AssignTypeArrayOid
2057  *
2058  *	Pre-assign the type's array OID for use in pg_type.typarray
2059  */
2060 Oid
AssignTypeArrayOid(void)2061 AssignTypeArrayOid(void)
2062 {
2063 	Oid			type_array_oid;
2064 
2065 	/* Use binary-upgrade override for pg_type.typarray? */
2066 	if (IsBinaryUpgrade)
2067 	{
2068 		if (!OidIsValid(binary_upgrade_next_array_pg_type_oid))
2069 			ereport(ERROR,
2070 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2071 					 errmsg("pg_type array OID value not set when in binary upgrade mode")));
2072 
2073 		type_array_oid = binary_upgrade_next_array_pg_type_oid;
2074 		binary_upgrade_next_array_pg_type_oid = InvalidOid;
2075 	}
2076 	else
2077 	{
2078 		Relation	pg_type = heap_open(TypeRelationId, AccessShareLock);
2079 
2080 		type_array_oid = GetNewOid(pg_type);
2081 		heap_close(pg_type, AccessShareLock);
2082 	}
2083 
2084 	return type_array_oid;
2085 }
2086 
2087 
2088 /*-------------------------------------------------------------------
2089  * DefineCompositeType
2090  *
2091  * Create a Composite Type relation.
2092  * `DefineRelation' does all the work, we just provide the correct
2093  * arguments!
2094  *
2095  * If the relation already exists, then 'DefineRelation' will abort
2096  * the xact...
2097  *
2098  * Return type is the new type's object address.
2099  *-------------------------------------------------------------------
2100  */
2101 ObjectAddress
DefineCompositeType(RangeVar * typevar,List * coldeflist)2102 DefineCompositeType(RangeVar *typevar, List *coldeflist)
2103 {
2104 	CreateStmt *createStmt = makeNode(CreateStmt);
2105 	Oid			old_type_oid;
2106 	Oid			typeNamespace;
2107 	ObjectAddress address;
2108 
2109 	/*
2110 	 * now set the parameters for keys/inheritance etc. All of these are
2111 	 * uninteresting for composite types...
2112 	 */
2113 	createStmt->relation = typevar;
2114 	createStmt->tableElts = coldeflist;
2115 	createStmt->inhRelations = NIL;
2116 	createStmt->constraints = NIL;
2117 	createStmt->options = NIL;
2118 	createStmt->oncommit = ONCOMMIT_NOOP;
2119 	createStmt->tablespacename = NULL;
2120 	createStmt->if_not_exists = false;
2121 
2122 	/*
2123 	 * Check for collision with an existing type name. If there is one and
2124 	 * it's an autogenerated array, we can rename it out of the way.  This
2125 	 * check is here mainly to get a better error message about a "type"
2126 	 * instead of below about a "relation".
2127 	 */
2128 	typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2129 														 NoLock, NULL);
2130 	RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2131 	old_type_oid =
2132 		GetSysCacheOid2(TYPENAMENSP,
2133 						CStringGetDatum(createStmt->relation->relname),
2134 						ObjectIdGetDatum(typeNamespace));
2135 	if (OidIsValid(old_type_oid))
2136 	{
2137 		if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2138 			ereport(ERROR,
2139 					(errcode(ERRCODE_DUPLICATE_OBJECT),
2140 					 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2141 	}
2142 
2143 	/*
2144 	 * Finally create the relation.  This also creates the type.
2145 	 */
2146 	DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address);
2147 
2148 	return address;
2149 }
2150 
2151 /*
2152  * AlterDomainDefault
2153  *
2154  * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
2155  *
2156  * Returns ObjectAddress of the modified domain.
2157  */
2158 ObjectAddress
AlterDomainDefault(List * names,Node * defaultRaw)2159 AlterDomainDefault(List *names, Node *defaultRaw)
2160 {
2161 	TypeName   *typename;
2162 	Oid			domainoid;
2163 	HeapTuple	tup;
2164 	ParseState *pstate;
2165 	Relation	rel;
2166 	char	   *defaultValue;
2167 	Node	   *defaultExpr = NULL;		/* NULL if no default specified */
2168 	Acl		   *typacl;
2169 	Datum		aclDatum;
2170 	bool		isNull;
2171 	Datum		new_record[Natts_pg_type];
2172 	bool		new_record_nulls[Natts_pg_type];
2173 	bool		new_record_repl[Natts_pg_type];
2174 	HeapTuple	newtuple;
2175 	Form_pg_type typTup;
2176 	ObjectAddress address;
2177 
2178 	/* Make a TypeName so we can use standard type lookup machinery */
2179 	typename = makeTypeNameFromNameList(names);
2180 	domainoid = typenameTypeId(NULL, typename);
2181 
2182 	/* Look up the domain in the type table */
2183 	rel = heap_open(TypeRelationId, RowExclusiveLock);
2184 
2185 	tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2186 	if (!HeapTupleIsValid(tup))
2187 		elog(ERROR, "cache lookup failed for type %u", domainoid);
2188 	typTup = (Form_pg_type) GETSTRUCT(tup);
2189 
2190 	/* Check it's a domain and check user has permission for ALTER DOMAIN */
2191 	checkDomainOwner(tup);
2192 
2193 	/* Setup new tuple */
2194 	MemSet(new_record, (Datum) 0, sizeof(new_record));
2195 	MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2196 	MemSet(new_record_repl, false, sizeof(new_record_repl));
2197 
2198 	/* Store the new default into the tuple */
2199 	if (defaultRaw)
2200 	{
2201 		/* Create a dummy ParseState for transformExpr */
2202 		pstate = make_parsestate(NULL);
2203 
2204 		/*
2205 		 * Cook the raw default into an expression; copy it in case the input
2206 		 * is in plan cache.  Note: name is used only for error messages.
2207 		 */
2208 		defaultExpr = cookDefault(pstate, copyObject(defaultRaw),
2209 								  typTup->typbasetype,
2210 								  typTup->typtypmod,
2211 								  NameStr(typTup->typname));
2212 
2213 		/*
2214 		 * If the expression is just a NULL constant, we treat the command
2215 		 * like ALTER ... DROP DEFAULT.  (But see note for same test in
2216 		 * DefineDomain.)
2217 		 */
2218 		if (defaultExpr == NULL ||
2219 			(IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2220 		{
2221 			/* Default is NULL, drop it */
2222 			new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2223 			new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2224 			new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2225 			new_record_repl[Anum_pg_type_typdefault - 1] = true;
2226 		}
2227 		else
2228 		{
2229 			/*
2230 			 * Expression must be stored as a nodeToString result, but we also
2231 			 * require a valid textual representation (mainly to make life
2232 			 * easier for pg_dump).
2233 			 */
2234 			defaultValue = deparse_expression(defaultExpr,
2235 											  NIL, false, false);
2236 
2237 			/*
2238 			 * Form an updated tuple with the new default and write it back.
2239 			 */
2240 			new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2241 
2242 			new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2243 			new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2244 			new_record_repl[Anum_pg_type_typdefault - 1] = true;
2245 		}
2246 	}
2247 	else
2248 	{
2249 		/* ALTER ... DROP DEFAULT */
2250 		new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2251 		new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2252 		new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2253 		new_record_repl[Anum_pg_type_typdefault - 1] = true;
2254 	}
2255 
2256 	newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2257 								 new_record, new_record_nulls,
2258 								 new_record_repl);
2259 
2260 	simple_heap_update(rel, &tup->t_self, newtuple);
2261 
2262 	CatalogUpdateIndexes(rel, newtuple);
2263 
2264 	/* Must extract ACL for use of GenerateTypeDependencies */
2265 	aclDatum = heap_getattr(newtuple, Anum_pg_type_typacl,
2266 							RelationGetDescr(rel), &isNull);
2267 	if (isNull)
2268 		typacl = NULL;
2269 	else
2270 		typacl = DatumGetAclPCopy(aclDatum);
2271 
2272 	/* Rebuild dependencies */
2273 	GenerateTypeDependencies(domainoid,
2274 							 (Form_pg_type) GETSTRUCT(newtuple),
2275 							 defaultExpr,
2276 							 typacl,
2277 							 0, /* relation kind is n/a */
2278 							 false,		/* a domain isn't an implicit array */
2279 							 false, /* nor is it any kind of dependent type */
2280 							 true); /* We do need to rebuild dependencies */
2281 
2282 	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2283 
2284 	ObjectAddressSet(address, TypeRelationId, domainoid);
2285 
2286 	/* Clean up */
2287 	heap_close(rel, NoLock);
2288 	heap_freetuple(newtuple);
2289 
2290 	return address;
2291 }
2292 
2293 /*
2294  * AlterDomainNotNull
2295  *
2296  * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2297  *
2298  * Returns ObjectAddress of the modified domain.
2299  */
2300 ObjectAddress
AlterDomainNotNull(List * names,bool notNull)2301 AlterDomainNotNull(List *names, bool notNull)
2302 {
2303 	TypeName   *typename;
2304 	Oid			domainoid;
2305 	Relation	typrel;
2306 	HeapTuple	tup;
2307 	Form_pg_type typTup;
2308 	ObjectAddress address = InvalidObjectAddress;
2309 
2310 	/* Make a TypeName so we can use standard type lookup machinery */
2311 	typename = makeTypeNameFromNameList(names);
2312 	domainoid = typenameTypeId(NULL, typename);
2313 
2314 	/* Look up the domain in the type table */
2315 	typrel = heap_open(TypeRelationId, RowExclusiveLock);
2316 
2317 	tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2318 	if (!HeapTupleIsValid(tup))
2319 		elog(ERROR, "cache lookup failed for type %u", domainoid);
2320 	typTup = (Form_pg_type) GETSTRUCT(tup);
2321 
2322 	/* Check it's a domain and check user has permission for ALTER DOMAIN */
2323 	checkDomainOwner(tup);
2324 
2325 	/* Is the domain already set to the desired constraint? */
2326 	if (typTup->typnotnull == notNull)
2327 	{
2328 		heap_close(typrel, RowExclusiveLock);
2329 		return address;
2330 	}
2331 
2332 	/* Adding a NOT NULL constraint requires checking existing columns */
2333 	if (notNull)
2334 	{
2335 		List	   *rels;
2336 		ListCell   *rt;
2337 
2338 		/* Fetch relation list with attributes based on this domain */
2339 		/* ShareLock is sufficient to prevent concurrent data changes */
2340 
2341 		rels = get_rels_with_domain(domainoid, ShareLock);
2342 
2343 		foreach(rt, rels)
2344 		{
2345 			RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2346 			Relation	testrel = rtc->rel;
2347 			TupleDesc	tupdesc = RelationGetDescr(testrel);
2348 			HeapScanDesc scan;
2349 			HeapTuple	tuple;
2350 			Snapshot	snapshot;
2351 
2352 			/* Scan all tuples in this relation */
2353 			snapshot = RegisterSnapshot(GetLatestSnapshot());
2354 			scan = heap_beginscan(testrel, snapshot, 0, NULL);
2355 			while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2356 			{
2357 				int			i;
2358 
2359 				/* Test attributes that are of the domain */
2360 				for (i = 0; i < rtc->natts; i++)
2361 				{
2362 					int			attnum = rtc->atts[i];
2363 
2364 					if (heap_attisnull(tuple, attnum))
2365 					{
2366 						/*
2367 						 * In principle the auxiliary information for this
2368 						 * error should be errdatatype(), but errtablecol()
2369 						 * seems considerably more useful in practice.  Since
2370 						 * this code only executes in an ALTER DOMAIN command,
2371 						 * the client should already know which domain is in
2372 						 * question.
2373 						 */
2374 						ereport(ERROR,
2375 								(errcode(ERRCODE_NOT_NULL_VIOLATION),
2376 								 errmsg("column \"%s\" of table \"%s\" contains null values",
2377 								NameStr(tupdesc->attrs[attnum - 1]->attname),
2378 										RelationGetRelationName(testrel)),
2379 								 errtablecol(testrel, attnum)));
2380 					}
2381 				}
2382 			}
2383 			heap_endscan(scan);
2384 			UnregisterSnapshot(snapshot);
2385 
2386 			/* Close each rel after processing, but keep lock */
2387 			heap_close(testrel, NoLock);
2388 		}
2389 	}
2390 
2391 	/*
2392 	 * Okay to update pg_type row.  We can scribble on typTup because it's a
2393 	 * copy.
2394 	 */
2395 	typTup->typnotnull = notNull;
2396 
2397 	simple_heap_update(typrel, &tup->t_self, tup);
2398 
2399 	CatalogUpdateIndexes(typrel, tup);
2400 
2401 	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2402 
2403 	ObjectAddressSet(address, TypeRelationId, domainoid);
2404 
2405 	/* Clean up */
2406 	heap_freetuple(tup);
2407 	heap_close(typrel, RowExclusiveLock);
2408 
2409 	return address;
2410 }
2411 
2412 /*
2413  * AlterDomainDropConstraint
2414  *
2415  * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2416  */
2417 ObjectAddress
AlterDomainDropConstraint(List * names,const char * constrName,DropBehavior behavior,bool missing_ok)2418 AlterDomainDropConstraint(List *names, const char *constrName,
2419 						  DropBehavior behavior, bool missing_ok)
2420 {
2421 	TypeName   *typename;
2422 	Oid			domainoid;
2423 	HeapTuple	tup;
2424 	Relation	rel;
2425 	Relation	conrel;
2426 	SysScanDesc conscan;
2427 	ScanKeyData key[1];
2428 	HeapTuple	contup;
2429 	bool		found = false;
2430 	ObjectAddress address = InvalidObjectAddress;
2431 
2432 	/* Make a TypeName so we can use standard type lookup machinery */
2433 	typename = makeTypeNameFromNameList(names);
2434 	domainoid = typenameTypeId(NULL, typename);
2435 
2436 	/* Look up the domain in the type table */
2437 	rel = heap_open(TypeRelationId, RowExclusiveLock);
2438 
2439 	tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2440 	if (!HeapTupleIsValid(tup))
2441 		elog(ERROR, "cache lookup failed for type %u", domainoid);
2442 
2443 	/* Check it's a domain and check user has permission for ALTER DOMAIN */
2444 	checkDomainOwner(tup);
2445 
2446 	/* Grab an appropriate lock on the pg_constraint relation */
2447 	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2448 
2449 	/* Use the index to scan only constraints of the target relation */
2450 	ScanKeyInit(&key[0],
2451 				Anum_pg_constraint_contypid,
2452 				BTEqualStrategyNumber, F_OIDEQ,
2453 				ObjectIdGetDatum(HeapTupleGetOid(tup)));
2454 
2455 	conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2456 								 NULL, 1, key);
2457 
2458 	/*
2459 	 * Scan over the result set, removing any matching entries.
2460 	 */
2461 	while ((contup = systable_getnext(conscan)) != NULL)
2462 	{
2463 		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
2464 
2465 		if (strcmp(NameStr(con->conname), constrName) == 0)
2466 		{
2467 			ObjectAddress conobj;
2468 
2469 			conobj.classId = ConstraintRelationId;
2470 			conobj.objectId = HeapTupleGetOid(contup);
2471 			conobj.objectSubId = 0;
2472 
2473 			performDeletion(&conobj, behavior, 0);
2474 			found = true;
2475 		}
2476 	}
2477 
2478 	ObjectAddressSet(address, TypeRelationId, domainoid);
2479 
2480 	/* Clean up after the scan */
2481 	systable_endscan(conscan);
2482 	heap_close(conrel, RowExclusiveLock);
2483 
2484 	heap_close(rel, NoLock);
2485 
2486 	if (!found)
2487 	{
2488 		if (!missing_ok)
2489 			ereport(ERROR,
2490 					(errcode(ERRCODE_UNDEFINED_OBJECT),
2491 				  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2492 						 constrName, TypeNameToString(typename))));
2493 		else
2494 			ereport(NOTICE,
2495 					(errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2496 							constrName, TypeNameToString(typename))));
2497 	}
2498 
2499 	return address;
2500 }
2501 
2502 /*
2503  * AlterDomainAddConstraint
2504  *
2505  * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2506  */
2507 ObjectAddress
AlterDomainAddConstraint(List * names,Node * newConstraint,ObjectAddress * constrAddr)2508 AlterDomainAddConstraint(List *names, Node *newConstraint,
2509 						 ObjectAddress *constrAddr)
2510 {
2511 	TypeName   *typename;
2512 	Oid			domainoid;
2513 	Relation	typrel;
2514 	HeapTuple	tup;
2515 	Form_pg_type typTup;
2516 	Constraint *constr;
2517 	char	   *ccbin;
2518 	ObjectAddress address;
2519 
2520 	/* Make a TypeName so we can use standard type lookup machinery */
2521 	typename = makeTypeNameFromNameList(names);
2522 	domainoid = typenameTypeId(NULL, typename);
2523 
2524 	/* Look up the domain in the type table */
2525 	typrel = heap_open(TypeRelationId, RowExclusiveLock);
2526 
2527 	tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2528 	if (!HeapTupleIsValid(tup))
2529 		elog(ERROR, "cache lookup failed for type %u", domainoid);
2530 	typTup = (Form_pg_type) GETSTRUCT(tup);
2531 
2532 	/* Check it's a domain and check user has permission for ALTER DOMAIN */
2533 	checkDomainOwner(tup);
2534 
2535 	if (!IsA(newConstraint, Constraint))
2536 		elog(ERROR, "unrecognized node type: %d",
2537 			 (int) nodeTag(newConstraint));
2538 
2539 	constr = (Constraint *) newConstraint;
2540 
2541 	switch (constr->contype)
2542 	{
2543 		case CONSTR_CHECK:
2544 			/* processed below */
2545 			break;
2546 
2547 		case CONSTR_UNIQUE:
2548 			ereport(ERROR,
2549 					(errcode(ERRCODE_SYNTAX_ERROR),
2550 					 errmsg("unique constraints not possible for domains")));
2551 			break;
2552 
2553 		case CONSTR_PRIMARY:
2554 			ereport(ERROR,
2555 					(errcode(ERRCODE_SYNTAX_ERROR),
2556 				errmsg("primary key constraints not possible for domains")));
2557 			break;
2558 
2559 		case CONSTR_EXCLUSION:
2560 			ereport(ERROR,
2561 					(errcode(ERRCODE_SYNTAX_ERROR),
2562 				  errmsg("exclusion constraints not possible for domains")));
2563 			break;
2564 
2565 		case CONSTR_FOREIGN:
2566 			ereport(ERROR,
2567 					(errcode(ERRCODE_SYNTAX_ERROR),
2568 				errmsg("foreign key constraints not possible for domains")));
2569 			break;
2570 
2571 		case CONSTR_ATTR_DEFERRABLE:
2572 		case CONSTR_ATTR_NOT_DEFERRABLE:
2573 		case CONSTR_ATTR_DEFERRED:
2574 		case CONSTR_ATTR_IMMEDIATE:
2575 			ereport(ERROR,
2576 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2577 					 errmsg("specifying constraint deferrability not supported for domains")));
2578 			break;
2579 
2580 		default:
2581 			elog(ERROR, "unrecognized constraint subtype: %d",
2582 				 (int) constr->contype);
2583 			break;
2584 	}
2585 
2586 	/*
2587 	 * Since all other constraint types throw errors, this must be a check
2588 	 * constraint.  First, process the constraint expression and add an entry
2589 	 * to pg_constraint.
2590 	 */
2591 
2592 	ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
2593 								typTup->typbasetype, typTup->typtypmod,
2594 								constr, NameStr(typTup->typname), constrAddr);
2595 
2596 	/*
2597 	 * If requested to validate the constraint, test all values stored in the
2598 	 * attributes based on the domain the constraint is being added to.
2599 	 */
2600 	if (!constr->skip_validation)
2601 		validateDomainConstraint(domainoid, ccbin);
2602 
2603 	ObjectAddressSet(address, TypeRelationId, domainoid);
2604 
2605 	/* Clean up */
2606 	heap_close(typrel, RowExclusiveLock);
2607 
2608 	return address;
2609 }
2610 
2611 /*
2612  * AlterDomainValidateConstraint
2613  *
2614  * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2615  */
2616 ObjectAddress
AlterDomainValidateConstraint(List * names,char * constrName)2617 AlterDomainValidateConstraint(List *names, char *constrName)
2618 {
2619 	TypeName   *typename;
2620 	Oid			domainoid;
2621 	Relation	typrel;
2622 	Relation	conrel;
2623 	HeapTuple	tup;
2624 	Form_pg_constraint con = NULL;
2625 	Form_pg_constraint copy_con;
2626 	char	   *conbin;
2627 	SysScanDesc scan;
2628 	Datum		val;
2629 	bool		found = false;
2630 	bool		isnull;
2631 	HeapTuple	tuple;
2632 	HeapTuple	copyTuple;
2633 	ScanKeyData key;
2634 	ObjectAddress address;
2635 
2636 	/* Make a TypeName so we can use standard type lookup machinery */
2637 	typename = makeTypeNameFromNameList(names);
2638 	domainoid = typenameTypeId(NULL, typename);
2639 
2640 	/* Look up the domain in the type table */
2641 	typrel = heap_open(TypeRelationId, AccessShareLock);
2642 
2643 	tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2644 	if (!HeapTupleIsValid(tup))
2645 		elog(ERROR, "cache lookup failed for type %u", domainoid);
2646 
2647 	/* Check it's a domain and check user has permission for ALTER DOMAIN */
2648 	checkDomainOwner(tup);
2649 
2650 	/*
2651 	 * Find and check the target constraint
2652 	 */
2653 	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2654 	ScanKeyInit(&key,
2655 				Anum_pg_constraint_contypid,
2656 				BTEqualStrategyNumber, F_OIDEQ,
2657 				ObjectIdGetDatum(domainoid));
2658 	scan = systable_beginscan(conrel, ConstraintTypidIndexId,
2659 							  true, NULL, 1, &key);
2660 
2661 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2662 	{
2663 		con = (Form_pg_constraint) GETSTRUCT(tuple);
2664 		if (strcmp(NameStr(con->conname), constrName) == 0)
2665 		{
2666 			found = true;
2667 			break;
2668 		}
2669 	}
2670 
2671 	if (!found)
2672 		ereport(ERROR,
2673 				(errcode(ERRCODE_UNDEFINED_OBJECT),
2674 				 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2675 						constrName, TypeNameToString(typename))));
2676 
2677 	if (con->contype != CONSTRAINT_CHECK)
2678 		ereport(ERROR,
2679 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2680 		errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2681 			   constrName, TypeNameToString(typename))));
2682 
2683 	val = SysCacheGetAttr(CONSTROID, tuple,
2684 						  Anum_pg_constraint_conbin,
2685 						  &isnull);
2686 	if (isnull)
2687 		elog(ERROR, "null conbin for constraint %u",
2688 			 HeapTupleGetOid(tuple));
2689 	conbin = TextDatumGetCString(val);
2690 
2691 	validateDomainConstraint(domainoid, conbin);
2692 
2693 	/*
2694 	 * Now update the catalog, while we have the door open.
2695 	 */
2696 	copyTuple = heap_copytuple(tuple);
2697 	copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2698 	copy_con->convalidated = true;
2699 	simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
2700 	CatalogUpdateIndexes(conrel, copyTuple);
2701 
2702 	InvokeObjectPostAlterHook(ConstraintRelationId,
2703 							  HeapTupleGetOid(copyTuple), 0);
2704 
2705 	ObjectAddressSet(address, TypeRelationId, domainoid);
2706 
2707 	heap_freetuple(copyTuple);
2708 
2709 	systable_endscan(scan);
2710 
2711 	heap_close(typrel, AccessShareLock);
2712 	heap_close(conrel, RowExclusiveLock);
2713 
2714 	ReleaseSysCache(tup);
2715 
2716 	return address;
2717 }
2718 
2719 static void
validateDomainConstraint(Oid domainoid,char * ccbin)2720 validateDomainConstraint(Oid domainoid, char *ccbin)
2721 {
2722 	Expr	   *expr = (Expr *) stringToNode(ccbin);
2723 	List	   *rels;
2724 	ListCell   *rt;
2725 	EState	   *estate;
2726 	ExprContext *econtext;
2727 	ExprState  *exprstate;
2728 
2729 	/* Need an EState to run ExecEvalExpr */
2730 	estate = CreateExecutorState();
2731 	econtext = GetPerTupleExprContext(estate);
2732 
2733 	/* build execution state for expr */
2734 	exprstate = ExecPrepareExpr(expr, estate);
2735 
2736 	/* Fetch relation list with attributes based on this domain */
2737 	/* ShareLock is sufficient to prevent concurrent data changes */
2738 
2739 	rels = get_rels_with_domain(domainoid, ShareLock);
2740 
2741 	foreach(rt, rels)
2742 	{
2743 		RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2744 		Relation	testrel = rtc->rel;
2745 		TupleDesc	tupdesc = RelationGetDescr(testrel);
2746 		HeapScanDesc scan;
2747 		HeapTuple	tuple;
2748 		Snapshot	snapshot;
2749 
2750 		/* Scan all tuples in this relation */
2751 		snapshot = RegisterSnapshot(GetLatestSnapshot());
2752 		scan = heap_beginscan(testrel, snapshot, 0, NULL);
2753 		while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2754 		{
2755 			int			i;
2756 
2757 			/* Test attributes that are of the domain */
2758 			for (i = 0; i < rtc->natts; i++)
2759 			{
2760 				int			attnum = rtc->atts[i];
2761 				Datum		d;
2762 				bool		isNull;
2763 				Datum		conResult;
2764 
2765 				d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2766 
2767 				econtext->domainValue_datum = d;
2768 				econtext->domainValue_isNull = isNull;
2769 
2770 				conResult = ExecEvalExprSwitchContext(exprstate,
2771 													  econtext,
2772 													  &isNull, NULL);
2773 
2774 				if (!isNull && !DatumGetBool(conResult))
2775 				{
2776 					/*
2777 					 * In principle the auxiliary information for this error
2778 					 * should be errdomainconstraint(), but errtablecol()
2779 					 * seems considerably more useful in practice.  Since this
2780 					 * code only executes in an ALTER DOMAIN command, the
2781 					 * client should already know which domain is in question,
2782 					 * and which constraint too.
2783 					 */
2784 					ereport(ERROR,
2785 							(errcode(ERRCODE_CHECK_VIOLATION),
2786 							 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2787 								NameStr(tupdesc->attrs[attnum - 1]->attname),
2788 									RelationGetRelationName(testrel)),
2789 							 errtablecol(testrel, attnum)));
2790 				}
2791 			}
2792 
2793 			ResetExprContext(econtext);
2794 		}
2795 		heap_endscan(scan);
2796 		UnregisterSnapshot(snapshot);
2797 
2798 		/* Hold relation lock till commit (XXX bad for concurrency) */
2799 		heap_close(testrel, NoLock);
2800 	}
2801 
2802 	FreeExecutorState(estate);
2803 }
2804 
2805 /*
2806  * get_rels_with_domain
2807  *
2808  * Fetch all relations / attributes which are using the domain
2809  *
2810  * The result is a list of RelToCheck structs, one for each distinct
2811  * relation, each containing one or more attribute numbers that are of
2812  * the domain type.  We have opened each rel and acquired the specified lock
2813  * type on it.
2814  *
2815  * We support nested domains by including attributes that are of derived
2816  * domain types.  Current callers do not need to distinguish between attributes
2817  * that are of exactly the given domain and those that are of derived domains.
2818  *
2819  * XXX this is completely broken because there is no way to lock the domain
2820  * to prevent columns from being added or dropped while our command runs.
2821  * We can partially protect against column drops by locking relations as we
2822  * come across them, but there is still a race condition (the window between
2823  * seeing a pg_depend entry and acquiring lock on the relation it references).
2824  * Also, holding locks on all these relations simultaneously creates a non-
2825  * trivial risk of deadlock.  We can minimize but not eliminate the deadlock
2826  * risk by using the weakest suitable lock (ShareLock for most callers).
2827  *
2828  * XXX the API for this is not sufficient to support checking domain values
2829  * that are inside container types, such as composite types, arrays, or
2830  * ranges.  Currently we just error out if a container type containing the
2831  * target domain is stored anywhere.
2832  *
2833  * Generally used for retrieving a list of tests when adding
2834  * new constraints to a domain.
2835  */
2836 static List *
get_rels_with_domain(Oid domainOid,LOCKMODE lockmode)2837 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2838 {
2839 	List	   *result = NIL;
2840 	char	   *domainTypeName = format_type_be(domainOid);
2841 	Relation	depRel;
2842 	ScanKeyData key[2];
2843 	SysScanDesc depScan;
2844 	HeapTuple	depTup;
2845 
2846 	Assert(lockmode != NoLock);
2847 
2848 	/* since this function recurses, it could be driven to stack overflow */
2849 	check_stack_depth();
2850 
2851 	/*
2852 	 * We scan pg_depend to find those things that depend on the domain. (We
2853 	 * assume we can ignore refobjsubid for a domain.)
2854 	 */
2855 	depRel = heap_open(DependRelationId, AccessShareLock);
2856 
2857 	ScanKeyInit(&key[0],
2858 				Anum_pg_depend_refclassid,
2859 				BTEqualStrategyNumber, F_OIDEQ,
2860 				ObjectIdGetDatum(TypeRelationId));
2861 	ScanKeyInit(&key[1],
2862 				Anum_pg_depend_refobjid,
2863 				BTEqualStrategyNumber, F_OIDEQ,
2864 				ObjectIdGetDatum(domainOid));
2865 
2866 	depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2867 								 NULL, 2, key);
2868 
2869 	while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2870 	{
2871 		Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2872 		RelToCheck *rtc = NULL;
2873 		ListCell   *rellist;
2874 		Form_pg_attribute pg_att;
2875 		int			ptr;
2876 
2877 		/* Check for directly dependent types */
2878 		if (pg_depend->classid == TypeRelationId)
2879 		{
2880 			if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
2881 			{
2882 				/*
2883 				 * This is a sub-domain, so recursively add dependent columns
2884 				 * to the output list.  This is a bit inefficient since we may
2885 				 * fail to combine RelToCheck entries when attributes of the
2886 				 * same rel have different derived domain types, but it's
2887 				 * probably not worth improving.
2888 				 */
2889 				result = list_concat(result,
2890 									 get_rels_with_domain(pg_depend->objid,
2891 														  lockmode));
2892 			}
2893 			else
2894 			{
2895 				/*
2896 				 * Otherwise, it is some container type using the domain, so
2897 				 * fail if there are any columns of this type.
2898 				 */
2899 				find_composite_type_dependencies(pg_depend->objid,
2900 												 NULL,
2901 												 domainTypeName);
2902 			}
2903 			continue;
2904 		}
2905 
2906 		/* Else, ignore dependees that aren't user columns of relations */
2907 		/* (we assume system columns are never of domain types) */
2908 		if (pg_depend->classid != RelationRelationId ||
2909 			pg_depend->objsubid <= 0)
2910 			continue;
2911 
2912 		/* See if we already have an entry for this relation */
2913 		foreach(rellist, result)
2914 		{
2915 			RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2916 
2917 			if (RelationGetRelid(rt->rel) == pg_depend->objid)
2918 			{
2919 				rtc = rt;
2920 				break;
2921 			}
2922 		}
2923 
2924 		if (rtc == NULL)
2925 		{
2926 			/* First attribute found for this relation */
2927 			Relation	rel;
2928 
2929 			/* Acquire requested lock on relation */
2930 			rel = relation_open(pg_depend->objid, lockmode);
2931 
2932 			/*
2933 			 * Check to see if rowtype is stored anyplace as a composite-type
2934 			 * column; if so we have to fail, for now anyway.
2935 			 */
2936 			if (OidIsValid(rel->rd_rel->reltype))
2937 				find_composite_type_dependencies(rel->rd_rel->reltype,
2938 												 NULL,
2939 												 domainTypeName);
2940 
2941 			/*
2942 			 * Otherwise, we can ignore relations except those with both
2943 			 * storage and user-chosen column types.
2944 			 *
2945 			 * XXX If an index-only scan could satisfy "col::some_domain" from
2946 			 * a suitable expression index, this should also check expression
2947 			 * index columns.
2948 			 */
2949 			if (rel->rd_rel->relkind != RELKIND_RELATION &&
2950 				rel->rd_rel->relkind != RELKIND_MATVIEW)
2951 			{
2952 				relation_close(rel, lockmode);
2953 				continue;
2954 			}
2955 
2956 			/* Build the RelToCheck entry with enough space for all atts */
2957 			rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2958 			rtc->rel = rel;
2959 			rtc->natts = 0;
2960 			rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2961 			result = lcons(rtc, result);
2962 		}
2963 
2964 		/*
2965 		 * Confirm column has not been dropped, and is of the expected type.
2966 		 * This defends against an ALTER DROP COLUMN occurring just before we
2967 		 * acquired lock ... but if the whole table were dropped, we'd still
2968 		 * have a problem.
2969 		 */
2970 		if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2971 			continue;
2972 		pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2973 		if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2974 			continue;
2975 
2976 		/*
2977 		 * Okay, add column to result.  We store the columns in column-number
2978 		 * order; this is just a hack to improve predictability of regression
2979 		 * test output ...
2980 		 */
2981 		Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2982 
2983 		ptr = rtc->natts++;
2984 		while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2985 		{
2986 			rtc->atts[ptr] = rtc->atts[ptr - 1];
2987 			ptr--;
2988 		}
2989 		rtc->atts[ptr] = pg_depend->objsubid;
2990 	}
2991 
2992 	systable_endscan(depScan);
2993 
2994 	relation_close(depRel, AccessShareLock);
2995 
2996 	return result;
2997 }
2998 
2999 /*
3000  * checkDomainOwner
3001  *
3002  * Check that the type is actually a domain and that the current user
3003  * has permission to do ALTER DOMAIN on it.  Throw an error if not.
3004  */
3005 void
checkDomainOwner(HeapTuple tup)3006 checkDomainOwner(HeapTuple tup)
3007 {
3008 	Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
3009 
3010 	/* Check that this is actually a domain */
3011 	if (typTup->typtype != TYPTYPE_DOMAIN)
3012 		ereport(ERROR,
3013 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3014 				 errmsg("%s is not a domain",
3015 						format_type_be(HeapTupleGetOid(tup)))));
3016 
3017 	/* Permission check: must own type */
3018 	if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3019 		aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
3020 }
3021 
3022 /*
3023  * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
3024  */
3025 static char *
domainAddConstraint(Oid domainOid,Oid domainNamespace,Oid baseTypeOid,int typMod,Constraint * constr,char * domainName,ObjectAddress * constrAddr)3026 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
3027 					int typMod, Constraint *constr,
3028 					char *domainName, ObjectAddress *constrAddr)
3029 {
3030 	Node	   *expr;
3031 	char	   *ccsrc;
3032 	char	   *ccbin;
3033 	ParseState *pstate;
3034 	CoerceToDomainValue *domVal;
3035 	Oid			ccoid;
3036 
3037 	/*
3038 	 * Assign or validate constraint name
3039 	 */
3040 	if (constr->conname)
3041 	{
3042 		if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
3043 								 domainOid,
3044 								 domainNamespace,
3045 								 constr->conname))
3046 			ereport(ERROR,
3047 					(errcode(ERRCODE_DUPLICATE_OBJECT),
3048 				 errmsg("constraint \"%s\" for domain \"%s\" already exists",
3049 						constr->conname, domainName)));
3050 	}
3051 	else
3052 		constr->conname = ChooseConstraintName(domainName,
3053 											   NULL,
3054 											   "check",
3055 											   domainNamespace,
3056 											   NIL);
3057 
3058 	/*
3059 	 * Convert the A_EXPR in raw_expr into an EXPR
3060 	 */
3061 	pstate = make_parsestate(NULL);
3062 
3063 	/*
3064 	 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3065 	 * the expression.  Note that it will appear to have the type of the base
3066 	 * type, not the domain.  This seems correct since within the check
3067 	 * expression, we should not assume the input value can be considered a
3068 	 * member of the domain.
3069 	 */
3070 	domVal = makeNode(CoerceToDomainValue);
3071 	domVal->typeId = baseTypeOid;
3072 	domVal->typeMod = typMod;
3073 	domVal->collation = get_typcollation(baseTypeOid);
3074 	domVal->location = -1;		/* will be set when/if used */
3075 
3076 	pstate->p_value_substitute = (Node *) domVal;
3077 
3078 	/*
3079 	 * Transform the expression; first we must copy the input, in case it's in
3080 	 * plan cache.
3081 	 */
3082 	expr = transformExpr(pstate, copyObject(constr->raw_expr),
3083 						 EXPR_KIND_DOMAIN_CHECK);
3084 
3085 	/*
3086 	 * Make sure it yields a boolean result.
3087 	 */
3088 	expr = coerce_to_boolean(pstate, expr, "CHECK");
3089 
3090 	/*
3091 	 * Fix up collation information.
3092 	 */
3093 	assign_expr_collations(pstate, expr);
3094 
3095 	/*
3096 	 * Domains don't allow variables (this is probably dead code now that
3097 	 * add_missing_from is history, but let's be sure).
3098 	 */
3099 	if (list_length(pstate->p_rtable) != 0 ||
3100 		contain_var_clause(expr))
3101 		ereport(ERROR,
3102 				(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3103 		  errmsg("cannot use table references in domain check constraint")));
3104 
3105 	/*
3106 	 * Convert to string form for storage.
3107 	 */
3108 	ccbin = nodeToString(expr);
3109 
3110 	/*
3111 	 * Deparse it to produce text for consrc.
3112 	 */
3113 	ccsrc = deparse_expression(expr,
3114 							   NIL, false, false);
3115 
3116 	/*
3117 	 * Store the constraint in pg_constraint
3118 	 */
3119 	ccoid =
3120 		CreateConstraintEntry(constr->conname,	/* Constraint Name */
3121 							  domainNamespace,	/* namespace */
3122 							  CONSTRAINT_CHECK, /* Constraint Type */
3123 							  false,	/* Is Deferrable */
3124 							  false,	/* Is Deferred */
3125 							  !constr->skip_validation, /* Is Validated */
3126 							  InvalidOid,		/* not a relation constraint */
3127 							  NULL,
3128 							  0,
3129 							  domainOid,		/* domain constraint */
3130 							  InvalidOid,		/* no associated index */
3131 							  InvalidOid,		/* Foreign key fields */
3132 							  NULL,
3133 							  NULL,
3134 							  NULL,
3135 							  NULL,
3136 							  0,
3137 							  ' ',
3138 							  ' ',
3139 							  ' ',
3140 							  NULL,		/* not an exclusion constraint */
3141 							  expr,		/* Tree form of check constraint */
3142 							  ccbin,	/* Binary form of check constraint */
3143 							  ccsrc,	/* Source form of check constraint */
3144 							  true,		/* is local */
3145 							  0,	/* inhcount */
3146 							  false,	/* connoinherit */
3147 							  false);	/* is_internal */
3148 	if (constrAddr)
3149 		ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
3150 
3151 	/*
3152 	 * Return the compiled constraint expression so the calling routine can
3153 	 * perform any additional required tests.
3154 	 */
3155 	return ccbin;
3156 }
3157 
3158 
3159 /*
3160  * Execute ALTER TYPE RENAME
3161  */
3162 ObjectAddress
RenameType(RenameStmt * stmt)3163 RenameType(RenameStmt *stmt)
3164 {
3165 	List	   *names = stmt->object;
3166 	const char *newTypeName = stmt->newname;
3167 	TypeName   *typename;
3168 	Oid			typeOid;
3169 	Relation	rel;
3170 	HeapTuple	tup;
3171 	Form_pg_type typTup;
3172 	ObjectAddress address;
3173 
3174 	/* Make a TypeName so we can use standard type lookup machinery */
3175 	typename = makeTypeNameFromNameList(names);
3176 	typeOid = typenameTypeId(NULL, typename);
3177 
3178 	/* Look up the type in the type table */
3179 	rel = heap_open(TypeRelationId, RowExclusiveLock);
3180 
3181 	tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3182 	if (!HeapTupleIsValid(tup))
3183 		elog(ERROR, "cache lookup failed for type %u", typeOid);
3184 	typTup = (Form_pg_type) GETSTRUCT(tup);
3185 
3186 	/* check permissions on type */
3187 	if (!pg_type_ownercheck(typeOid, GetUserId()))
3188 		aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3189 
3190 	/* ALTER DOMAIN used on a non-domain? */
3191 	if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3192 		ereport(ERROR,
3193 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3194 				 errmsg("\"%s\" is not a domain",
3195 						format_type_be(typeOid))));
3196 
3197 	/*
3198 	 * If it's a composite type, we need to check that it really is a
3199 	 * free-standing composite type, and not a table's rowtype. We want people
3200 	 * to use ALTER TABLE not ALTER TYPE for that case.
3201 	 */
3202 	if (typTup->typtype == TYPTYPE_COMPOSITE &&
3203 		get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3204 		ereport(ERROR,
3205 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3206 				 errmsg("%s is a table's row type",
3207 						format_type_be(typeOid)),
3208 				 errhint("Use ALTER TABLE instead.")));
3209 
3210 	/* don't allow direct alteration of array types, either */
3211 	if (OidIsValid(typTup->typelem) &&
3212 		get_array_type(typTup->typelem) == typeOid)
3213 		ereport(ERROR,
3214 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3215 				 errmsg("cannot alter array type %s",
3216 						format_type_be(typeOid)),
3217 				 errhint("You can alter type %s, which will alter the array type as well.",
3218 						 format_type_be(typTup->typelem))));
3219 
3220 	/*
3221 	 * If type is composite we need to rename associated pg_class entry too.
3222 	 * RenameRelationInternal will call RenameTypeInternal automatically.
3223 	 */
3224 	if (typTup->typtype == TYPTYPE_COMPOSITE)
3225 		RenameRelationInternal(typTup->typrelid, newTypeName, false);
3226 	else
3227 		RenameTypeInternal(typeOid, newTypeName,
3228 						   typTup->typnamespace);
3229 
3230 	ObjectAddressSet(address, TypeRelationId, typeOid);
3231 	/* Clean up */
3232 	heap_close(rel, RowExclusiveLock);
3233 
3234 	return address;
3235 }
3236 
3237 /*
3238  * Change the owner of a type.
3239  */
3240 ObjectAddress
AlterTypeOwner(List * names,Oid newOwnerId,ObjectType objecttype)3241 AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
3242 {
3243 	TypeName   *typename;
3244 	Oid			typeOid;
3245 	Relation	rel;
3246 	HeapTuple	tup;
3247 	HeapTuple	newtup;
3248 	Form_pg_type typTup;
3249 	AclResult	aclresult;
3250 	ObjectAddress address;
3251 
3252 	rel = heap_open(TypeRelationId, RowExclusiveLock);
3253 
3254 	/* Make a TypeName so we can use standard type lookup machinery */
3255 	typename = makeTypeNameFromNameList(names);
3256 
3257 	/* Use LookupTypeName here so that shell types can be processed */
3258 	tup = LookupTypeName(NULL, typename, NULL, false);
3259 	if (tup == NULL)
3260 		ereport(ERROR,
3261 				(errcode(ERRCODE_UNDEFINED_OBJECT),
3262 				 errmsg("type \"%s\" does not exist",
3263 						TypeNameToString(typename))));
3264 	typeOid = typeTypeId(tup);
3265 
3266 	/* Copy the syscache entry so we can scribble on it below */
3267 	newtup = heap_copytuple(tup);
3268 	ReleaseSysCache(tup);
3269 	tup = newtup;
3270 	typTup = (Form_pg_type) GETSTRUCT(tup);
3271 
3272 	/* Don't allow ALTER DOMAIN on a type */
3273 	if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3274 		ereport(ERROR,
3275 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3276 				 errmsg("%s is not a domain",
3277 						format_type_be(typeOid))));
3278 
3279 	/*
3280 	 * If it's a composite type, we need to check that it really is a
3281 	 * free-standing composite type, and not a table's rowtype. We want people
3282 	 * to use ALTER TABLE not ALTER TYPE for that case.
3283 	 */
3284 	if (typTup->typtype == TYPTYPE_COMPOSITE &&
3285 		get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3286 		ereport(ERROR,
3287 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3288 				 errmsg("%s is a table's row type",
3289 						format_type_be(typeOid)),
3290 				 errhint("Use ALTER TABLE instead.")));
3291 
3292 	/* don't allow direct alteration of array types, either */
3293 	if (OidIsValid(typTup->typelem) &&
3294 		get_array_type(typTup->typelem) == typeOid)
3295 		ereport(ERROR,
3296 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3297 				 errmsg("cannot alter array type %s",
3298 						format_type_be(typeOid)),
3299 				 errhint("You can alter type %s, which will alter the array type as well.",
3300 						 format_type_be(typTup->typelem))));
3301 
3302 	/*
3303 	 * If the new owner is the same as the existing owner, consider the
3304 	 * command to have succeeded.  This is for dump restoration purposes.
3305 	 */
3306 	if (typTup->typowner != newOwnerId)
3307 	{
3308 		/* Superusers can always do it */
3309 		if (!superuser())
3310 		{
3311 			/* Otherwise, must be owner of the existing object */
3312 			if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3313 				aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
3314 
3315 			/* Must be able to become new owner */
3316 			check_is_member_of_role(GetUserId(), newOwnerId);
3317 
3318 			/* New owner must have CREATE privilege on namespace */
3319 			aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3320 											  newOwnerId,
3321 											  ACL_CREATE);
3322 			if (aclresult != ACLCHECK_OK)
3323 				aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
3324 							   get_namespace_name(typTup->typnamespace));
3325 		}
3326 
3327 		AlterTypeOwner_oid(typeOid, newOwnerId, true);
3328 	}
3329 
3330 	ObjectAddressSet(address, TypeRelationId, typeOid);
3331 
3332 	/* Clean up */
3333 	heap_close(rel, RowExclusiveLock);
3334 
3335 	return address;
3336 }
3337 
3338 /*
3339  * AlterTypeOwner_oid - change type owner unconditionally
3340  *
3341  * This function recurses to handle a pg_class entry, if necessary.  It
3342  * invokes any necessary access object hooks.  If hasDependEntry is TRUE, this
3343  * function modifies the pg_shdepend entry appropriately (this should be
3344  * passed as FALSE only for table rowtypes and array types).
3345  *
3346  * This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
3347  * OWNED BY.  It assumes the caller has done all needed check.
3348  */
3349 void
AlterTypeOwner_oid(Oid typeOid,Oid newOwnerId,bool hasDependEntry)3350 AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
3351 {
3352 	Relation	rel;
3353 	HeapTuple	tup;
3354 	Form_pg_type typTup;
3355 
3356 	rel = heap_open(TypeRelationId, RowExclusiveLock);
3357 
3358 	tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3359 	if (!HeapTupleIsValid(tup))
3360 		elog(ERROR, "cache lookup failed for type %u", typeOid);
3361 	typTup = (Form_pg_type) GETSTRUCT(tup);
3362 
3363 	/*
3364 	 * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3365 	 * the pg_class entry properly.  That will call back to
3366 	 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3367 	 */
3368 	if (typTup->typtype == TYPTYPE_COMPOSITE)
3369 		ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3370 	else
3371 		AlterTypeOwnerInternal(typeOid, newOwnerId);
3372 
3373 	/* Update owner dependency reference */
3374 	if (hasDependEntry)
3375 		changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3376 
3377 	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3378 
3379 	ReleaseSysCache(tup);
3380 	heap_close(rel, RowExclusiveLock);
3381 }
3382 
3383 /*
3384  * AlterTypeOwnerInternal - bare-bones type owner change.
3385  *
3386  * This routine simply modifies the owner of a pg_type entry, and recurses
3387  * to handle a possible array type.
3388  */
3389 void
AlterTypeOwnerInternal(Oid typeOid,Oid newOwnerId)3390 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
3391 {
3392 	Relation	rel;
3393 	HeapTuple	tup;
3394 	Form_pg_type typTup;
3395 	Datum		repl_val[Natts_pg_type];
3396 	bool		repl_null[Natts_pg_type];
3397 	bool		repl_repl[Natts_pg_type];
3398 	Acl		   *newAcl;
3399 	Datum		aclDatum;
3400 	bool		isNull;
3401 
3402 	rel = heap_open(TypeRelationId, RowExclusiveLock);
3403 
3404 	tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3405 	if (!HeapTupleIsValid(tup))
3406 		elog(ERROR, "cache lookup failed for type %u", typeOid);
3407 	typTup = (Form_pg_type) GETSTRUCT(tup);
3408 
3409 	memset(repl_null, false, sizeof(repl_null));
3410 	memset(repl_repl, false, sizeof(repl_repl));
3411 
3412 	repl_repl[Anum_pg_type_typowner - 1] = true;
3413 	repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3414 
3415 	aclDatum = heap_getattr(tup,
3416 							Anum_pg_type_typacl,
3417 							RelationGetDescr(rel),
3418 							&isNull);
3419 	/* Null ACLs do not require changes */
3420 	if (!isNull)
3421 	{
3422 		newAcl = aclnewowner(DatumGetAclP(aclDatum),
3423 							 typTup->typowner, newOwnerId);
3424 		repl_repl[Anum_pg_type_typacl - 1] = true;
3425 		repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3426 	}
3427 
3428 	tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3429 							repl_repl);
3430 
3431 	simple_heap_update(rel, &tup->t_self, tup);
3432 
3433 	CatalogUpdateIndexes(rel, tup);
3434 
3435 	/* If it has an array type, update that too */
3436 	if (OidIsValid(typTup->typarray))
3437 		AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
3438 
3439 	/* Clean up */
3440 	heap_close(rel, RowExclusiveLock);
3441 }
3442 
3443 /*
3444  * Execute ALTER TYPE SET SCHEMA
3445  */
3446 ObjectAddress
AlterTypeNamespace(List * names,const char * newschema,ObjectType objecttype,Oid * oldschema)3447 AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype,
3448 				   Oid *oldschema)
3449 {
3450 	TypeName   *typename;
3451 	Oid			typeOid;
3452 	Oid			nspOid;
3453 	Oid			oldNspOid;
3454 	ObjectAddresses *objsMoved;
3455 	ObjectAddress myself;
3456 
3457 	/* Make a TypeName so we can use standard type lookup machinery */
3458 	typename = makeTypeNameFromNameList(names);
3459 	typeOid = typenameTypeId(NULL, typename);
3460 
3461 	/* Don't allow ALTER DOMAIN on a type */
3462 	if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3463 		ereport(ERROR,
3464 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3465 				 errmsg("%s is not a domain",
3466 						format_type_be(typeOid))));
3467 
3468 	/* get schema OID and check its permissions */
3469 	nspOid = LookupCreationNamespace(newschema);
3470 
3471 	objsMoved = new_object_addresses();
3472 	oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3473 	free_object_addresses(objsMoved);
3474 
3475 	if (oldschema)
3476 		*oldschema = oldNspOid;
3477 
3478 	ObjectAddressSet(myself, TypeRelationId, typeOid);
3479 
3480 	return myself;
3481 }
3482 
3483 Oid
AlterTypeNamespace_oid(Oid typeOid,Oid nspOid,ObjectAddresses * objsMoved)3484 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
3485 {
3486 	Oid			elemOid;
3487 
3488 	/* check permissions on type */
3489 	if (!pg_type_ownercheck(typeOid, GetUserId()))
3490 		aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
3491 
3492 	/* don't allow direct alteration of array types */
3493 	elemOid = get_element_type(typeOid);
3494 	if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3495 		ereport(ERROR,
3496 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3497 				 errmsg("cannot alter array type %s",
3498 						format_type_be(typeOid)),
3499 				 errhint("You can alter type %s, which will alter the array type as well.",
3500 						 format_type_be(elemOid))));
3501 
3502 	/* and do the work */
3503 	return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3504 }
3505 
3506 /*
3507  * Move specified type to new namespace.
3508  *
3509  * Caller must have already checked privileges.
3510  *
3511  * The function automatically recurses to process the type's array type,
3512  * if any.  isImplicitArray should be TRUE only when doing this internal
3513  * recursion (outside callers must never try to move an array type directly).
3514  *
3515  * If errorOnTableType is TRUE, the function errors out if the type is
3516  * a table type.  ALTER TABLE has to be used to move a table to a new
3517  * namespace.
3518  *
3519  * Returns the type's old namespace OID.
3520  */
3521 Oid
AlterTypeNamespaceInternal(Oid typeOid,Oid nspOid,bool isImplicitArray,bool errorOnTableType,ObjectAddresses * objsMoved)3522 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
3523 						   bool isImplicitArray,
3524 						   bool errorOnTableType,
3525 						   ObjectAddresses *objsMoved)
3526 {
3527 	Relation	rel;
3528 	HeapTuple	tup;
3529 	Form_pg_type typform;
3530 	Oid			oldNspOid;
3531 	Oid			arrayOid;
3532 	bool		isCompositeType;
3533 	ObjectAddress thisobj;
3534 
3535 	/*
3536 	 * Make sure we haven't moved this object previously.
3537 	 */
3538 	thisobj.classId = TypeRelationId;
3539 	thisobj.objectId = typeOid;
3540 	thisobj.objectSubId = 0;
3541 
3542 	if (object_address_present(&thisobj, objsMoved))
3543 		return InvalidOid;
3544 
3545 	rel = heap_open(TypeRelationId, RowExclusiveLock);
3546 
3547 	tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3548 	if (!HeapTupleIsValid(tup))
3549 		elog(ERROR, "cache lookup failed for type %u", typeOid);
3550 	typform = (Form_pg_type) GETSTRUCT(tup);
3551 
3552 	oldNspOid = typform->typnamespace;
3553 	arrayOid = typform->typarray;
3554 
3555 	/* If the type is already there, we scan skip these next few checks. */
3556 	if (oldNspOid != nspOid)
3557 	{
3558 		/* common checks on switching namespaces */
3559 		CheckSetNamespace(oldNspOid, nspOid);
3560 
3561 		/* check for duplicate name (more friendly than unique-index failure) */
3562 		if (SearchSysCacheExists2(TYPENAMENSP,
3563 								  CStringGetDatum(NameStr(typform->typname)),
3564 								  ObjectIdGetDatum(nspOid)))
3565 			ereport(ERROR,
3566 					(errcode(ERRCODE_DUPLICATE_OBJECT),
3567 					 errmsg("type \"%s\" already exists in schema \"%s\"",
3568 							NameStr(typform->typname),
3569 							get_namespace_name(nspOid))));
3570 	}
3571 
3572 	/* Detect whether type is a composite type (but not a table rowtype) */
3573 	isCompositeType =
3574 		(typform->typtype == TYPTYPE_COMPOSITE &&
3575 		 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3576 
3577 	/* Enforce not-table-type if requested */
3578 	if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3579 		errorOnTableType)
3580 		ereport(ERROR,
3581 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
3582 				 errmsg("%s is a table's row type",
3583 						format_type_be(typeOid)),
3584 				 errhint("Use ALTER TABLE instead.")));
3585 
3586 	if (oldNspOid != nspOid)
3587 	{
3588 		/* OK, modify the pg_type row */
3589 
3590 		/* tup is a copy, so we can scribble directly on it */
3591 		typform->typnamespace = nspOid;
3592 
3593 		simple_heap_update(rel, &tup->t_self, tup);
3594 		CatalogUpdateIndexes(rel, tup);
3595 	}
3596 
3597 	/*
3598 	 * Composite types have pg_class entries.
3599 	 *
3600 	 * We need to modify the pg_class tuple as well to reflect the change of
3601 	 * schema.
3602 	 */
3603 	if (isCompositeType)
3604 	{
3605 		Relation	classRel;
3606 
3607 		classRel = heap_open(RelationRelationId, RowExclusiveLock);
3608 
3609 		AlterRelationNamespaceInternal(classRel, typform->typrelid,
3610 									   oldNspOid, nspOid,
3611 									   false, objsMoved);
3612 
3613 		heap_close(classRel, RowExclusiveLock);
3614 
3615 		/*
3616 		 * Check for constraints associated with the composite type (we don't
3617 		 * currently support this, but probably will someday).
3618 		 */
3619 		AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3620 								  nspOid, false, objsMoved);
3621 	}
3622 	else
3623 	{
3624 		/* If it's a domain, it might have constraints */
3625 		if (typform->typtype == TYPTYPE_DOMAIN)
3626 			AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
3627 									  objsMoved);
3628 	}
3629 
3630 	/*
3631 	 * Update dependency on schema, if any --- a table rowtype has not got
3632 	 * one, and neither does an implicit array.
3633 	 */
3634 	if (oldNspOid != nspOid &&
3635 		(isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3636 		!isImplicitArray)
3637 		if (changeDependencyFor(TypeRelationId, typeOid,
3638 								NamespaceRelationId, oldNspOid, nspOid) != 1)
3639 			elog(ERROR, "failed to change schema dependency for type %s",
3640 				 format_type_be(typeOid));
3641 
3642 	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3643 
3644 	heap_freetuple(tup);
3645 
3646 	heap_close(rel, RowExclusiveLock);
3647 
3648 	add_exact_object_address(&thisobj, objsMoved);
3649 
3650 	/* Recursively alter the associated array type, if any */
3651 	if (OidIsValid(arrayOid))
3652 		AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
3653 
3654 	return oldNspOid;
3655 }
3656