OSDN Git Service

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