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