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