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