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