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