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