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