OSDN Git Service

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