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