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