]> granicus.if.org Git - postgresql/blob - src/backend/commands/typecmds.c
Further code review for range types patch.
[postgresql] / src / backend / commands / typecmds.c
1 /*-------------------------------------------------------------------------
2  *
3  * typecmds.c
4  *        Routines for SQL commands that manipulate types (and domains).
5  *
6  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/commands/typecmds.c
12  *
13  * DESCRIPTION
14  *        The "DefineFoo" routines take the parse tree and pick out the
15  *        appropriate arguments/flags, passing the results to the
16  *        corresponding "FooDefine" routines (in src/catalog) that do
17  *        the actual catalog-munging.  These routines also verify permission
18  *        of the user to execute the command.
19  *
20  * NOTES
21  *        These things must be defined and committed in the following order:
22  *              "create function":
23  *                              input/output, recv/send functions
24  *              "create type":
25  *                              type
26  *              "create operator":
27  *                              operators
28  *
29  *
30  *-------------------------------------------------------------------------
31  */
32 #include "postgres.h"
33
34 #include "access/genam.h"
35 #include "access/heapam.h"
36 #include "access/xact.h"
37 #include "catalog/catalog.h"
38 #include "catalog/dependency.h"
39 #include "catalog/heap.h"
40 #include "catalog/indexing.h"
41 #include "catalog/pg_collation.h"
42 #include "catalog/pg_constraint.h"
43 #include "catalog/pg_depend.h"
44 #include "catalog/pg_enum.h"
45 #include "catalog/pg_language.h"
46 #include "catalog/pg_namespace.h"
47 #include "catalog/pg_proc.h"
48 #include "catalog/pg_proc_fn.h"
49 #include "catalog/pg_range.h"
50 #include "catalog/pg_type.h"
51 #include "catalog/pg_type_fn.h"
52 #include "commands/defrem.h"
53 #include "commands/tablecmds.h"
54 #include "commands/typecmds.h"
55 #include "executor/executor.h"
56 #include "miscadmin.h"
57 #include "nodes/makefuncs.h"
58 #include "optimizer/planner.h"
59 #include "optimizer/var.h"
60 #include "parser/parse_coerce.h"
61 #include "parser/parse_collate.h"
62 #include "parser/parse_expr.h"
63 #include "parser/parse_func.h"
64 #include "parser/parse_type.h"
65 #include "utils/acl.h"
66 #include "utils/builtins.h"
67 #include "utils/fmgroids.h"
68 #include "utils/lsyscache.h"
69 #include "utils/memutils.h"
70 #include "utils/rangetypes.h"
71 #include "utils/rel.h"
72 #include "utils/syscache.h"
73 #include "utils/tqual.h"
74
75
76 /* result structure for get_rels_with_domain() */
77 typedef struct
78 {
79         Relation        rel;                    /* opened and locked relation */
80         int                     natts;                  /* number of attributes of interest */
81         int                *atts;                       /* attribute numbers */
82         /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
83 } RelToCheck;
84
85 /* Potentially set by contrib/pg_upgrade_support functions */
86 Oid                     binary_upgrade_next_array_pg_type_oid = InvalidOid;
87
88 static Oid      findTypeInputFunction(List *procname, Oid typeOid);
89 static Oid      findTypeOutputFunction(List *procname, Oid typeOid);
90 static Oid      findTypeReceiveFunction(List *procname, Oid typeOid);
91 static Oid      findTypeSendFunction(List *procname, Oid typeOid);
92 static Oid      findTypeTypmodinFunction(List *procname);
93 static Oid      findTypeTypmodoutFunction(List *procname);
94 static Oid      findTypeAnalyzeFunction(List *procname, Oid typeOid);
95 static Oid      findRangeCanonicalFunction(List *procname, Oid typeOid);
96 static Oid      findRangeSubOpclass(List *procname, Oid typeOid);
97 static Oid      findRangeSubtypeDiffFunction(List *procname, Oid typeOid);
98 static void validateDomainConstraint(Oid domainoid, char *ccbin);
99 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
100 static void checkDomainOwner(HeapTuple tup);
101 static void checkEnumOwner(HeapTuple tup);
102 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
103                                         Oid baseTypeOid,
104                                         int typMod, Constraint *constr,
105                                         char *domainName);
106 static void makeRangeConstructor(char *name, Oid namespace, Oid rettype,
107                                          Oid subtype);
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                            InvalidOid,          /* analyze procedure - default */
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         /*
761          * Identify the collation if any
762          */
763         baseColl = baseType->typcollation;
764         if (stmt->collClause)
765                 domaincoll = get_collation_oid(stmt->collClause->collname, false);
766         else
767                 domaincoll = baseColl;
768
769         /* Complain if COLLATE is applied to an uncollatable type */
770         if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
771                 ereport(ERROR,
772                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
773                                  errmsg("collations are not supported by type %s",
774                                                 format_type_be(basetypeoid))));
775
776         /* passed by value */
777         byValue = baseType->typbyval;
778
779         /* Required Alignment */
780         alignment = baseType->typalign;
781
782         /* TOAST Strategy */
783         storage = baseType->typstorage;
784
785         /* Storage Length */
786         internalLength = baseType->typlen;
787
788         /* Type Category */
789         category = baseType->typcategory;
790
791         /* Array element Delimiter */
792         delimiter = baseType->typdelim;
793
794         /* I/O Functions */
795         inputProcedure = F_DOMAIN_IN;
796         outputProcedure = baseType->typoutput;
797         receiveProcedure = F_DOMAIN_RECV;
798         sendProcedure = baseType->typsend;
799
800         /* Domains never accept typmods, so no typmodin/typmodout needed */
801
802         /* Analysis function */
803         analyzeProcedure = baseType->typanalyze;
804
805         /* Inherited default value */
806         datum = SysCacheGetAttr(TYPEOID, typeTup,
807                                                         Anum_pg_type_typdefault, &isnull);
808         if (!isnull)
809                 defaultValue = TextDatumGetCString(datum);
810
811         /* Inherited default binary value */
812         datum = SysCacheGetAttr(TYPEOID, typeTup,
813                                                         Anum_pg_type_typdefaultbin, &isnull);
814         if (!isnull)
815                 defaultValueBin = TextDatumGetCString(datum);
816
817         /*
818          * Run through constraints manually to avoid the additional processing
819          * conducted by DefineRelation() and friends.
820          */
821         foreach(listptr, schema)
822         {
823                 Constraint *constr = lfirst(listptr);
824
825                 if (!IsA(constr, Constraint))
826                         elog(ERROR, "unrecognized node type: %d",
827                                  (int) nodeTag(constr));
828                 switch (constr->contype)
829                 {
830                         case CONSTR_DEFAULT:
831
832                                 /*
833                                  * The inherited default value may be overridden by the user
834                                  * with the DEFAULT <expr> clause ... but only once.
835                                  */
836                                 if (saw_default)
837                                         ereport(ERROR,
838                                                         (errcode(ERRCODE_SYNTAX_ERROR),
839                                                          errmsg("multiple default expressions")));
840                                 saw_default = true;
841
842                                 if (constr->raw_expr)
843                                 {
844                                         ParseState *pstate;
845                                         Node       *defaultExpr;
846
847                                         /* Create a dummy ParseState for transformExpr */
848                                         pstate = make_parsestate(NULL);
849
850                                         /*
851                                          * Cook the constr->raw_expr into an expression. Note:
852                                          * name is strictly for error message
853                                          */
854                                         defaultExpr = cookDefault(pstate, constr->raw_expr,
855                                                                                           basetypeoid,
856                                                                                           basetypeMod,
857                                                                                           domainName);
858
859                                         /*
860                                          * If the expression is just a NULL constant, we treat it
861                                          * like not having a default.
862                                          *
863                                          * Note that if the basetype is another domain, we'll see
864                                          * a CoerceToDomain expr here and not discard the default.
865                                          * This is critical because the domain default needs to be
866                                          * retained to override any default that the base domain
867                                          * might have.
868                                          */
869                                         if (defaultExpr == NULL ||
870                                                 (IsA(defaultExpr, Const) &&
871                                                  ((Const *) defaultExpr)->constisnull))
872                                         {
873                                                 defaultValue = NULL;
874                                                 defaultValueBin = NULL;
875                                         }
876                                         else
877                                         {
878                                                 /*
879                                                  * Expression must be stored as a nodeToString result,
880                                                  * but we also require a valid textual representation
881                                                  * (mainly to make life easier for pg_dump).
882                                                  */
883                                                 defaultValue =
884                                                         deparse_expression(defaultExpr,
885                                                                                            deparse_context_for(domainName,
886                                                                                                                                  InvalidOid),
887                                                                                            false, false);
888                                                 defaultValueBin = nodeToString(defaultExpr);
889                                         }
890                                 }
891                                 else
892                                 {
893                                         /* No default (can this still happen?) */
894                                         defaultValue = NULL;
895                                         defaultValueBin = NULL;
896                                 }
897                                 break;
898
899                         case CONSTR_NOTNULL:
900                                 if (nullDefined && !typNotNull)
901                                         ereport(ERROR,
902                                                         (errcode(ERRCODE_SYNTAX_ERROR),
903                                                    errmsg("conflicting NULL/NOT NULL constraints")));
904                                 typNotNull = true;
905                                 nullDefined = true;
906                                 break;
907
908                         case CONSTR_NULL:
909                                 if (nullDefined && typNotNull)
910                                         ereport(ERROR,
911                                                         (errcode(ERRCODE_SYNTAX_ERROR),
912                                                    errmsg("conflicting NULL/NOT NULL constraints")));
913                                 typNotNull = false;
914                                 nullDefined = true;
915                                 break;
916
917                         case CONSTR_CHECK:
918
919                                 /*
920                                  * Check constraints are handled after domain creation, as
921                                  * they require the Oid of the domain
922                                  */
923                                 break;
924
925                                 /*
926                                  * All else are error cases
927                                  */
928                         case CONSTR_UNIQUE:
929                                 ereport(ERROR,
930                                                 (errcode(ERRCODE_SYNTAX_ERROR),
931                                          errmsg("unique constraints not possible for domains")));
932                                 break;
933
934                         case CONSTR_PRIMARY:
935                                 ereport(ERROR,
936                                                 (errcode(ERRCODE_SYNTAX_ERROR),
937                                 errmsg("primary key constraints not possible for domains")));
938                                 break;
939
940                         case CONSTR_EXCLUSION:
941                                 ereport(ERROR,
942                                                 (errcode(ERRCODE_SYNTAX_ERROR),
943                                   errmsg("exclusion constraints not possible for domains")));
944                                 break;
945
946                         case CONSTR_FOREIGN:
947                                 ereport(ERROR,
948                                                 (errcode(ERRCODE_SYNTAX_ERROR),
949                                 errmsg("foreign key constraints not possible for domains")));
950                                 break;
951
952                         case CONSTR_ATTR_DEFERRABLE:
953                         case CONSTR_ATTR_NOT_DEFERRABLE:
954                         case CONSTR_ATTR_DEFERRED:
955                         case CONSTR_ATTR_IMMEDIATE:
956                                 ereport(ERROR,
957                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
958                                                  errmsg("specifying constraint deferrability not supported for domains")));
959                                 break;
960
961                         default:
962                                 elog(ERROR, "unrecognized constraint subtype: %d",
963                                          (int) constr->contype);
964                                 break;
965                 }
966         }
967
968         /*
969          * Have TypeCreate do all the real work.
970          */
971         domainoid =
972                 TypeCreate(InvalidOid,  /* no predetermined type OID */
973                                    domainName,  /* type name */
974                                    domainNamespace,             /* namespace */
975                                    InvalidOid,  /* relation oid (n/a here) */
976                                    0,                   /* relation kind (ditto) */
977                                    GetUserId(), /* owner's ID */
978                                    internalLength,              /* internal size */
979                                    TYPTYPE_DOMAIN,              /* type-type (domain type) */
980                                    category,    /* type-category */
981                                    false,               /* domain types are never preferred */
982                                    delimiter,   /* array element delimiter */
983                                    inputProcedure,              /* input procedure */
984                                    outputProcedure,             /* output procedure */
985                                    receiveProcedure,    /* receive procedure */
986                                    sendProcedure,               /* send procedure */
987                                    InvalidOid,  /* typmodin procedure - none */
988                                    InvalidOid,  /* typmodout procedure - none */
989                                    analyzeProcedure,    /* analyze procedure */
990                                    InvalidOid,  /* no array element type */
991                                    false,               /* this isn't an array */
992                                    InvalidOid,  /* no arrays for domains (yet) */
993                                    basetypeoid, /* base type ID */
994                                    defaultValue,        /* default type value (text) */
995                                    defaultValueBin,             /* default type value (binary) */
996                                    byValue,             /* passed by value */
997                                    alignment,   /* required alignment */
998                                    storage,             /* TOAST strategy */
999                                    basetypeMod, /* typeMod value */
1000                                    typNDims,    /* Array dimensions for base type */
1001                                    typNotNull,  /* Type NOT NULL */
1002                                    domaincoll); /* type's collation */
1003
1004         /*
1005          * Process constraints which refer to the domain ID returned by TypeCreate
1006          */
1007         foreach(listptr, schema)
1008         {
1009                 Constraint *constr = lfirst(listptr);
1010
1011                 /* it must be a Constraint, per check above */
1012
1013                 switch (constr->contype)
1014                 {
1015                         case CONSTR_CHECK:
1016                                 domainAddConstraint(domainoid, domainNamespace,
1017                                                                         basetypeoid, basetypeMod,
1018                                                                         constr, domainName);
1019                                 break;
1020
1021                                 /* Other constraint types were fully processed above */
1022
1023                         default:
1024                                 break;
1025                 }
1026
1027                 /* CCI so we can detect duplicate constraint names */
1028                 CommandCounterIncrement();
1029         }
1030
1031         /*
1032          * Now we can clean up.
1033          */
1034         ReleaseSysCache(typeTup);
1035 }
1036
1037
1038 /*
1039  * DefineEnum
1040  *              Registers a new enum.
1041  */
1042 void
1043 DefineEnum(CreateEnumStmt *stmt)
1044 {
1045         char       *enumName;
1046         char       *enumArrayName;
1047         Oid                     enumNamespace;
1048         Oid                     enumTypeOid;
1049         AclResult       aclresult;
1050         Oid                     old_type_oid;
1051         Oid                     enumArrayOid;
1052
1053         /* Convert list of names to a name and namespace */
1054         enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1055                                                                                                           &enumName);
1056
1057         /* Check we have creation rights in target namespace */
1058         aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1059         if (aclresult != ACLCHECK_OK)
1060                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1061                                            get_namespace_name(enumNamespace));
1062
1063         /*
1064          * Check for collision with an existing type name.      If there is one and
1065          * it's an autogenerated array, we can rename it out of the way.
1066          */
1067         old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1068                                                                    CStringGetDatum(enumName),
1069                                                                    ObjectIdGetDatum(enumNamespace));
1070         if (OidIsValid(old_type_oid))
1071         {
1072                 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1073                         ereport(ERROR,
1074                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
1075                                          errmsg("type \"%s\" already exists", enumName)));
1076         }
1077
1078         enumArrayOid = AssignTypeArrayOid();
1079
1080         /* Create the pg_type entry */
1081         enumTypeOid =
1082                 TypeCreate(InvalidOid,  /* no predetermined type OID */
1083                                    enumName,    /* type name */
1084                                    enumNamespace,               /* namespace */
1085                                    InvalidOid,  /* relation oid (n/a here) */
1086                                    0,                   /* relation kind (ditto) */
1087                                    GetUserId(), /* owner's ID */
1088                                    sizeof(Oid), /* internal size */
1089                                    TYPTYPE_ENUM,        /* type-type (enum type) */
1090                                    TYPCATEGORY_ENUM,    /* type-category (enum type) */
1091                                    false,               /* enum types are never preferred */
1092                                    DEFAULT_TYPDELIM,    /* array element delimiter */
1093                                    F_ENUM_IN,   /* input procedure */
1094                                    F_ENUM_OUT,  /* output procedure */
1095                                    F_ENUM_RECV, /* receive procedure */
1096                                    F_ENUM_SEND, /* send procedure */
1097                                    InvalidOid,  /* typmodin procedure - none */
1098                                    InvalidOid,  /* typmodout procedure - none */
1099                                    InvalidOid,  /* analyze procedure - default */
1100                                    InvalidOid,  /* element type ID */
1101                                    false,               /* this is not an array type */
1102                                    enumArrayOid,        /* array type we are about to create */
1103                                    InvalidOid,  /* base type ID (only for domains) */
1104                                    NULL,                /* never a default type value */
1105                                    NULL,                /* binary default isn't sent either */
1106                                    true,                /* always passed by value */
1107                                    'i',                 /* int alignment */
1108                                    'p',                 /* TOAST strategy always plain */
1109                                    -1,                  /* typMod (Domains only) */
1110                                    0,                   /* Array dimensions of typbasetype */
1111                                    false,               /* Type NOT NULL */
1112                                    InvalidOid); /* type's collation */
1113
1114         /* Enter the enum's values into pg_enum */
1115         EnumValuesCreate(enumTypeOid, stmt->vals);
1116
1117         /*
1118          * Create the array type that goes with it.
1119          */
1120         enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1121
1122         TypeCreate(enumArrayOid,        /* force assignment of this type OID */
1123                            enumArrayName,       /* type name */
1124                            enumNamespace,       /* namespace */
1125                            InvalidOid,          /* relation oid (n/a here) */
1126                            0,                           /* relation kind (ditto) */
1127                            GetUserId(),         /* owner's ID */
1128                            -1,                          /* internal size (always varlena) */
1129                            TYPTYPE_BASE,        /* type-type (base type) */
1130                            TYPCATEGORY_ARRAY,           /* type-category (array) */
1131                            false,                       /* array types are never preferred */
1132                            DEFAULT_TYPDELIM,    /* array element delimiter */
1133                            F_ARRAY_IN,          /* input procedure */
1134                            F_ARRAY_OUT,         /* output procedure */
1135                            F_ARRAY_RECV,        /* receive procedure */
1136                            F_ARRAY_SEND,        /* send procedure */
1137                            InvalidOid,          /* typmodin procedure - none */
1138                            InvalidOid,          /* typmodout procedure - none */
1139                            InvalidOid,          /* analyze procedure - default */
1140                            enumTypeOid,         /* element type ID */
1141                            true,                        /* yes this is an array type */
1142                            InvalidOid,          /* no further array type */
1143                            InvalidOid,          /* base type ID */
1144                            NULL,                        /* never a default type value */
1145                            NULL,                        /* binary default isn't sent either */
1146                            false,                       /* never passed by value */
1147                            'i',                         /* enums have align i, so do their arrays */
1148                            'x',                         /* ARRAY is always toastable */
1149                            -1,                          /* typMod (Domains only) */
1150                            0,                           /* Array dimensions of typbasetype */
1151                            false,                       /* Type NOT NULL */
1152                            InvalidOid);         /* type's collation */
1153
1154         pfree(enumArrayName);
1155 }
1156
1157 /*
1158  * DefineRange
1159  *              Registers a new range type.
1160  */
1161 void
1162 DefineRange(CreateRangeStmt *stmt)
1163 {
1164         char       *typeName;
1165         char       *rangeArrayName;
1166         Oid                     typeNamespace;
1167         Oid                     typoid;
1168         Oid                     rangeArrayOid;
1169         List       *parameters = stmt->params;
1170         List       *rangeSubOpclassName = NIL;
1171         List       *rangeSubtypeDiffName = NIL;
1172         List       *rangeCollationName = NIL;
1173         Oid                     rangeCollation = InvalidOid;
1174         regproc         rangeAnalyze = InvalidOid;
1175         Oid                     rangeSubtype = InvalidOid;
1176         regproc         rangeSubOpclass = InvalidOid;
1177         regproc         rangeCanonical = InvalidOid;
1178         regproc         rangeSubtypeDiff = InvalidOid;
1179         int16           subtyplen;
1180         bool            subtypbyval;
1181         char            subtypalign;
1182         char            alignment;
1183         AclResult       aclresult;
1184         ListCell   *lc;
1185
1186         /* Convert list of names to a name and namespace */
1187         typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1188                                                                                                           &typeName);
1189
1190         /* Check we have creation rights in target namespace */
1191         aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1192         if (aclresult != ACLCHECK_OK)
1193                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
1194                                            get_namespace_name(typeNamespace));
1195
1196         /*
1197          * Look to see if type already exists (presumably as a shell; if not,
1198          * TypeCreate will complain).
1199          */
1200         typoid = GetSysCacheOid2(TYPENAMENSP,
1201                                                          CStringGetDatum(typeName),
1202                                                          ObjectIdGetDatum(typeNamespace));
1203
1204         /*
1205          * If it's not a shell, see if it's an autogenerated array type, and if so
1206          * rename it out of the way.
1207          */
1208         if (OidIsValid(typoid) && get_typisdefined(typoid))
1209         {
1210                 if (moveArrayTypeName(typoid, typeName, typeNamespace))
1211                         typoid = InvalidOid;
1212         }
1213
1214         /*
1215          * If it doesn't exist, create it as a shell, so that the OID is known for
1216          * use in the I/O function definitions.
1217          */
1218         if (!OidIsValid(typoid))
1219         {
1220                 typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
1221                 /* Make new shell type visible for modification below */
1222                 CommandCounterIncrement();
1223
1224                 /*
1225                  * If the command was a parameterless CREATE TYPE, we're done ---
1226                  * creating the shell type was all we're supposed to do.
1227                  */
1228                 if (parameters == NIL)
1229                         return;
1230         }
1231         else
1232         {
1233                 /* Complain if dummy CREATE TYPE and entry already exists */
1234                 if (parameters == NIL)
1235                         ereport(ERROR,
1236                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
1237                                          errmsg("type \"%s\" already exists", typeName)));
1238         }
1239
1240         foreach(lc, stmt->params)
1241         {
1242                 DefElem    *defel = lfirst(lc);
1243
1244                 if (pg_strcasecmp(defel->defname, "subtype") == 0)
1245                 {
1246                         if (OidIsValid(rangeSubtype))
1247                                 ereport(ERROR,
1248                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1249                                                  errmsg("conflicting or redundant options")));
1250                         rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1251                 }
1252                 else if (pg_strcasecmp(defel->defname, "canonical") == 0)
1253                 {
1254                         if (OidIsValid(rangeCanonical))
1255                                 ereport(ERROR,
1256                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1257                                                  errmsg("conflicting or redundant options")));
1258                         rangeCanonical = findRangeCanonicalFunction(
1259                                                                                  defGetQualifiedName(defel), typoid);
1260                 }
1261                 else if (pg_strcasecmp(defel->defname, "collation") == 0)
1262                 {
1263                         if (rangeCollationName != NIL)
1264                                 ereport(ERROR,
1265                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1266                                                  errmsg("conflicting or redundant options")));
1267                         rangeCollationName = defGetQualifiedName(defel);
1268                 }
1269                 else if (pg_strcasecmp(defel->defname, "analyze") == 0)
1270                 {
1271                         if (OidIsValid(rangeAnalyze))
1272                                 ereport(ERROR,
1273                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1274                                                  errmsg("conflicting or redundant options")));
1275                         rangeAnalyze = findTypeAnalyzeFunction(defGetQualifiedName(defel),
1276                                                                                                    typoid);
1277                 }
1278                 else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
1279                 {
1280                         if (rangeSubOpclassName != NIL)
1281                                 ereport(ERROR,
1282                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1283                                                  errmsg("conflicting or redundant options")));
1284                         rangeSubOpclassName = defGetQualifiedName(defel);
1285                 }
1286                 else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
1287                 {
1288                         if (rangeSubtypeDiffName != NIL)
1289                                 ereport(ERROR,
1290                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1291                                                  errmsg("conflicting or redundant options")));
1292                         rangeSubtypeDiffName = defGetQualifiedName(defel);
1293                 }
1294                 else
1295                 {
1296                         ereport(ERROR,
1297                                         (errcode(ERRCODE_SYNTAX_ERROR),
1298                                          errmsg("type attribute \"%s\" not recognized",
1299                                                         defel->defname)));
1300                         continue;
1301                 }
1302         }
1303
1304         if (!OidIsValid(rangeSubtype))
1305                 ereport(ERROR,
1306                                 (errcode(ERRCODE_SYNTAX_ERROR),
1307                                  errmsg("type attribute \"subtype\" is required")));
1308
1309         if (type_is_collatable(rangeSubtype))
1310         {
1311                 if (rangeCollationName == NIL)
1312                         rangeCollation = get_typcollation(rangeSubtype);
1313                 else
1314                         rangeCollation = get_collation_oid(rangeCollationName, false);
1315         }
1316         else if (rangeCollationName != NIL)
1317                 ereport(ERROR,
1318                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1319                                  errmsg("range collation specified but subtype does not support collation")));
1320
1321         rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1322
1323         if (rangeSubtypeDiffName != NIL)
1324                 rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1325                                                                                                                 rangeSubtype);
1326
1327         get_typlenbyvalalign(rangeSubtype,
1328                                                  &subtyplen, &subtypbyval, &subtypalign);
1329
1330         /* alignment must be 'i' or 'd' for ranges */
1331         alignment = (subtypalign == 'd') ? 'd' : 'i';
1332
1333         /* Allocate OID for array type */
1334         rangeArrayOid = AssignTypeArrayOid();
1335
1336         /* Create the pg_type entry */
1337         typoid =
1338                 TypeCreate(InvalidOid,  /* no predetermined type OID */
1339                                    typeName,    /* type name */
1340                                    typeNamespace,               /* namespace */
1341                                    InvalidOid,  /* relation oid (n/a here) */
1342                                    0,                   /* relation kind (ditto) */
1343                                    GetUserId(), /* owner's ID */
1344                                    -1,                  /* internal size (always varlena) */
1345                                    TYPTYPE_RANGE,               /* type-type (range type) */
1346                                    TYPCATEGORY_RANGE,   /* type-category (range type) */
1347                                    false,               /* range types are never preferred */
1348                                    DEFAULT_TYPDELIM,    /* array element delimiter */
1349                                    F_RANGE_IN,  /* input procedure */
1350                                    F_RANGE_OUT, /* output procedure */
1351                                    F_RANGE_RECV,        /* receive procedure */
1352                                    F_RANGE_SEND,        /* send procedure */
1353                                    InvalidOid,  /* typmodin procedure - none */
1354                                    InvalidOid,  /* typmodout procedure - none */
1355                                    rangeAnalyze,        /* analyze procedure */
1356                                    InvalidOid,  /* element type ID - none */
1357                                    false,               /* this is not an array type */
1358                                    rangeArrayOid,               /* array type we are about to create */
1359                                    InvalidOid,  /* base type ID (only for domains) */
1360                                    NULL,                /* never a default type value */
1361                                    NULL,                /* binary default isn't sent either */
1362                                    false,               /* never passed by value */
1363                                    alignment,   /* alignment */
1364                                    'x',                 /* TOAST strategy (always extended) */
1365                                    -1,                  /* typMod (Domains only) */
1366                                    0,                   /* Array dimensions of typbasetype */
1367                                    false,               /* Type NOT NULL */
1368                                    InvalidOid); /* typcollation */
1369
1370         /* create the entry in pg_range */
1371         RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1372                                 rangeCanonical, rangeSubtypeDiff);
1373
1374         /*
1375          * Create the array type that goes with it.
1376          */
1377         rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1378
1379         TypeCreate(rangeArrayOid,       /* force assignment of this type OID */
1380                            rangeArrayName,      /* type name */
1381                            typeNamespace,       /* namespace */
1382                            InvalidOid,          /* relation oid (n/a here) */
1383                            0,                           /* relation kind (ditto) */
1384                            GetUserId(),         /* owner's ID */
1385                            -1,                          /* internal size (always varlena) */
1386                            TYPTYPE_BASE,        /* type-type (base type) */
1387                            TYPCATEGORY_ARRAY,           /* type-category (array) */
1388                            false,                       /* array types are never preferred */
1389                            DEFAULT_TYPDELIM,    /* array element delimiter */
1390                            F_ARRAY_IN,          /* input procedure */
1391                            F_ARRAY_OUT,         /* output procedure */
1392                            F_ARRAY_RECV,        /* receive procedure */
1393                            F_ARRAY_SEND,        /* send procedure */
1394                            InvalidOid,          /* typmodin procedure - none */
1395                            InvalidOid,          /* typmodout procedure - none */
1396                            InvalidOid,          /* analyze procedure - default */
1397                            typoid,                      /* element type ID */
1398                            true,                        /* yes this is an array type */
1399                            InvalidOid,          /* no further array type */
1400                            InvalidOid,          /* base type ID */
1401                            NULL,                        /* never a default type value */
1402                            NULL,                        /* binary default isn't sent either */
1403                            false,                       /* never passed by value */
1404                            alignment,           /* alignment - same as range's */
1405                            'x',                         /* ARRAY is always toastable */
1406                            -1,                          /* typMod (Domains only) */
1407                            0,                           /* Array dimensions of typbasetype */
1408                            false,                       /* Type NOT NULL */
1409                            InvalidOid);         /* typcollation */
1410
1411         pfree(rangeArrayName);
1412
1413         /* And create the constructor functions for this range type */
1414         makeRangeConstructor(typeName, typeNamespace, typoid, rangeSubtype);
1415 }
1416
1417 /*
1418  * Because there may exist several range types over one subtype, the range type
1419  * can't be determined from the subtype. This means that constructors can't be
1420  * polymorphic, and so we must generate a new constructor for every range type
1421  * defined.
1422  *
1423  * We actually define 4 functions with 0 through 3 arguments. This is just to
1424  * offer more convenience for the user.
1425  */
1426 static void
1427 makeRangeConstructor(char *name, Oid namespace, Oid rangeOid, Oid subtype)
1428 {
1429         ObjectAddress referenced;
1430         Oid                     constructorArgTypes[3];
1431         int                     i;
1432
1433         referenced.classId = TypeRelationId;
1434         referenced.objectId = rangeOid;
1435         referenced.objectSubId = 0;
1436
1437         constructorArgTypes[0] = subtype;
1438         constructorArgTypes[1] = subtype;
1439         constructorArgTypes[2] = TEXTOID;
1440
1441         for (i = 0; i < 4; i++)
1442         {
1443                 oidvector  *constructorArgTypesVector;
1444                 ObjectAddress myself;
1445                 Oid                     procOid;
1446                 char       *prosrc[4] = {"range_constructor0",
1447                         "range_constructor1",
1448                         "range_constructor2",
1449                 "range_constructor3"};
1450
1451                 constructorArgTypesVector = buildoidvector(constructorArgTypes, i);
1452
1453                 procOid = ProcedureCreate(
1454                                                                   name, /* name */
1455                                                                   namespace,    /* namespace */
1456                                                                   false,                /* replace */
1457                                                                   false,                /* return set */
1458                                                                   rangeOid,             /* return type */
1459                                                                   INTERNALlanguageId,   /* language */
1460                                                                   F_FMGR_INTERNAL_VALIDATOR,    /* language validator */
1461                                                                   prosrc[i],    /* prosrc */
1462                                                                   NULL, /* probin */
1463                                                                   false,                /* agg */
1464                                                                   false,                /* window */
1465                                                                   false,                /* security definer */
1466                                                                   false,                /* strict */
1467                                                                   PROVOLATILE_IMMUTABLE,                /* volatility */
1468                                                                   constructorArgTypesVector,    /* param types */
1469                                                                   PointerGetDatum(NULL),                /* allParameterTypes */
1470                                                                   PointerGetDatum(NULL),                /* parameterModes */
1471                                                                   PointerGetDatum(NULL),                /* parameterNames */
1472                                                                   NIL,  /* parameterDefaults */
1473                                                                   PointerGetDatum(NULL),                /* proconfig */
1474                                                                   1.0,  /* procost */
1475                                                                   0.0); /* prorows */
1476
1477                 /*
1478                  * Make the constructors internally-dependent on the range type so
1479                  * that they go away silently when the type is dropped.  Note that
1480                  * pg_dump depends on this choice to avoid dumping the constructors.
1481                  */
1482                 myself.classId = ProcedureRelationId;
1483                 myself.objectId = procOid;
1484                 myself.objectSubId = 0;
1485                 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1486         }
1487 }
1488
1489 /*
1490  * AlterEnum
1491  *              Adds a new label to an existing enum.
1492  */
1493 void
1494 AlterEnum(AlterEnumStmt *stmt)
1495 {
1496         Oid                     enum_type_oid;
1497         TypeName   *typename;
1498         HeapTuple       tup;
1499
1500         /* Make a TypeName so we can use standard type lookup machinery */
1501         typename = makeTypeNameFromNameList(stmt->typeName);
1502         enum_type_oid = typenameTypeId(NULL, typename);
1503
1504         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1505         if (!HeapTupleIsValid(tup))
1506                 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1507
1508         /* Check it's an enum and check user has permission to ALTER the enum */
1509         checkEnumOwner(tup);
1510
1511         /* Add the new label */
1512         AddEnumLabel(enum_type_oid, stmt->newVal,
1513                                  stmt->newValNeighbor, stmt->newValIsAfter);
1514
1515         ReleaseSysCache(tup);
1516 }
1517
1518
1519 /*
1520  * checkEnumOwner
1521  *
1522  * Check that the type is actually an enum and that the current user
1523  * has permission to do ALTER TYPE on it.  Throw an error if not.
1524  */
1525 static void
1526 checkEnumOwner(HeapTuple tup)
1527 {
1528         Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1529
1530         /* Check that this is actually an enum */
1531         if (typTup->typtype != TYPTYPE_ENUM)
1532                 ereport(ERROR,
1533                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1534                                  errmsg("%s is not an enum",
1535                                                 format_type_be(HeapTupleGetOid(tup)))));
1536
1537         /* Permission check: must own type */
1538         if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1539                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1540                                            format_type_be(HeapTupleGetOid(tup)));
1541 }
1542
1543
1544 /*
1545  * Find suitable I/O functions for a type.
1546  *
1547  * typeOid is the type's OID (which will already exist, if only as a shell
1548  * type).
1549  */
1550
1551 static Oid
1552 findTypeInputFunction(List *procname, Oid typeOid)
1553 {
1554         Oid                     argList[3];
1555         Oid                     procOid;
1556
1557         /*
1558          * Input functions can take a single argument of type CSTRING, or three
1559          * arguments (string, typioparam OID, typmod).
1560          *
1561          * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1562          * see this, we issue a warning and fix up the pg_proc entry.
1563          */
1564         argList[0] = CSTRINGOID;
1565
1566         procOid = LookupFuncName(procname, 1, argList, true);
1567         if (OidIsValid(procOid))
1568                 return procOid;
1569
1570         argList[1] = OIDOID;
1571         argList[2] = INT4OID;
1572
1573         procOid = LookupFuncName(procname, 3, argList, true);
1574         if (OidIsValid(procOid))
1575                 return procOid;
1576
1577         /* No luck, try it with OPAQUE */
1578         argList[0] = OPAQUEOID;
1579
1580         procOid = LookupFuncName(procname, 1, argList, true);
1581
1582         if (!OidIsValid(procOid))
1583         {
1584                 argList[1] = OIDOID;
1585                 argList[2] = INT4OID;
1586
1587                 procOid = LookupFuncName(procname, 3, argList, true);
1588         }
1589
1590         if (OidIsValid(procOid))
1591         {
1592                 /* Found, but must complain and fix the pg_proc entry */
1593                 ereport(WARNING,
1594                                 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1595                                                 NameListToString(procname))));
1596                 SetFunctionArgType(procOid, 0, CSTRINGOID);
1597
1598                 /*
1599                  * Need CommandCounterIncrement since DefineType will likely try to
1600                  * alter the pg_proc tuple again.
1601                  */
1602                 CommandCounterIncrement();
1603
1604                 return procOid;
1605         }
1606
1607         /* Use CSTRING (preferred) in the error message */
1608         argList[0] = CSTRINGOID;
1609
1610         ereport(ERROR,
1611                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
1612                          errmsg("function %s does not exist",
1613                                         func_signature_string(procname, 1, NIL, argList))));
1614
1615         return InvalidOid;                      /* keep compiler quiet */
1616 }
1617
1618 static Oid
1619 findTypeOutputFunction(List *procname, Oid typeOid)
1620 {
1621         Oid                     argList[1];
1622         Oid                     procOid;
1623
1624         /*
1625          * Output functions can take a single argument of the type.
1626          *
1627          * For backwards compatibility we allow OPAQUE in place of the actual type
1628          * name; if we see this, we issue a warning and fix up the pg_proc entry.
1629          */
1630         argList[0] = typeOid;
1631
1632         procOid = LookupFuncName(procname, 1, argList, true);
1633         if (OidIsValid(procOid))
1634                 return procOid;
1635
1636         /* No luck, try it with OPAQUE */
1637         argList[0] = OPAQUEOID;
1638
1639         procOid = LookupFuncName(procname, 1, argList, true);
1640
1641         if (OidIsValid(procOid))
1642         {
1643                 /* Found, but must complain and fix the pg_proc entry */
1644                 ereport(WARNING,
1645                 (errmsg("changing argument type of function %s from \"opaque\" to %s",
1646                                 NameListToString(procname), format_type_be(typeOid))));
1647                 SetFunctionArgType(procOid, 0, typeOid);
1648
1649                 /*
1650                  * Need CommandCounterIncrement since DefineType will likely try to
1651                  * alter the pg_proc tuple again.
1652                  */
1653                 CommandCounterIncrement();
1654
1655                 return procOid;
1656         }
1657
1658         /* Use type name, not OPAQUE, in the failure message. */
1659         argList[0] = typeOid;
1660
1661         ereport(ERROR,
1662                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
1663                          errmsg("function %s does not exist",
1664                                         func_signature_string(procname, 1, NIL, argList))));
1665
1666         return InvalidOid;                      /* keep compiler quiet */
1667 }
1668
1669 static Oid
1670 findTypeReceiveFunction(List *procname, Oid typeOid)
1671 {
1672         Oid                     argList[3];
1673         Oid                     procOid;
1674
1675         /*
1676          * Receive functions can take a single argument of type INTERNAL, or three
1677          * arguments (internal, typioparam OID, typmod).
1678          */
1679         argList[0] = INTERNALOID;
1680
1681         procOid = LookupFuncName(procname, 1, argList, true);
1682         if (OidIsValid(procOid))
1683                 return procOid;
1684
1685         argList[1] = OIDOID;
1686         argList[2] = INT4OID;
1687
1688         procOid = LookupFuncName(procname, 3, argList, true);
1689         if (OidIsValid(procOid))
1690                 return procOid;
1691
1692         ereport(ERROR,
1693                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
1694                          errmsg("function %s does not exist",
1695                                         func_signature_string(procname, 1, NIL, argList))));
1696
1697         return InvalidOid;                      /* keep compiler quiet */
1698 }
1699
1700 static Oid
1701 findTypeSendFunction(List *procname, Oid typeOid)
1702 {
1703         Oid                     argList[1];
1704         Oid                     procOid;
1705
1706         /*
1707          * Send functions can take a single argument of the type.
1708          */
1709         argList[0] = typeOid;
1710
1711         procOid = LookupFuncName(procname, 1, argList, true);
1712         if (OidIsValid(procOid))
1713                 return procOid;
1714
1715         ereport(ERROR,
1716                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
1717                          errmsg("function %s does not exist",
1718                                         func_signature_string(procname, 1, NIL, argList))));
1719
1720         return InvalidOid;                      /* keep compiler quiet */
1721 }
1722
1723 static Oid
1724 findTypeTypmodinFunction(List *procname)
1725 {
1726         Oid                     argList[1];
1727         Oid                     procOid;
1728
1729         /*
1730          * typmodin functions always take one cstring[] argument and return int4.
1731          */
1732         argList[0] = CSTRINGARRAYOID;
1733
1734         procOid = LookupFuncName(procname, 1, argList, true);
1735         if (!OidIsValid(procOid))
1736                 ereport(ERROR,
1737                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1738                                  errmsg("function %s does not exist",
1739                                                 func_signature_string(procname, 1, NIL, argList))));
1740
1741         if (get_func_rettype(procOid) != INT4OID)
1742                 ereport(ERROR,
1743                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1744                                  errmsg("typmod_in function %s must return type \"integer\"",
1745                                                 NameListToString(procname))));
1746
1747         return procOid;
1748 }
1749
1750 static Oid
1751 findTypeTypmodoutFunction(List *procname)
1752 {
1753         Oid                     argList[1];
1754         Oid                     procOid;
1755
1756         /*
1757          * typmodout functions always take one int4 argument and return cstring.
1758          */
1759         argList[0] = INT4OID;
1760
1761         procOid = LookupFuncName(procname, 1, argList, true);
1762         if (!OidIsValid(procOid))
1763                 ereport(ERROR,
1764                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1765                                  errmsg("function %s does not exist",
1766                                                 func_signature_string(procname, 1, NIL, argList))));
1767
1768         if (get_func_rettype(procOid) != CSTRINGOID)
1769                 ereport(ERROR,
1770                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1771                                  errmsg("typmod_out function %s must return type \"cstring\"",
1772                                                 NameListToString(procname))));
1773
1774         return procOid;
1775 }
1776
1777 static Oid
1778 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1779 {
1780         Oid                     argList[1];
1781         Oid                     procOid;
1782
1783         /*
1784          * Analyze functions always take one INTERNAL argument and return bool.
1785          */
1786         argList[0] = INTERNALOID;
1787
1788         procOid = LookupFuncName(procname, 1, argList, true);
1789         if (!OidIsValid(procOid))
1790                 ereport(ERROR,
1791                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1792                                  errmsg("function %s does not exist",
1793                                                 func_signature_string(procname, 1, NIL, argList))));
1794
1795         if (get_func_rettype(procOid) != BOOLOID)
1796                 ereport(ERROR,
1797                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1798                           errmsg("type analyze function %s must return type \"boolean\"",
1799                                          NameListToString(procname))));
1800
1801         return procOid;
1802 }
1803
1804 /*
1805  * Find named btree opclass for subtype, or default btree opclass if
1806  * opcname is NIL. This will be used for comparing values of subtype.
1807  */
1808 static Oid
1809 findRangeSubOpclass(List *opcname, Oid subtype)
1810 {
1811         Oid                     opcid;
1812
1813         if (opcname == NIL)
1814         {
1815                 opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1816                 if (!OidIsValid(opcid))
1817                 {
1818                         ereport(ERROR,
1819                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
1820                                          errmsg("data type %s has no default operator class for access method \"btree\"",
1821                                                         format_type_be(subtype)),
1822                                          errhint("You must specify an operator class for the data type or define a default operator class for the data type.")));
1823                 }
1824                 return opcid;
1825         }
1826
1827         opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1828
1829         return opcid;
1830 }
1831
1832 /*
1833  * Used to find a range's 'canonical' function.
1834  */
1835 static Oid
1836 findRangeSubtypeDiffFunction(List *procname, Oid typeOid)
1837 {
1838         Oid                     argList[2];
1839         Oid                     procOid;
1840
1841         argList[0] = typeOid;
1842         argList[1] = typeOid;
1843
1844         procOid = LookupFuncName(procname, 2, argList, true);
1845
1846         if (!OidIsValid(procOid))
1847                 ereport(ERROR,
1848                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1849                                  errmsg("function %s does not exist",
1850                                                 func_signature_string(procname, 2, NIL, argList))));
1851
1852         if (get_func_rettype(procOid) != FLOAT8OID)
1853                 ereport(ERROR,
1854                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1855                  errmsg("range subtype diff function %s must return type \"float8\"",
1856                                 func_signature_string(procname, 2, NIL, argList))));
1857
1858         if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1859                 ereport(ERROR,
1860                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1861                                  errmsg("range subtype diff function %s must be immutable",
1862                                                 func_signature_string(procname, 2, NIL, argList))));
1863
1864         return procOid;
1865 }
1866
1867 /*
1868  * Used to find a range's 'canonical' function.
1869  */
1870 static Oid
1871 findRangeCanonicalFunction(List *procname, Oid typeOid)
1872 {
1873         Oid                     argList[1];
1874         Oid                     procOid;
1875
1876         argList[0] = typeOid;
1877
1878         procOid = LookupFuncName(procname, 1, argList, true);
1879
1880         if (!OidIsValid(procOid))
1881                 ereport(ERROR,
1882                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1883                                  errmsg("function %s does not exist",
1884                                                 func_signature_string(procname, 1, NIL, argList))));
1885
1886         if (get_func_rettype(procOid) != typeOid)
1887                 ereport(ERROR,
1888                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1889                                  errmsg("range canonical function %s must return range type",
1890                                                 NameListToString(procname))));
1891
1892         if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1893                 ereport(ERROR,
1894                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1895                                  errmsg("range canonical function %s must be immutable",
1896                                                 func_signature_string(procname, 1, NIL, argList))));
1897
1898         return procOid;
1899 }
1900
1901 /*
1902  *      AssignTypeArrayOid
1903  *
1904  *      Pre-assign the type's array OID for use in pg_type.typarray
1905  */
1906 Oid
1907 AssignTypeArrayOid(void)
1908 {
1909         Oid                     type_array_oid;
1910
1911         /* Use binary-upgrade override for pg_type.typarray, if supplied. */
1912         if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid))
1913         {
1914                 type_array_oid = binary_upgrade_next_array_pg_type_oid;
1915                 binary_upgrade_next_array_pg_type_oid = InvalidOid;
1916         }
1917         else
1918         {
1919                 Relation        pg_type = heap_open(TypeRelationId, AccessShareLock);
1920
1921                 type_array_oid = GetNewOid(pg_type);
1922                 heap_close(pg_type, AccessShareLock);
1923         }
1924
1925         return type_array_oid;
1926 }
1927
1928
1929 /*-------------------------------------------------------------------
1930  * DefineCompositeType
1931  *
1932  * Create a Composite Type relation.
1933  * `DefineRelation' does all the work, we just provide the correct
1934  * arguments!
1935  *
1936  * If the relation already exists, then 'DefineRelation' will abort
1937  * the xact...
1938  *
1939  * DefineCompositeType returns relid for use when creating
1940  * an implicit composite type during function creation
1941  *-------------------------------------------------------------------
1942  */
1943 Oid
1944 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1945 {
1946         CreateStmt *createStmt = makeNode(CreateStmt);
1947         Oid                     old_type_oid;
1948         Oid                     typeNamespace;
1949         Oid                     relid;
1950
1951         /*
1952          * now set the parameters for keys/inheritance etc. All of these are
1953          * uninteresting for composite types...
1954          */
1955         createStmt->relation = (RangeVar *) typevar;
1956         createStmt->tableElts = coldeflist;
1957         createStmt->inhRelations = NIL;
1958         createStmt->constraints = NIL;
1959         createStmt->options = list_make1(defWithOids(false));
1960         createStmt->oncommit = ONCOMMIT_NOOP;
1961         createStmt->tablespacename = NULL;
1962         createStmt->if_not_exists = false;
1963
1964         /*
1965          * Check for collision with an existing type name. If there is one and
1966          * it's an autogenerated array, we can rename it out of the way.  This
1967          * check is here mainly to get a better error message about a "type"
1968          * instead of below about a "relation".
1969          */
1970         typeNamespace = RangeVarGetCreationNamespace(createStmt->relation);
1971         RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
1972         old_type_oid =
1973                 GetSysCacheOid2(TYPENAMENSP,
1974                                                 CStringGetDatum(createStmt->relation->relname),
1975                                                 ObjectIdGetDatum(typeNamespace));
1976         if (OidIsValid(old_type_oid))
1977         {
1978                 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
1979                         ereport(ERROR,
1980                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
1981                                          errmsg("type \"%s\" already exists", createStmt->relation->relname)));
1982         }
1983
1984         /*
1985          * Finally create the relation.  This also creates the type.
1986          */
1987         relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
1988         Assert(relid != InvalidOid);
1989         return relid;
1990 }
1991
1992 /*
1993  * AlterDomainDefault
1994  *
1995  * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1996  */
1997 void
1998 AlterDomainDefault(List *names, Node *defaultRaw)
1999 {
2000         TypeName   *typename;
2001         Oid                     domainoid;
2002         HeapTuple       tup;
2003         ParseState *pstate;
2004         Relation        rel;
2005         char       *defaultValue;
2006         Node       *defaultExpr = NULL;         /* NULL if no default specified */
2007         Datum           new_record[Natts_pg_type];
2008         bool            new_record_nulls[Natts_pg_type];
2009         bool            new_record_repl[Natts_pg_type];
2010         HeapTuple       newtuple;
2011         Form_pg_type typTup;
2012
2013         /* Make a TypeName so we can use standard type lookup machinery */
2014         typename = makeTypeNameFromNameList(names);
2015         domainoid = typenameTypeId(NULL, typename);
2016
2017         /* Look up the domain in the type table */
2018         rel = heap_open(TypeRelationId, RowExclusiveLock);
2019
2020         tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2021         if (!HeapTupleIsValid(tup))
2022                 elog(ERROR, "cache lookup failed for type %u", domainoid);
2023         typTup = (Form_pg_type) GETSTRUCT(tup);
2024
2025         /* Check it's a domain and check user has permission for ALTER DOMAIN */
2026         checkDomainOwner(tup);
2027
2028         /* Setup new tuple */
2029         MemSet(new_record, (Datum) 0, sizeof(new_record));
2030         MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2031         MemSet(new_record_repl, false, sizeof(new_record_repl));
2032
2033         /* Store the new default into the tuple */
2034         if (defaultRaw)
2035         {
2036                 /* Create a dummy ParseState for transformExpr */
2037                 pstate = make_parsestate(NULL);
2038
2039                 /*
2040                  * Cook the colDef->raw_expr into an expression. Note: Name is
2041                  * strictly for error message
2042                  */
2043                 defaultExpr = cookDefault(pstate, defaultRaw,
2044                                                                   typTup->typbasetype,
2045                                                                   typTup->typtypmod,
2046                                                                   NameStr(typTup->typname));
2047
2048                 /*
2049                  * If the expression is just a NULL constant, we treat the command
2050                  * like ALTER ... DROP DEFAULT.  (But see note for same test in
2051                  * DefineDomain.)
2052                  */
2053                 if (defaultExpr == NULL ||
2054                         (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2055                 {
2056                         /* Default is NULL, drop it */
2057                         new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2058                         new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2059                         new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2060                         new_record_repl[Anum_pg_type_typdefault - 1] = true;
2061                 }
2062                 else
2063                 {
2064                         /*
2065                          * Expression must be stored as a nodeToString result, but we also
2066                          * require a valid textual representation (mainly to make life
2067                          * easier for pg_dump).
2068                          */
2069                         defaultValue = deparse_expression(defaultExpr,
2070                                                                 deparse_context_for(NameStr(typTup->typname),
2071                                                                                                         InvalidOid),
2072                                                                                           false, false);
2073
2074                         /*
2075                          * Form an updated tuple with the new default and write it back.
2076                          */
2077                         new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2078
2079                         new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2080                         new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2081                         new_record_repl[Anum_pg_type_typdefault - 1] = true;
2082                 }
2083         }
2084         else
2085         {
2086                 /* ALTER ... DROP DEFAULT */
2087                 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2088                 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2089                 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2090                 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2091         }
2092
2093         newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2094                                                                  new_record, new_record_nulls,
2095                                                                  new_record_repl);
2096
2097         simple_heap_update(rel, &tup->t_self, newtuple);
2098
2099         CatalogUpdateIndexes(rel, newtuple);
2100
2101         /* Rebuild dependencies */
2102         GenerateTypeDependencies(typTup->typnamespace,
2103                                                          domainoid,
2104                                                          InvalidOid,            /* typrelid is n/a */
2105                                                          0, /* relation kind is n/a */
2106                                                          typTup->typowner,
2107                                                          typTup->typinput,
2108                                                          typTup->typoutput,
2109                                                          typTup->typreceive,
2110                                                          typTup->typsend,
2111                                                          typTup->typmodin,
2112                                                          typTup->typmodout,
2113                                                          typTup->typanalyze,
2114                                                          InvalidOid,
2115                                                          false,         /* a domain isn't an implicit array */
2116                                                          typTup->typbasetype,
2117                                                          typTup->typcollation,
2118                                                          defaultExpr,
2119                                                          true);         /* Rebuild is true */
2120
2121         /* Clean up */
2122         heap_close(rel, NoLock);
2123         heap_freetuple(newtuple);
2124 }
2125
2126 /*
2127  * AlterDomainNotNull
2128  *
2129  * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
2130  */
2131 void
2132 AlterDomainNotNull(List *names, bool notNull)
2133 {
2134         TypeName   *typename;
2135         Oid                     domainoid;
2136         Relation        typrel;
2137         HeapTuple       tup;
2138         Form_pg_type typTup;
2139
2140         /* Make a TypeName so we can use standard type lookup machinery */
2141         typename = makeTypeNameFromNameList(names);
2142         domainoid = typenameTypeId(NULL, typename);
2143
2144         /* Look up the domain in the type table */
2145         typrel = heap_open(TypeRelationId, RowExclusiveLock);
2146
2147         tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2148         if (!HeapTupleIsValid(tup))
2149                 elog(ERROR, "cache lookup failed for type %u", domainoid);
2150         typTup = (Form_pg_type) GETSTRUCT(tup);
2151
2152         /* Check it's a domain and check user has permission for ALTER DOMAIN */
2153         checkDomainOwner(tup);
2154
2155         /* Is the domain already set to the desired constraint? */
2156         if (typTup->typnotnull == notNull)
2157         {
2158                 heap_close(typrel, RowExclusiveLock);
2159                 return;
2160         }
2161
2162         /* Adding a NOT NULL constraint requires checking existing columns */
2163         if (notNull)
2164         {
2165                 List       *rels;
2166                 ListCell   *rt;
2167
2168                 /* Fetch relation list with attributes based on this domain */
2169                 /* ShareLock is sufficient to prevent concurrent data changes */
2170
2171                 rels = get_rels_with_domain(domainoid, ShareLock);
2172
2173                 foreach(rt, rels)
2174                 {
2175                         RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2176                         Relation        testrel = rtc->rel;
2177                         TupleDesc       tupdesc = RelationGetDescr(testrel);
2178                         HeapScanDesc scan;
2179                         HeapTuple       tuple;
2180
2181                         /* Scan all tuples in this relation */
2182                         scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2183                         while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2184                         {
2185                                 int                     i;
2186
2187                                 /* Test attributes that are of the domain */
2188                                 for (i = 0; i < rtc->natts; i++)
2189                                 {
2190                                         int                     attnum = rtc->atts[i];
2191
2192                                         if (heap_attisnull(tuple, attnum))
2193                                                 ereport(ERROR,
2194                                                                 (errcode(ERRCODE_NOT_NULL_VIOLATION),
2195                                                                  errmsg("column \"%s\" of table \"%s\" contains null values",
2196                                                                 NameStr(tupdesc->attrs[attnum - 1]->attname),
2197                                                                                 RelationGetRelationName(testrel))));
2198                                 }
2199                         }
2200                         heap_endscan(scan);
2201
2202                         /* Close each rel after processing, but keep lock */
2203                         heap_close(testrel, NoLock);
2204                 }
2205         }
2206
2207         /*
2208          * Okay to update pg_type row.  We can scribble on typTup because it's a
2209          * copy.
2210          */
2211         typTup->typnotnull = notNull;
2212
2213         simple_heap_update(typrel, &tup->t_self, tup);
2214
2215         CatalogUpdateIndexes(typrel, tup);
2216
2217         /* Clean up */
2218         heap_freetuple(tup);
2219         heap_close(typrel, RowExclusiveLock);
2220 }
2221
2222 /*
2223  * AlterDomainDropConstraint
2224  *
2225  * Implements the ALTER DOMAIN DROP CONSTRAINT statement
2226  */
2227 void
2228 AlterDomainDropConstraint(List *names, const char *constrName,
2229                                                   DropBehavior behavior)
2230 {
2231         TypeName   *typename;
2232         Oid                     domainoid;
2233         HeapTuple       tup;
2234         Relation        rel;
2235         Relation        conrel;
2236         SysScanDesc conscan;
2237         ScanKeyData key[1];
2238         HeapTuple       contup;
2239
2240         /* Make a TypeName so we can use standard type lookup machinery */
2241         typename = makeTypeNameFromNameList(names);
2242         domainoid = typenameTypeId(NULL, typename);
2243
2244         /* Look up the domain in the type table */
2245         rel = heap_open(TypeRelationId, RowExclusiveLock);
2246
2247         tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2248         if (!HeapTupleIsValid(tup))
2249                 elog(ERROR, "cache lookup failed for type %u", domainoid);
2250
2251         /* Check it's a domain and check user has permission for ALTER DOMAIN */
2252         checkDomainOwner(tup);
2253
2254         /* Grab an appropriate lock on the pg_constraint relation */
2255         conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2256
2257         /* Use the index to scan only constraints of the target relation */
2258         ScanKeyInit(&key[0],
2259                                 Anum_pg_constraint_contypid,
2260                                 BTEqualStrategyNumber, F_OIDEQ,
2261                                 ObjectIdGetDatum(HeapTupleGetOid(tup)));
2262
2263         conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2264                                                                  SnapshotNow, 1, key);
2265
2266         /*
2267          * Scan over the result set, removing any matching entries.
2268          */
2269         while ((contup = systable_getnext(conscan)) != NULL)
2270         {
2271                 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
2272
2273                 if (strcmp(NameStr(con->conname), constrName) == 0)
2274                 {
2275                         ObjectAddress conobj;
2276
2277                         conobj.classId = ConstraintRelationId;
2278                         conobj.objectId = HeapTupleGetOid(contup);
2279                         conobj.objectSubId = 0;
2280
2281                         performDeletion(&conobj, behavior);
2282                 }
2283         }
2284         /* Clean up after the scan */
2285         systable_endscan(conscan);
2286         heap_close(conrel, RowExclusiveLock);
2287
2288         heap_close(rel, NoLock);
2289 }
2290
2291 /*
2292  * AlterDomainAddConstraint
2293  *
2294  * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
2295  */
2296 void
2297 AlterDomainAddConstraint(List *names, Node *newConstraint)
2298 {
2299         TypeName   *typename;
2300         Oid                     domainoid;
2301         Relation        typrel;
2302         HeapTuple       tup;
2303         Form_pg_type typTup;
2304         Constraint *constr;
2305         char       *ccbin;
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         typrel = 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         typTup = (Form_pg_type) GETSTRUCT(tup);
2318
2319         /* Check it's a domain and check user has permission for ALTER DOMAIN */
2320         checkDomainOwner(tup);
2321
2322         if (!IsA(newConstraint, Constraint))
2323                 elog(ERROR, "unrecognized node type: %d",
2324                          (int) nodeTag(newConstraint));
2325
2326         constr = (Constraint *) newConstraint;
2327
2328         switch (constr->contype)
2329         {
2330                 case CONSTR_CHECK:
2331                         /* processed below */
2332                         break;
2333
2334                 case CONSTR_UNIQUE:
2335                         ereport(ERROR,
2336                                         (errcode(ERRCODE_SYNTAX_ERROR),
2337                                          errmsg("unique constraints not possible for domains")));
2338                         break;
2339
2340                 case CONSTR_PRIMARY:
2341                         ereport(ERROR,
2342                                         (errcode(ERRCODE_SYNTAX_ERROR),
2343                                 errmsg("primary key constraints not possible for domains")));
2344                         break;
2345
2346                 case CONSTR_EXCLUSION:
2347                         ereport(ERROR,
2348                                         (errcode(ERRCODE_SYNTAX_ERROR),
2349                                   errmsg("exclusion constraints not possible for domains")));
2350                         break;
2351
2352                 case CONSTR_FOREIGN:
2353                         ereport(ERROR,
2354                                         (errcode(ERRCODE_SYNTAX_ERROR),
2355                                 errmsg("foreign key constraints not possible for domains")));
2356                         break;
2357
2358                 case CONSTR_ATTR_DEFERRABLE:
2359                 case CONSTR_ATTR_NOT_DEFERRABLE:
2360                 case CONSTR_ATTR_DEFERRED:
2361                 case CONSTR_ATTR_IMMEDIATE:
2362                         ereport(ERROR,
2363                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2364                                          errmsg("specifying constraint deferrability not supported for domains")));
2365                         break;
2366
2367                 default:
2368                         elog(ERROR, "unrecognized constraint subtype: %d",
2369                                  (int) constr->contype);
2370                         break;
2371         }
2372
2373         /*
2374          * Since all other constraint types throw errors, this must be a check
2375          * constraint.  First, process the constraint expression and add an entry
2376          * to pg_constraint.
2377          */
2378
2379         ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
2380                                                                 typTup->typbasetype, typTup->typtypmod,
2381                                                                 constr, NameStr(typTup->typname));
2382
2383         /*
2384          * If requested to validate the constraint, test all values stored in the
2385          * attributes based on the domain the constraint is being added to.
2386          */
2387         if (!constr->skip_validation)
2388                 validateDomainConstraint(domainoid, ccbin);
2389
2390         /* Clean up */
2391         heap_close(typrel, RowExclusiveLock);
2392 }
2393
2394 /*
2395  * AlterDomainValidateConstraint
2396  *
2397  * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
2398  */
2399 void
2400 AlterDomainValidateConstraint(List *names, char *constrName)
2401 {
2402         TypeName   *typename;
2403         Oid                     domainoid;
2404         Relation        typrel;
2405         Relation        conrel;
2406         HeapTuple       tup;
2407         Form_pg_constraint con = NULL;
2408         Form_pg_constraint copy_con;
2409         char       *conbin;
2410         SysScanDesc scan;
2411         Datum           val;
2412         bool            found = false;
2413         bool            isnull;
2414         HeapTuple       tuple;
2415         HeapTuple       copyTuple;
2416         ScanKeyData key;
2417
2418         /* Make a TypeName so we can use standard type lookup machinery */
2419         typename = makeTypeNameFromNameList(names);
2420         domainoid = typenameTypeId(NULL, typename);
2421
2422         /* Look up the domain in the type table */
2423         typrel = heap_open(TypeRelationId, AccessShareLock);
2424
2425         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2426         if (!HeapTupleIsValid(tup))
2427                 elog(ERROR, "cache lookup failed for type %u", domainoid);
2428
2429         /* Check it's a domain and check user has permission for ALTER DOMAIN */
2430         checkDomainOwner(tup);
2431
2432         /*
2433          * Find and check the target constraint
2434          */
2435         conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2436         ScanKeyInit(&key,
2437                                 Anum_pg_constraint_contypid,
2438                                 BTEqualStrategyNumber, F_OIDEQ,
2439                                 ObjectIdGetDatum(domainoid));
2440         scan = systable_beginscan(conrel, ConstraintTypidIndexId,
2441                                                           true, SnapshotNow, 1, &key);
2442
2443         while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2444         {
2445                 con = (Form_pg_constraint) GETSTRUCT(tuple);
2446                 if (strcmp(NameStr(con->conname), constrName) == 0)
2447                 {
2448                         found = true;
2449                         break;
2450                 }
2451         }
2452
2453         if (!found)
2454                 ereport(ERROR,
2455                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2456                                  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2457                                                 constrName, TypeNameToString(typename))));
2458
2459         if (con->contype != CONSTRAINT_CHECK)
2460                 ereport(ERROR,
2461                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2462                 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2463                            constrName, TypeNameToString(typename))));
2464
2465         val = SysCacheGetAttr(CONSTROID, tuple,
2466                                                   Anum_pg_constraint_conbin,
2467                                                   &isnull);
2468         if (isnull)
2469                 elog(ERROR, "null conbin for constraint %u",
2470                          HeapTupleGetOid(tuple));
2471         conbin = TextDatumGetCString(val);
2472
2473         validateDomainConstraint(domainoid, conbin);
2474
2475         /*
2476          * Now update the catalog, while we have the door open.
2477          */
2478         copyTuple = heap_copytuple(tuple);
2479         copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2480         copy_con->convalidated = true;
2481         simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
2482         CatalogUpdateIndexes(conrel, copyTuple);
2483         heap_freetuple(copyTuple);
2484
2485         systable_endscan(scan);
2486
2487         heap_close(typrel, AccessShareLock);
2488         heap_close(conrel, RowExclusiveLock);
2489
2490         ReleaseSysCache(tup);
2491 }
2492
2493 static void
2494 validateDomainConstraint(Oid domainoid, char *ccbin)
2495 {
2496         Expr       *expr = (Expr *) stringToNode(ccbin);
2497         List       *rels;
2498         ListCell   *rt;
2499         EState     *estate;
2500         ExprContext *econtext;
2501         ExprState  *exprstate;
2502
2503         /* Need an EState to run ExecEvalExpr */
2504         estate = CreateExecutorState();
2505         econtext = GetPerTupleExprContext(estate);
2506
2507         /* build execution state for expr */
2508         exprstate = ExecPrepareExpr(expr, estate);
2509
2510         /* Fetch relation list with attributes based on this domain */
2511         /* ShareLock is sufficient to prevent concurrent data changes */
2512
2513         rels = get_rels_with_domain(domainoid, ShareLock);
2514
2515         foreach(rt, rels)
2516         {
2517                 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2518                 Relation        testrel = rtc->rel;
2519                 TupleDesc       tupdesc = RelationGetDescr(testrel);
2520                 HeapScanDesc scan;
2521                 HeapTuple       tuple;
2522
2523                 /* Scan all tuples in this relation */
2524                 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
2525                 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2526                 {
2527                         int                     i;
2528
2529                         /* Test attributes that are of the domain */
2530                         for (i = 0; i < rtc->natts; i++)
2531                         {
2532                                 int                     attnum = rtc->atts[i];
2533                                 Datum           d;
2534                                 bool            isNull;
2535                                 Datum           conResult;
2536
2537                                 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
2538
2539                                 econtext->domainValue_datum = d;
2540                                 econtext->domainValue_isNull = isNull;
2541
2542                                 conResult = ExecEvalExprSwitchContext(exprstate,
2543                                                                                                           econtext,
2544                                                                                                           &isNull, NULL);
2545
2546                                 if (!isNull && !DatumGetBool(conResult))
2547                                         ereport(ERROR,
2548                                                         (errcode(ERRCODE_CHECK_VIOLATION),
2549                                                          errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
2550                                                                 NameStr(tupdesc->attrs[attnum - 1]->attname),
2551                                                                         RelationGetRelationName(testrel))));
2552                         }
2553
2554                         ResetExprContext(econtext);
2555                 }
2556                 heap_endscan(scan);
2557
2558                 /* Hold relation lock till commit (XXX bad for concurrency) */
2559                 heap_close(testrel, NoLock);
2560         }
2561
2562         FreeExecutorState(estate);
2563 }
2564
2565 /*
2566  * get_rels_with_domain
2567  *
2568  * Fetch all relations / attributes which are using the domain
2569  *
2570  * The result is a list of RelToCheck structs, one for each distinct
2571  * relation, each containing one or more attribute numbers that are of
2572  * the domain type.  We have opened each rel and acquired the specified lock
2573  * type on it.
2574  *
2575  * We support nested domains by including attributes that are of derived
2576  * domain types.  Current callers do not need to distinguish between attributes
2577  * that are of exactly the given domain and those that are of derived domains.
2578  *
2579  * XXX this is completely broken because there is no way to lock the domain
2580  * to prevent columns from being added or dropped while our command runs.
2581  * We can partially protect against column drops by locking relations as we
2582  * come across them, but there is still a race condition (the window between
2583  * seeing a pg_depend entry and acquiring lock on the relation it references).
2584  * Also, holding locks on all these relations simultaneously creates a non-
2585  * trivial risk of deadlock.  We can minimize but not eliminate the deadlock
2586  * risk by using the weakest suitable lock (ShareLock for most callers).
2587  *
2588  * XXX the API for this is not sufficient to support checking domain values
2589  * that are inside composite types or arrays.  Currently we just error out
2590  * if a composite type containing the target domain is stored anywhere.
2591  * There are not currently arrays of domains; if there were, we could take
2592  * the same approach, but it'd be nicer to fix it properly.
2593  *
2594  * Generally used for retrieving a list of tests when adding
2595  * new constraints to a domain.
2596  */
2597 static List *
2598 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
2599 {
2600         List       *result = NIL;
2601         Relation        depRel;
2602         ScanKeyData key[2];
2603         SysScanDesc depScan;
2604         HeapTuple       depTup;
2605
2606         Assert(lockmode != NoLock);
2607
2608         /*
2609          * We scan pg_depend to find those things that depend on the domain. (We
2610          * assume we can ignore refobjsubid for a domain.)
2611          */
2612         depRel = heap_open(DependRelationId, AccessShareLock);
2613
2614         ScanKeyInit(&key[0],
2615                                 Anum_pg_depend_refclassid,
2616                                 BTEqualStrategyNumber, F_OIDEQ,
2617                                 ObjectIdGetDatum(TypeRelationId));
2618         ScanKeyInit(&key[1],
2619                                 Anum_pg_depend_refobjid,
2620                                 BTEqualStrategyNumber, F_OIDEQ,
2621                                 ObjectIdGetDatum(domainOid));
2622
2623         depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2624                                                                  SnapshotNow, 2, key);
2625
2626         while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2627         {
2628                 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2629                 RelToCheck *rtc = NULL;
2630                 ListCell   *rellist;
2631                 Form_pg_attribute pg_att;
2632                 int                     ptr;
2633
2634                 /* Check for directly dependent types --- must be domains */
2635                 if (pg_depend->classid == TypeRelationId)
2636                 {
2637                         Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
2638
2639                         /*
2640                          * Recursively add dependent columns to the output list.  This is
2641                          * a bit inefficient since we may fail to combine RelToCheck
2642                          * entries when attributes of the same rel have different derived
2643                          * domain types, but it's probably not worth improving.
2644                          */
2645                         result = list_concat(result,
2646                                                                  get_rels_with_domain(pg_depend->objid,
2647                                                                                                           lockmode));
2648                         continue;
2649                 }
2650
2651                 /* Else, ignore dependees that aren't user columns of relations */
2652                 /* (we assume system columns are never of domain types) */
2653                 if (pg_depend->classid != RelationRelationId ||
2654                         pg_depend->objsubid <= 0)
2655                         continue;
2656
2657                 /* See if we already have an entry for this relation */
2658                 foreach(rellist, result)
2659                 {
2660                         RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2661
2662                         if (RelationGetRelid(rt->rel) == pg_depend->objid)
2663                         {
2664                                 rtc = rt;
2665                                 break;
2666                         }
2667                 }
2668
2669                 if (rtc == NULL)
2670                 {
2671                         /* First attribute found for this relation */
2672                         Relation        rel;
2673
2674                         /* Acquire requested lock on relation */
2675                         rel = relation_open(pg_depend->objid, lockmode);
2676
2677                         /*
2678                          * Check to see if rowtype is stored anyplace as a composite-type
2679                          * column; if so we have to fail, for now anyway.
2680                          */
2681                         if (OidIsValid(rel->rd_rel->reltype))
2682                                 find_composite_type_dependencies(rel->rd_rel->reltype,
2683                                                                                                  NULL,
2684                                                                                                  format_type_be(domainOid));
2685
2686                         /* Otherwise we can ignore views, composite types, etc */
2687                         if (rel->rd_rel->relkind != RELKIND_RELATION)
2688                         {
2689                                 relation_close(rel, lockmode);
2690                                 continue;
2691                         }
2692
2693                         /* Build the RelToCheck entry with enough space for all atts */
2694                         rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2695                         rtc->rel = rel;
2696                         rtc->natts = 0;
2697                         rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2698                         result = lcons(rtc, result);
2699                 }
2700
2701                 /*
2702                  * Confirm column has not been dropped, and is of the expected type.
2703                  * This defends against an ALTER DROP COLUMN occuring just before we
2704                  * acquired lock ... but if the whole table were dropped, we'd still
2705                  * have a problem.
2706                  */
2707                 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
2708                         continue;
2709                 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
2710                 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
2711                         continue;
2712
2713                 /*
2714                  * Okay, add column to result.  We store the columns in column-number
2715                  * order; this is just a hack to improve predictability of regression
2716                  * test output ...
2717                  */
2718                 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
2719
2720                 ptr = rtc->natts++;
2721                 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
2722                 {
2723                         rtc->atts[ptr] = rtc->atts[ptr - 1];
2724                         ptr--;
2725                 }
2726                 rtc->atts[ptr] = pg_depend->objsubid;
2727         }
2728
2729         systable_endscan(depScan);
2730
2731         relation_close(depRel, AccessShareLock);
2732
2733         return result;
2734 }
2735
2736 /*
2737  * checkDomainOwner
2738  *
2739  * Check that the type is actually a domain and that the current user
2740  * has permission to do ALTER DOMAIN on it.  Throw an error if not.
2741  */
2742 static void
2743 checkDomainOwner(HeapTuple tup)
2744 {
2745         Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2746
2747         /* Check that this is actually a domain */
2748         if (typTup->typtype != TYPTYPE_DOMAIN)
2749                 ereport(ERROR,
2750                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2751                                  errmsg("%s is not a domain",
2752                                                 format_type_be(HeapTupleGetOid(tup)))));
2753
2754         /* Permission check: must own type */
2755         if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2756                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2757                                            format_type_be(HeapTupleGetOid(tup)));
2758 }
2759
2760 /*
2761  * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
2762  */
2763 static char *
2764 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
2765                                         int typMod, Constraint *constr,
2766                                         char *domainName)
2767 {
2768         Node       *expr;
2769         char       *ccsrc;
2770         char       *ccbin;
2771         ParseState *pstate;
2772         CoerceToDomainValue *domVal;
2773
2774         /*
2775          * Assign or validate constraint name
2776          */
2777         if (constr->conname)
2778         {
2779                 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
2780                                                                  domainOid,
2781                                                                  domainNamespace,
2782                                                                  constr->conname))
2783                         ereport(ERROR,
2784                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
2785                                  errmsg("constraint \"%s\" for domain \"%s\" already exists",
2786                                                 constr->conname, domainName)));
2787         }
2788         else
2789                 constr->conname = ChooseConstraintName(domainName,
2790                                                                                            NULL,
2791                                                                                            "check",
2792                                                                                            domainNamespace,
2793                                                                                            NIL);
2794
2795         /*
2796          * Convert the A_EXPR in raw_expr into an EXPR
2797          */
2798         pstate = make_parsestate(NULL);
2799
2800         /*
2801          * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
2802          * the expression.      Note that it will appear to have the type of the base
2803          * type, not the domain.  This seems correct since within the check
2804          * expression, we should not assume the input value can be considered a
2805          * member of the domain.
2806          */
2807         domVal = makeNode(CoerceToDomainValue);
2808         domVal->typeId = baseTypeOid;
2809         domVal->typeMod = typMod;
2810         domVal->collation = get_typcollation(baseTypeOid);
2811         domVal->location = -1;          /* will be set when/if used */
2812
2813         pstate->p_value_substitute = (Node *) domVal;
2814
2815         expr = transformExpr(pstate, constr->raw_expr);
2816
2817         /*
2818          * Make sure it yields a boolean result.
2819          */
2820         expr = coerce_to_boolean(pstate, expr, "CHECK");
2821
2822         /*
2823          * Fix up collation information.
2824          */
2825         assign_expr_collations(pstate, expr);
2826
2827         /*
2828          * Make sure no outside relations are referred to.
2829          */
2830         if (list_length(pstate->p_rtable) != 0)
2831                 ereport(ERROR,
2832                                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2833                   errmsg("cannot use table references in domain check constraint")));
2834
2835         /*
2836          * Domains don't allow var clauses (this should be redundant with the
2837          * above check, but make it anyway)
2838          */
2839         if (contain_var_clause(expr))
2840                 ereport(ERROR,
2841                                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2842                   errmsg("cannot use table references in domain check constraint")));
2843
2844         /*
2845          * No subplans or aggregates, either...
2846          */
2847         if (pstate->p_hasSubLinks)
2848                 ereport(ERROR,
2849                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2850                                  errmsg("cannot use subquery in check constraint")));
2851         if (pstate->p_hasAggs)
2852                 ereport(ERROR,
2853                                 (errcode(ERRCODE_GROUPING_ERROR),
2854                            errmsg("cannot use aggregate function in check constraint")));
2855         if (pstate->p_hasWindowFuncs)
2856                 ereport(ERROR,
2857                                 (errcode(ERRCODE_WINDOWING_ERROR),
2858                                  errmsg("cannot use window function in check constraint")));
2859
2860         /*
2861          * Convert to string form for storage.
2862          */
2863         ccbin = nodeToString(expr);
2864
2865         /*
2866          * Deparse it to produce text for consrc.
2867          *
2868          * Since VARNOs aren't allowed in domain constraints, relation context
2869          * isn't required as anything other than a shell.
2870          */
2871         ccsrc = deparse_expression(expr,
2872                                                            deparse_context_for(domainName,
2873                                                                                                    InvalidOid),
2874                                                            false, false);
2875
2876         /*
2877          * Store the constraint in pg_constraint
2878          */
2879         CreateConstraintEntry(constr->conname,          /* Constraint Name */
2880                                                   domainNamespace,              /* namespace */
2881                                                   CONSTRAINT_CHECK,             /* Constraint Type */
2882                                                   false,        /* Is Deferrable */
2883                                                   false,        /* Is Deferred */
2884                                                   !constr->skip_validation,             /* Is Validated */
2885                                                   InvalidOid,   /* not a relation constraint */
2886                                                   NULL,
2887                                                   0,
2888                                                   domainOid,    /* domain constraint */
2889                                                   InvalidOid,   /* no associated index */
2890                                                   InvalidOid,   /* Foreign key fields */
2891                                                   NULL,
2892                                                   NULL,
2893                                                   NULL,
2894                                                   NULL,
2895                                                   0,
2896                                                   ' ',
2897                                                   ' ',
2898                                                   ' ',
2899                                                   NULL, /* not an exclusion constraint */
2900                                                   expr, /* Tree form of check constraint */
2901                                                   ccbin,        /* Binary form of check constraint */
2902                                                   ccsrc,        /* Source form of check constraint */
2903                                                   true, /* is local */
2904                                                   0);   /* inhcount */
2905
2906         /*
2907          * Return the compiled constraint expression so the calling routine can
2908          * perform any additional required tests.
2909          */
2910         return ccbin;
2911 }
2912
2913 /*
2914  * GetDomainConstraints - get a list of the current constraints of domain
2915  *
2916  * Returns a possibly-empty list of DomainConstraintState nodes.
2917  *
2918  * This is called by the executor during plan startup for a CoerceToDomain
2919  * expression node.  The given constraints will be checked for each value
2920  * passed through the node.
2921  *
2922  * We allow this to be called for non-domain types, in which case the result
2923  * is always NIL.
2924  */
2925 List *
2926 GetDomainConstraints(Oid typeOid)
2927 {
2928         List       *result = NIL;
2929         bool            notNull = false;
2930         Relation        conRel;
2931
2932         conRel = heap_open(ConstraintRelationId, AccessShareLock);
2933
2934         for (;;)
2935         {
2936                 HeapTuple       tup;
2937                 HeapTuple       conTup;
2938                 Form_pg_type typTup;
2939                 ScanKeyData key[1];
2940                 SysScanDesc scan;
2941
2942                 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
2943                 if (!HeapTupleIsValid(tup))
2944                         elog(ERROR, "cache lookup failed for type %u", typeOid);
2945                 typTup = (Form_pg_type) GETSTRUCT(tup);
2946
2947                 if (typTup->typtype != TYPTYPE_DOMAIN)
2948                 {
2949                         /* Not a domain, so done */
2950                         ReleaseSysCache(tup);
2951                         break;
2952                 }
2953
2954                 /* Test for NOT NULL Constraint */
2955                 if (typTup->typnotnull)
2956                         notNull = true;
2957
2958                 /* Look for CHECK Constraints on this domain */
2959                 ScanKeyInit(&key[0],
2960                                         Anum_pg_constraint_contypid,
2961                                         BTEqualStrategyNumber, F_OIDEQ,
2962                                         ObjectIdGetDatum(typeOid));
2963
2964                 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
2965                                                                   SnapshotNow, 1, key);
2966
2967                 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
2968                 {
2969                         Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
2970                         Datum           val;
2971                         bool            isNull;
2972                         Expr       *check_expr;
2973                         DomainConstraintState *r;
2974
2975                         /* Ignore non-CHECK constraints (presently, shouldn't be any) */
2976                         if (c->contype != CONSTRAINT_CHECK)
2977                                 continue;
2978
2979                         /*
2980                          * Not expecting conbin to be NULL, but we'll test for it anyway
2981                          */
2982                         val = fastgetattr(conTup, Anum_pg_constraint_conbin,
2983                                                           conRel->rd_att, &isNull);
2984                         if (isNull)
2985                                 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
2986                                          NameStr(typTup->typname), NameStr(c->conname));
2987
2988                         check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
2989
2990                         /* ExecInitExpr assumes we've planned the expression */
2991                         check_expr = expression_planner(check_expr);
2992
2993                         r = makeNode(DomainConstraintState);
2994                         r->constrainttype = DOM_CONSTRAINT_CHECK;
2995                         r->name = pstrdup(NameStr(c->conname));
2996                         r->check_expr = ExecInitExpr(check_expr, NULL);
2997
2998                         /*
2999                          * use lcons() here because constraints of lower domains should be
3000                          * applied earlier.
3001                          */
3002                         result = lcons(r, result);
3003                 }
3004
3005                 systable_endscan(scan);
3006
3007                 /* loop to next domain in stack */
3008                 typeOid = typTup->typbasetype;
3009                 ReleaseSysCache(tup);
3010         }
3011
3012         heap_close(conRel, AccessShareLock);
3013
3014         /*
3015          * Only need to add one NOT NULL check regardless of how many domains in
3016          * the stack request it.
3017          */
3018         if (notNull)
3019         {
3020                 DomainConstraintState *r = makeNode(DomainConstraintState);
3021
3022                 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
3023                 r->name = pstrdup("NOT NULL");
3024                 r->check_expr = NULL;
3025
3026                 /* lcons to apply the nullness check FIRST */
3027                 result = lcons(r, result);
3028         }
3029
3030         return result;
3031 }
3032
3033
3034 /*
3035  * Execute ALTER TYPE RENAME
3036  */
3037 void
3038 RenameType(List *names, const char *newTypeName)
3039 {
3040         TypeName   *typename;
3041         Oid                     typeOid;
3042         Relation        rel;
3043         HeapTuple       tup;
3044         Form_pg_type typTup;
3045
3046         /* Make a TypeName so we can use standard type lookup machinery */
3047         typename = makeTypeNameFromNameList(names);
3048         typeOid = typenameTypeId(NULL, typename);
3049
3050         /* Look up the type in the type table */
3051         rel = heap_open(TypeRelationId, RowExclusiveLock);
3052
3053         tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3054         if (!HeapTupleIsValid(tup))
3055                 elog(ERROR, "cache lookup failed for type %u", typeOid);
3056         typTup = (Form_pg_type) GETSTRUCT(tup);
3057
3058         /* check permissions on type */
3059         if (!pg_type_ownercheck(typeOid, GetUserId()))
3060                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3061                                            format_type_be(typeOid));
3062
3063         /*
3064          * If it's a composite type, we need to check that it really is a
3065          * free-standing composite type, and not a table's rowtype. We want people
3066          * to use ALTER TABLE not ALTER TYPE for that case.
3067          */
3068         if (typTup->typtype == TYPTYPE_COMPOSITE &&
3069                 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3070                 ereport(ERROR,
3071                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3072                                  errmsg("%s is a table's row type",
3073                                                 format_type_be(typeOid)),
3074                                  errhint("Use ALTER TABLE instead.")));
3075
3076         /* don't allow direct alteration of array types, either */
3077         if (OidIsValid(typTup->typelem) &&
3078                 get_array_type(typTup->typelem) == typeOid)
3079                 ereport(ERROR,
3080                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3081                                  errmsg("cannot alter array type %s",
3082                                                 format_type_be(typeOid)),
3083                                  errhint("You can alter type %s, which will alter the array type as well.",
3084                                                  format_type_be(typTup->typelem))));
3085
3086         /*
3087          * If type is composite we need to rename associated pg_class entry too.
3088          * RenameRelationInternal will call RenameTypeInternal automatically.
3089          */
3090         if (typTup->typtype == TYPTYPE_COMPOSITE)
3091                 RenameRelationInternal(typTup->typrelid, newTypeName,
3092                                                            typTup->typnamespace);
3093         else
3094                 RenameTypeInternal(typeOid, newTypeName,
3095                                                    typTup->typnamespace);
3096
3097         /* Clean up */
3098         heap_close(rel, RowExclusiveLock);
3099 }
3100
3101 /*
3102  * Change the owner of a type.
3103  */
3104 void
3105 AlterTypeOwner(List *names, Oid newOwnerId)
3106 {
3107         TypeName   *typename;
3108         Oid                     typeOid;
3109         Relation        rel;
3110         HeapTuple       tup;
3111         HeapTuple       newtup;
3112         Form_pg_type typTup;
3113         AclResult       aclresult;
3114
3115         rel = heap_open(TypeRelationId, RowExclusiveLock);
3116
3117         /* Make a TypeName so we can use standard type lookup machinery */
3118         typename = makeTypeNameFromNameList(names);
3119
3120         /* Use LookupTypeName here so that shell types can be processed */
3121         tup = LookupTypeName(NULL, typename, NULL);
3122         if (tup == NULL)
3123                 ereport(ERROR,
3124                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
3125                                  errmsg("type \"%s\" does not exist",
3126                                                 TypeNameToString(typename))));
3127         typeOid = typeTypeId(tup);
3128
3129         /* Copy the syscache entry so we can scribble on it below */
3130         newtup = heap_copytuple(tup);
3131         ReleaseSysCache(tup);
3132         tup = newtup;
3133         typTup = (Form_pg_type) GETSTRUCT(tup);
3134
3135         /*
3136          * If it's a composite type, we need to check that it really is a
3137          * free-standing composite type, and not a table's rowtype. We want people
3138          * to use ALTER TABLE not ALTER TYPE for that case.
3139          */
3140         if (typTup->typtype == TYPTYPE_COMPOSITE &&
3141                 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3142                 ereport(ERROR,
3143                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3144                                  errmsg("%s is a table's row type",
3145                                                 format_type_be(typeOid)),
3146                                  errhint("Use ALTER TABLE instead.")));
3147
3148         /* don't allow direct alteration of array types, either */
3149         if (OidIsValid(typTup->typelem) &&
3150                 get_array_type(typTup->typelem) == typeOid)
3151                 ereport(ERROR,
3152                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3153                                  errmsg("cannot alter array type %s",
3154                                                 format_type_be(typeOid)),
3155                                  errhint("You can alter type %s, which will alter the array type as well.",
3156                                                  format_type_be(typTup->typelem))));
3157
3158         /*
3159          * If the new owner is the same as the existing owner, consider the
3160          * command to have succeeded.  This is for dump restoration purposes.
3161          */
3162         if (typTup->typowner != newOwnerId)
3163         {
3164                 /* Superusers can always do it */
3165                 if (!superuser())
3166                 {
3167                         /* Otherwise, must be owner of the existing object */
3168                         if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
3169                                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3170                                                            format_type_be(HeapTupleGetOid(tup)));
3171
3172                         /* Must be able to become new owner */
3173                         check_is_member_of_role(GetUserId(), newOwnerId);
3174
3175                         /* New owner must have CREATE privilege on namespace */
3176                         aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3177                                                                                           newOwnerId,
3178                                                                                           ACL_CREATE);
3179                         if (aclresult != ACLCHECK_OK)
3180                                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
3181                                                            get_namespace_name(typTup->typnamespace));
3182                 }
3183
3184                 /*
3185                  * If it's a composite type, invoke ATExecChangeOwner so that we fix
3186                  * up the pg_class entry properly.      That will call back to
3187                  * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3188                  */
3189                 if (typTup->typtype == TYPTYPE_COMPOSITE)
3190                         ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3191                 else
3192                 {
3193                         /*
3194                          * We can just apply the modification directly.
3195                          *
3196                          * okay to scribble on typTup because it's a copy
3197                          */
3198                         typTup->typowner = newOwnerId;
3199
3200                         simple_heap_update(rel, &tup->t_self, tup);
3201
3202                         CatalogUpdateIndexes(rel, tup);
3203
3204                         /* Update owner dependency reference */
3205                         changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3206
3207                         /* If it has an array type, update that too */
3208                         if (OidIsValid(typTup->typarray))
3209                                 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3210                 }
3211         }
3212
3213         /* Clean up */
3214         heap_close(rel, RowExclusiveLock);
3215 }
3216
3217 /*
3218  * AlterTypeOwnerInternal - change type owner unconditionally
3219  *
3220  * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
3221  * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
3222  * It assumes the caller has done all needed checks.  The function will
3223  * automatically recurse to an array type if the type has one.
3224  *
3225  * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
3226  * entry (ie, it's not a table rowtype nor an array type).
3227  */
3228 void
3229 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
3230                                            bool hasDependEntry)
3231 {
3232         Relation        rel;
3233         HeapTuple       tup;
3234         Form_pg_type typTup;
3235
3236         rel = heap_open(TypeRelationId, RowExclusiveLock);
3237
3238         tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3239         if (!HeapTupleIsValid(tup))
3240                 elog(ERROR, "cache lookup failed for type %u", typeOid);
3241         typTup = (Form_pg_type) GETSTRUCT(tup);
3242
3243         /*
3244          * Modify the owner --- okay to scribble on typTup because it's a copy
3245          */
3246         typTup->typowner = newOwnerId;
3247
3248         simple_heap_update(rel, &tup->t_self, tup);
3249
3250         CatalogUpdateIndexes(rel, tup);
3251
3252         /* Update owner dependency reference, if it has one */
3253         if (hasDependEntry)
3254                 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3255
3256         /* If it has an array type, update that too */
3257         if (OidIsValid(typTup->typarray))
3258                 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
3259
3260         /* Clean up */
3261         heap_close(rel, RowExclusiveLock);
3262 }
3263
3264 /*
3265  * Execute ALTER TYPE SET SCHEMA
3266  */
3267 void
3268 AlterTypeNamespace(List *names, const char *newschema)
3269 {
3270         TypeName   *typename;
3271         Oid                     typeOid;
3272         Oid                     nspOid;
3273
3274         /* Make a TypeName so we can use standard type lookup machinery */
3275         typename = makeTypeNameFromNameList(names);
3276         typeOid = typenameTypeId(NULL, typename);
3277
3278         /* get schema OID and check its permissions */
3279         nspOid = LookupCreationNamespace(newschema);
3280
3281         AlterTypeNamespace_oid(typeOid, nspOid);
3282 }
3283
3284 Oid
3285 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid)
3286 {
3287         Oid                     elemOid;
3288
3289         /* check permissions on type */
3290         if (!pg_type_ownercheck(typeOid, GetUserId()))
3291                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
3292                                            format_type_be(typeOid));
3293
3294         /* don't allow direct alteration of array types */
3295         elemOid = get_element_type(typeOid);
3296         if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3297                 ereport(ERROR,
3298                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3299                                  errmsg("cannot alter array type %s",
3300                                                 format_type_be(typeOid)),
3301                                  errhint("You can alter type %s, which will alter the array type as well.",
3302                                                  format_type_be(elemOid))));
3303
3304         /* and do the work */
3305         return AlterTypeNamespaceInternal(typeOid, nspOid, false, true);
3306 }
3307
3308 /*
3309  * Move specified type to new namespace.
3310  *
3311  * Caller must have already checked privileges.
3312  *
3313  * The function automatically recurses to process the type's array type,
3314  * if any.      isImplicitArray should be TRUE only when doing this internal
3315  * recursion (outside callers must never try to move an array type directly).
3316  *
3317  * If errorOnTableType is TRUE, the function errors out if the type is
3318  * a table type.  ALTER TABLE has to be used to move a table to a new
3319  * namespace.
3320  *
3321  * Returns the type's old namespace OID.
3322  */
3323 Oid
3324 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
3325                                                    bool isImplicitArray,
3326                                                    bool errorOnTableType)
3327 {
3328         Relation        rel;
3329         HeapTuple       tup;
3330         Form_pg_type typform;
3331         Oid                     oldNspOid;
3332         Oid                     arrayOid;
3333         bool            isCompositeType;
3334
3335         rel = heap_open(TypeRelationId, RowExclusiveLock);
3336
3337         tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3338         if (!HeapTupleIsValid(tup))
3339                 elog(ERROR, "cache lookup failed for type %u", typeOid);
3340         typform = (Form_pg_type) GETSTRUCT(tup);
3341
3342         oldNspOid = typform->typnamespace;
3343         arrayOid = typform->typarray;
3344
3345         /* common checks on switching namespaces */
3346         CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
3347
3348         /* check for duplicate name (more friendly than unique-index failure) */
3349         if (SearchSysCacheExists2(TYPENAMENSP,
3350                                                           CStringGetDatum(NameStr(typform->typname)),
3351                                                           ObjectIdGetDatum(nspOid)))
3352                 ereport(ERROR,
3353                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
3354                                  errmsg("type \"%s\" already exists in schema \"%s\"",
3355                                                 NameStr(typform->typname),
3356                                                 get_namespace_name(nspOid))));
3357
3358         /* Detect whether type is a composite type (but not a table rowtype) */
3359         isCompositeType =
3360                 (typform->typtype == TYPTYPE_COMPOSITE &&
3361                  get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3362
3363         /* Enforce not-table-type if requested */
3364         if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3365                 errorOnTableType)
3366                 ereport(ERROR,
3367                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3368                                  errmsg("%s is a table's row type",
3369                                                 format_type_be(typeOid)),
3370                                  errhint("Use ALTER TABLE instead.")));
3371
3372         /* OK, modify the pg_type row */
3373
3374         /* tup is a copy, so we can scribble directly on it */
3375         typform->typnamespace = nspOid;
3376
3377         simple_heap_update(rel, &tup->t_self, tup);
3378         CatalogUpdateIndexes(rel, tup);
3379
3380         /*
3381          * Composite types have pg_class entries.
3382          *
3383          * We need to modify the pg_class tuple as well to reflect the change of
3384          * schema.
3385          */
3386         if (isCompositeType)
3387         {
3388                 Relation        classRel;
3389
3390                 classRel = heap_open(RelationRelationId, RowExclusiveLock);
3391
3392                 AlterRelationNamespaceInternal(classRel, typform->typrelid,
3393                                                                            oldNspOid, nspOid,
3394                                                                            false);
3395
3396                 heap_close(classRel, RowExclusiveLock);
3397
3398                 /*
3399                  * Check for constraints associated with the composite type (we don't
3400                  * currently support this, but probably will someday).
3401                  */
3402                 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3403                                                                   nspOid, false);
3404         }
3405         else
3406         {
3407                 /* If it's a domain, it might have constraints */
3408                 if (typform->typtype == TYPTYPE_DOMAIN)
3409                         AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
3410         }
3411
3412         /*
3413          * Update dependency on schema, if any --- a table rowtype has not got
3414          * one, and neither does an implicit array.
3415          */
3416         if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3417                 !isImplicitArray)
3418                 if (changeDependencyFor(TypeRelationId, typeOid,
3419                                                                 NamespaceRelationId, oldNspOid, nspOid) != 1)
3420                         elog(ERROR, "failed to change schema dependency for type %s",
3421                                  format_type_be(typeOid));
3422
3423         heap_freetuple(tup);
3424
3425         heap_close(rel, RowExclusiveLock);
3426
3427         /* Recursively alter the associated array type, if any */
3428         if (OidIsValid(arrayOid))
3429                 AlterTypeNamespaceInternal(arrayOid, nspOid, true, true);
3430
3431         return oldNspOid;
3432 }