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