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