OSDN Git Service

Eliminate a gratuitously different wording of the 'cannot use aggregate function...
[pg-rex/syncrep.git] / 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-2006, 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.91 2006/06/21 18:09:53 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/heapam.h"
35 #include "access/genam.h"
36 #include "catalog/dependency.h"
37 #include "catalog/heap.h"
38 #include "catalog/indexing.h"
39 #include "catalog/namespace.h"
40 #include "catalog/pg_constraint.h"
41 #include "catalog/pg_depend.h"
42 #include "catalog/pg_namespace.h"
43 #include "catalog/pg_type.h"
44 #include "commands/defrem.h"
45 #include "commands/tablecmds.h"
46 #include "commands/typecmds.h"
47 #include "executor/executor.h"
48 #include "miscadmin.h"
49 #include "nodes/execnodes.h"
50 #include "nodes/makefuncs.h"
51 #include "optimizer/clauses.h"
52 #include "optimizer/planmain.h"
53 #include "optimizer/var.h"
54 #include "parser/parse_coerce.h"
55 #include "parser/parse_expr.h"
56 #include "parser/parse_func.h"
57 #include "parser/parse_relation.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
66
67 /* result structure for get_rels_with_domain() */
68 typedef struct
69 {
70         Relation        rel;                    /* opened and locked relation */
71         int                     natts;                  /* number of attributes of interest */
72         int                *atts;                       /* attribute numbers */
73         /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
74 } RelToCheck;
75
76
77 static Oid      findTypeInputFunction(List *procname, Oid typeOid);
78 static Oid      findTypeOutputFunction(List *procname, Oid typeOid);
79 static Oid      findTypeReceiveFunction(List *procname, Oid typeOid);
80 static Oid      findTypeSendFunction(List *procname, Oid typeOid);
81 static Oid      findTypeAnalyzeFunction(List *procname, Oid typeOid);
82 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
83 static void checkDomainOwner(HeapTuple tup, TypeName *typename);
84 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
85                                         Oid baseTypeOid,
86                                         int typMod, Constraint *constr,
87                                         char *domainName);
88
89
90 /*
91  * DefineType
92  *              Registers a new type.
93  */
94 void
95 DefineType(List *names, List *parameters)
96 {
97         char       *typeName;
98         Oid                     typeNamespace;
99         AclResult       aclresult;
100         int16           internalLength = -1;    /* default: variable-length */
101         Oid                     elemType = InvalidOid;
102         List       *inputName = NIL;
103         List       *outputName = NIL;
104         List       *receiveName = NIL;
105         List       *sendName = NIL;
106         List       *analyzeName = NIL;
107         char       *defaultValue = NULL;
108         bool            byValue = false;
109         char            delimiter = DEFAULT_TYPDELIM;
110         char            alignment = 'i';        /* default alignment */
111         char            storage = 'p';  /* default TOAST storage method */
112         Oid                     inputOid;
113         Oid                     outputOid;
114         Oid                     receiveOid = InvalidOid;
115         Oid                     sendOid = InvalidOid;
116         Oid                     analyzeOid = InvalidOid;
117         char       *shadow_type;
118         ListCell   *pl;
119         Oid                     typoid;
120         Oid                     resulttype;
121
122         /* Convert list of names to a name and namespace */
123         typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
124
125         /* Check we have creation rights in target namespace */
126         aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
127         if (aclresult != ACLCHECK_OK)
128                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
129                                            get_namespace_name(typeNamespace));
130
131         /*
132          * Type names must be one character shorter than other names, allowing
133          * room to create the corresponding array type name with prepended "_".
134          */
135         if (strlen(typeName) > (NAMEDATALEN - 2))
136                 ereport(ERROR,
137                                 (errcode(ERRCODE_INVALID_NAME),
138                                  errmsg("type names must be %d characters or less",
139                                                 NAMEDATALEN - 2)));
140
141         /*
142          * Look to see if type already exists (presumably as a shell; if not,
143          * TypeCreate will complain).  If it doesn't, create it as a shell, so
144          * that the OID is known for use in the I/O function definitions.
145          */
146         typoid = GetSysCacheOid(TYPENAMENSP,
147                                                         CStringGetDatum(typeName),
148                                                         ObjectIdGetDatum(typeNamespace),
149                                                         0, 0);
150         if (!OidIsValid(typoid))
151         {
152                 typoid = TypeShellMake(typeName, typeNamespace);
153                 /* Make new shell type visible for modification below */
154                 CommandCounterIncrement();
155
156                 /*
157                  * If the command was a parameterless CREATE TYPE, we're done ---
158                  * creating the shell type was all we're supposed to do.
159                  */
160                 if (parameters == NIL)
161                         return;
162         }
163         else
164         {
165                 /* Complain if dummy CREATE TYPE and entry already exists */
166                 if (parameters == NIL)
167                         ereport(ERROR,
168                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
169                                          errmsg("type \"%s\" already exists", typeName)));
170         }
171
172         foreach(pl, parameters)
173         {
174                 DefElem    *defel = (DefElem *) lfirst(pl);
175
176                 if (pg_strcasecmp(defel->defname, "internallength") == 0)
177                         internalLength = defGetTypeLength(defel);
178                 else if (pg_strcasecmp(defel->defname, "externallength") == 0)
179                         ;                                       /* ignored -- remove after 7.3 */
180                 else if (pg_strcasecmp(defel->defname, "input") == 0)
181                         inputName = defGetQualifiedName(defel);
182                 else if (pg_strcasecmp(defel->defname, "output") == 0)
183                         outputName = defGetQualifiedName(defel);
184                 else if (pg_strcasecmp(defel->defname, "receive") == 0)
185                         receiveName = defGetQualifiedName(defel);
186                 else if (pg_strcasecmp(defel->defname, "send") == 0)
187                         sendName = defGetQualifiedName(defel);
188                 else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
189                                  pg_strcasecmp(defel->defname, "analyse") == 0)
190                         analyzeName = defGetQualifiedName(defel);
191                 else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
192                 {
193                         char       *p = defGetString(defel);
194
195                         delimiter = p[0];
196                 }
197                 else if (pg_strcasecmp(defel->defname, "element") == 0)
198                 {
199                         elemType = typenameTypeId(NULL, defGetTypeName(defel));
200                         /* disallow arrays of pseudotypes */
201                         if (get_typtype(elemType) == 'p')
202                                 ereport(ERROR,
203                                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
204                                                  errmsg("array element type cannot be %s",
205                                                                 format_type_be(elemType))));
206                 }
207                 else if (pg_strcasecmp(defel->defname, "default") == 0)
208                         defaultValue = defGetString(defel);
209                 else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
210                         byValue = defGetBoolean(defel);
211                 else if (pg_strcasecmp(defel->defname, "alignment") == 0)
212                 {
213                         char       *a = defGetString(defel);
214
215                         /*
216                          * Note: if argument was an unquoted identifier, parser will have
217                          * applied translations to it, so be prepared to recognize
218                          * translated type names as well as the nominal form.
219                          */
220                         if (pg_strcasecmp(a, "double") == 0 ||
221                                 pg_strcasecmp(a, "float8") == 0 ||
222                                 pg_strcasecmp(a, "pg_catalog.float8") == 0)
223                                 alignment = 'd';
224                         else if (pg_strcasecmp(a, "int4") == 0 ||
225                                          pg_strcasecmp(a, "pg_catalog.int4") == 0)
226                                 alignment = 'i';
227                         else if (pg_strcasecmp(a, "int2") == 0 ||
228                                          pg_strcasecmp(a, "pg_catalog.int2") == 0)
229                                 alignment = 's';
230                         else if (pg_strcasecmp(a, "char") == 0 ||
231                                          pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
232                                 alignment = 'c';
233                         else
234                                 ereport(ERROR,
235                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
236                                                  errmsg("alignment \"%s\" not recognized", a)));
237                 }
238                 else if (pg_strcasecmp(defel->defname, "storage") == 0)
239                 {
240                         char       *a = defGetString(defel);
241
242                         if (pg_strcasecmp(a, "plain") == 0)
243                                 storage = 'p';
244                         else if (pg_strcasecmp(a, "external") == 0)
245                                 storage = 'e';
246                         else if (pg_strcasecmp(a, "extended") == 0)
247                                 storage = 'x';
248                         else if (pg_strcasecmp(a, "main") == 0)
249                                 storage = 'm';
250                         else
251                                 ereport(ERROR,
252                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
253                                                  errmsg("storage \"%s\" not recognized", a)));
254                 }
255                 else
256                         ereport(WARNING,
257                                         (errcode(ERRCODE_SYNTAX_ERROR),
258                                          errmsg("type attribute \"%s\" not recognized",
259                                                         defel->defname)));
260         }
261
262         /*
263          * make sure we have our required definitions
264          */
265         if (inputName == NIL)
266                 ereport(ERROR,
267                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
268                                  errmsg("type input function must be specified")));
269         if (outputName == NIL)
270                 ereport(ERROR,
271                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
272                                  errmsg("type output function must be specified")));
273
274         /*
275          * Convert I/O proc names to OIDs
276          */
277         inputOid = findTypeInputFunction(inputName, typoid);
278         outputOid = findTypeOutputFunction(outputName, typoid);
279         if (receiveName)
280                 receiveOid = findTypeReceiveFunction(receiveName, typoid);
281         if (sendName)
282                 sendOid = findTypeSendFunction(sendName, typoid);
283
284         /*
285          * Verify that I/O procs return the expected thing.  If we see OPAQUE,
286          * complain and change it to the correct type-safe choice.
287          */
288         resulttype = get_func_rettype(inputOid);
289         if (resulttype != typoid)
290         {
291                 if (resulttype == OPAQUEOID)
292                 {
293                         /* backwards-compatibility hack */
294                         ereport(WARNING,
295                                         (errmsg("changing return type of function %s from \"opaque\" to %s",
296                                                         NameListToString(inputName), typeName)));
297                         SetFunctionReturnType(inputOid, typoid);
298                 }
299                 else
300                         ereport(ERROR,
301                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
302                                          errmsg("type input function %s must return type %s",
303                                                         NameListToString(inputName), typeName)));
304         }
305         resulttype = get_func_rettype(outputOid);
306         if (resulttype != CSTRINGOID)
307         {
308                 if (resulttype == OPAQUEOID)
309                 {
310                         /* backwards-compatibility hack */
311                         ereport(WARNING,
312                                         (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
313                                                         NameListToString(outputName))));
314                         SetFunctionReturnType(outputOid, CSTRINGOID);
315                 }
316                 else
317                         ereport(ERROR,
318                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
319                            errmsg("type output function %s must return type \"cstring\"",
320                                           NameListToString(outputName))));
321         }
322         if (receiveOid)
323         {
324                 resulttype = get_func_rettype(receiveOid);
325                 if (resulttype != typoid)
326                         ereport(ERROR,
327                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
328                                          errmsg("type receive function %s must return type %s",
329                                                         NameListToString(receiveName), typeName)));
330         }
331         if (sendOid)
332         {
333                 resulttype = get_func_rettype(sendOid);
334                 if (resulttype != BYTEAOID)
335                         ereport(ERROR,
336                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
337                                    errmsg("type send function %s must return type \"bytea\"",
338                                                   NameListToString(sendName))));
339         }
340
341         /*
342          * Convert analysis function proc name to an OID. If no analysis function
343          * is specified, we'll use zero to select the built-in default algorithm.
344          */
345         if (analyzeName)
346                 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
347
348         /*
349          * Check permissions on functions.  We choose to require the creator/owner
350          * of a type to also own the underlying functions.  Since creating a type
351          * is tantamount to granting public execute access on the functions, the
352          * minimum sane check would be for execute-with-grant-option.  But we don't
353          * have a way to make the type go away if the grant option is revoked, so
354          * ownership seems better.
355          */
356         if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
357                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
358                                            NameListToString(inputName));
359         if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
360                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
361                                            NameListToString(outputName));
362         if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
363                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
364                                            NameListToString(receiveName));
365         if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
366                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
367                                            NameListToString(sendName));
368         if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
369                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
370                                            NameListToString(analyzeName));
371
372         /*
373          * now have TypeCreate do all the real work.
374          */
375         typoid =
376                 TypeCreate(typeName,    /* type name */
377                                    typeNamespace,               /* namespace */
378                                    InvalidOid,  /* relation oid (n/a here) */
379                                    0,                   /* relation kind (ditto) */
380                                    internalLength,              /* internal size */
381                                    'b',                 /* type-type (base type) */
382                                    delimiter,   /* array element delimiter */
383                                    inputOid,    /* input procedure */
384                                    outputOid,   /* output procedure */
385                                    receiveOid,  /* receive procedure */
386                                    sendOid,             /* send procedure */
387                                    analyzeOid,  /* analyze procedure */
388                                    elemType,    /* element type ID */
389                                    InvalidOid,  /* base type ID (only for domains) */
390                                    defaultValue,        /* default type value */
391                                    NULL,                /* no binary form available */
392                                    byValue,             /* passed by value */
393                                    alignment,   /* required alignment */
394                                    storage,             /* TOAST strategy */
395                                    -1,                  /* typMod (Domains only) */
396                                    0,                   /* Array Dimensions of typbasetype */
397                                    false);              /* Type NOT NULL */
398
399         /*
400          * When we create a base type (as opposed to a complex type) we need to
401          * have an array entry for it in pg_type as well.
402          */
403         shadow_type = makeArrayTypeName(typeName);
404
405         /* alignment must be 'i' or 'd' for arrays */
406         alignment = (alignment == 'd') ? 'd' : 'i';
407
408         TypeCreate(shadow_type,         /* type name */
409                            typeNamespace,       /* namespace */
410                            InvalidOid,          /* relation oid (n/a here) */
411                            0,                           /* relation kind (ditto) */
412                            -1,                          /* internal size */
413                            'b',                         /* type-type (base type) */
414                            DEFAULT_TYPDELIM,    /* array element delimiter */
415                            F_ARRAY_IN,          /* input procedure */
416                            F_ARRAY_OUT,         /* output procedure */
417                            F_ARRAY_RECV,        /* receive procedure */
418                            F_ARRAY_SEND,        /* send procedure */
419                            InvalidOid,          /* analyze procedure - default */
420                            typoid,                      /* element type ID */
421                            InvalidOid,          /* base type ID */
422                            NULL,                        /* never a default type value */
423                            NULL,                        /* binary default isn't sent either */
424                            false,                       /* never passed by value */
425                            alignment,           /* see above */
426                            'x',                         /* ARRAY is always toastable */
427                            -1,                          /* typMod (Domains only) */
428                            0,                           /* Array dimensions of typbasetype */
429                            false);                      /* Type NOT NULL */
430
431         pfree(shadow_type);
432 }
433
434
435 /*
436  *      RemoveType
437  *              Removes a datatype.
438  */
439 void
440 RemoveType(List *names, DropBehavior behavior, bool missing_ok)
441 {
442         TypeName   *typename;
443         Oid                     typeoid;
444         HeapTuple       tup;
445         ObjectAddress object;
446
447         /* Make a TypeName so we can use standard type lookup machinery */
448         typename = makeTypeNameFromNameList(names);
449
450         /* Use LookupTypeName here so that shell types can be removed. */
451         typeoid = LookupTypeName(NULL, typename);
452         if (!OidIsValid(typeoid))
453         {
454                 if (!missing_ok)
455                 {
456                         ereport(ERROR,
457                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
458                                          errmsg("type \"%s\" does not exist",
459                                                         TypeNameToString(typename))));
460                 }
461                 else
462                 {
463                         ereport(NOTICE,
464                                         (errmsg("type \"%s\" does not exist, skipping",
465                                                         TypeNameToString(typename))));
466                 }
467
468                 return;
469         }
470
471         tup = SearchSysCache(TYPEOID,
472                                                  ObjectIdGetDatum(typeoid),
473                                                  0, 0, 0);
474         if (!HeapTupleIsValid(tup))
475                 elog(ERROR, "cache lookup failed for type %u", typeoid);
476
477         /* Permission check: must own type or its namespace */
478         if (!pg_type_ownercheck(typeoid, GetUserId()) &&
479           !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace,
480                                                            GetUserId()))
481                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
482                                            TypeNameToString(typename));
483
484         ReleaseSysCache(tup);
485
486         /*
487          * Do the deletion
488          */
489         object.classId = TypeRelationId;
490         object.objectId = typeoid;
491         object.objectSubId = 0;
492
493         performDeletion(&object, behavior);
494 }
495
496
497 /*
498  * Guts of type deletion.
499  */
500 void
501 RemoveTypeById(Oid typeOid)
502 {
503         Relation        relation;
504         HeapTuple       tup;
505
506         relation = heap_open(TypeRelationId, RowExclusiveLock);
507
508         tup = SearchSysCache(TYPEOID,
509                                                  ObjectIdGetDatum(typeOid),
510                                                  0, 0, 0);
511         if (!HeapTupleIsValid(tup))
512                 elog(ERROR, "cache lookup failed for type %u", typeOid);
513
514         simple_heap_delete(relation, &tup->t_self);
515
516         ReleaseSysCache(tup);
517
518         heap_close(relation, RowExclusiveLock);
519 }
520
521
522 /*
523  * DefineDomain
524  *              Registers a new domain.
525  */
526 void
527 DefineDomain(CreateDomainStmt *stmt)
528 {
529         char       *domainName;
530         Oid                     domainNamespace;
531         AclResult       aclresult;
532         int16           internalLength;
533         Oid                     inputProcedure;
534         Oid                     outputProcedure;
535         Oid                     receiveProcedure;
536         Oid                     sendProcedure;
537         Oid                     analyzeProcedure;
538         bool            byValue;
539         Oid                     typelem;
540         char            delimiter;
541         char            alignment;
542         char            storage;
543         char            typtype;
544         Datum           datum;
545         bool            isnull;
546         Node       *defaultExpr = NULL;
547         char       *defaultValue = NULL;
548         char       *defaultValueBin = NULL;
549         bool            typNotNull = false;
550         bool            nullDefined = false;
551         int32           typNDims = list_length(stmt->typename->arrayBounds);
552         HeapTuple       typeTup;
553         List       *schema = stmt->constraints;
554         ListCell   *listptr;
555         Oid                     basetypeoid;
556         Oid                     domainoid;
557         Form_pg_type baseType;
558
559         /* Convert list of names to a name and namespace */
560         domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
561                                                                                                                 &domainName);
562
563         /* Check we have creation rights in target namespace */
564         aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
565                                                                           ACL_CREATE);
566         if (aclresult != ACLCHECK_OK)
567                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
568                                            get_namespace_name(domainNamespace));
569
570         /*
571          * Domainnames, unlike typenames don't need to account for the '_' prefix.
572          * So they can be one character longer.  (This test is presently useless
573          * since the parser will have truncated the name to fit.  But leave it
574          * here since we may someday support arrays of domains, in which case
575          * we'll be back to needing to enforce NAMEDATALEN-2.)
576          */
577         if (strlen(domainName) > (NAMEDATALEN - 1))
578                 ereport(ERROR,
579                                 (errcode(ERRCODE_INVALID_NAME),
580                                  errmsg("domain names must be %d characters or less",
581                                                 NAMEDATALEN - 1)));
582
583         /*
584          * Look up the base type.
585          */
586         typeTup = typenameType(NULL, stmt->typename);
587
588         baseType = (Form_pg_type) GETSTRUCT(typeTup);
589         basetypeoid = HeapTupleGetOid(typeTup);
590
591         /*
592          * Base type must be a plain base type or another domain.  Domains over
593          * pseudotypes would create a security hole.  Domains over composite
594          * types might be made to work in the future, but not today.
595          */
596         typtype = baseType->typtype;
597         if (typtype != 'b' && typtype != 'd')
598                 ereport(ERROR,
599                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
600                                  errmsg("\"%s\" is not a valid base type for a domain",
601                                                 TypeNameToString(stmt->typename))));
602
603         /* passed by value */
604         byValue = baseType->typbyval;
605
606         /* Required Alignment */
607         alignment = baseType->typalign;
608
609         /* TOAST Strategy */
610         storage = baseType->typstorage;
611
612         /* Storage Length */
613         internalLength = baseType->typlen;
614
615         /* Array element type (in case base type is an array) */
616         typelem = baseType->typelem;
617
618         /* Array element Delimiter */
619         delimiter = baseType->typdelim;
620
621         /* I/O Functions */
622         inputProcedure = F_DOMAIN_IN;
623         outputProcedure = baseType->typoutput;
624         receiveProcedure = F_DOMAIN_RECV;
625         sendProcedure = baseType->typsend;
626
627         /* Analysis function */
628         analyzeProcedure = baseType->typanalyze;
629
630         /* Inherited default value */
631         datum = SysCacheGetAttr(TYPEOID, typeTup,
632                                                         Anum_pg_type_typdefault, &isnull);
633         if (!isnull)
634                 defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum));
635
636         /* Inherited default binary value */
637         datum = SysCacheGetAttr(TYPEOID, typeTup,
638                                                         Anum_pg_type_typdefaultbin, &isnull);
639         if (!isnull)
640                 defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum));
641
642         /*
643          * Run through constraints manually to avoid the additional processing
644          * conducted by DefineRelation() and friends.
645          */
646         foreach(listptr, schema)
647         {
648                 Node       *newConstraint = lfirst(listptr);
649                 Constraint *constr;
650                 ParseState *pstate;
651
652                 /* Check for unsupported constraint types */
653                 if (IsA(newConstraint, FkConstraint))
654                         ereport(ERROR,
655                                         (errcode(ERRCODE_SYNTAX_ERROR),
656                                 errmsg("foreign key constraints not possible for domains")));
657
658                 /* otherwise it should be a plain Constraint */
659                 if (!IsA(newConstraint, Constraint))
660                         elog(ERROR, "unrecognized node type: %d",
661                                  (int) nodeTag(newConstraint));
662
663                 constr = (Constraint *) newConstraint;
664
665                 switch (constr->contype)
666                 {
667                         case CONSTR_DEFAULT:
668
669                                 /*
670                                  * The inherited default value may be overridden by the user
671                                  * with the DEFAULT <expr> statement.
672                                  */
673                                 if (defaultExpr)
674                                         ereport(ERROR,
675                                                         (errcode(ERRCODE_SYNTAX_ERROR),
676                                                          errmsg("multiple default expressions")));
677
678                                 /* Create a dummy ParseState for transformExpr */
679                                 pstate = make_parsestate(NULL);
680
681                                 /*
682                                  * Cook the constr->raw_expr into an expression. Note: Name is
683                                  * strictly for error message
684                                  */
685                                 defaultExpr = cookDefault(pstate, constr->raw_expr,
686                                                                                   basetypeoid,
687                                                                                   stmt->typename->typmod,
688                                                                                   domainName);
689
690                                 /*
691                                  * Expression must be stored as a nodeToString result, but we
692                                  * also require a valid textual representation (mainly to make
693                                  * life easier for pg_dump).
694                                  */
695                                 defaultValue = deparse_expression(defaultExpr,
696                                                                                           deparse_context_for(domainName,
697                                                                                                                                   InvalidOid),
698                                                                                                   false, false);
699                                 defaultValueBin = nodeToString(defaultExpr);
700                                 break;
701
702                         case CONSTR_NOTNULL:
703                                 if (nullDefined && !typNotNull)
704                                         ereport(ERROR,
705                                                         (errcode(ERRCODE_SYNTAX_ERROR),
706                                                    errmsg("conflicting NULL/NOT NULL constraints")));
707                                 typNotNull = true;
708                                 nullDefined = true;
709                                 break;
710
711                         case CONSTR_NULL:
712                                 if (nullDefined && typNotNull)
713                                         ereport(ERROR,
714                                                         (errcode(ERRCODE_SYNTAX_ERROR),
715                                                    errmsg("conflicting NULL/NOT NULL constraints")));
716                                 typNotNull = false;
717                                 nullDefined = true;
718                                 break;
719
720                         case CONSTR_CHECK:
721
722                                 /*
723                                  * Check constraints are handled after domain creation, as
724                                  * they require the Oid of the domain
725                                  */
726                                 break;
727
728                                 /*
729                                  * All else are error cases
730                                  */
731                         case CONSTR_UNIQUE:
732                                 ereport(ERROR,
733                                                 (errcode(ERRCODE_SYNTAX_ERROR),
734                                          errmsg("unique constraints not possible for domains")));
735                                 break;
736
737                         case CONSTR_PRIMARY:
738                                 ereport(ERROR,
739                                                 (errcode(ERRCODE_SYNTAX_ERROR),
740                                 errmsg("primary key constraints not possible for domains")));
741                                 break;
742
743                         case CONSTR_ATTR_DEFERRABLE:
744                         case CONSTR_ATTR_NOT_DEFERRABLE:
745                         case CONSTR_ATTR_DEFERRED:
746                         case CONSTR_ATTR_IMMEDIATE:
747                                 ereport(ERROR,
748                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
749                                                  errmsg("specifying constraint deferrability not supported for domains")));
750                                 break;
751
752                         default:
753                                 elog(ERROR, "unrecognized constraint subtype: %d",
754                                          (int) constr->contype);
755                                 break;
756                 }
757         }
758
759         /*
760          * Have TypeCreate do all the real work.
761          */
762         domainoid =
763                 TypeCreate(domainName,  /* type name */
764                                    domainNamespace,             /* namespace */
765                                    InvalidOid,  /* relation oid (n/a here) */
766                                    0,                   /* relation kind (ditto) */
767                                    internalLength,              /* internal size */
768                                    'd',                 /* type-type (domain type) */
769                                    delimiter,   /* array element delimiter */
770                                    inputProcedure,              /* input procedure */
771                                    outputProcedure,             /* output procedure */
772                                    receiveProcedure,    /* receive procedure */
773                                    sendProcedure,               /* send procedure */
774                                    analyzeProcedure,    /* analyze procedure */
775                                    typelem,             /* element type ID */
776                                    basetypeoid, /* base type ID */
777                                    defaultValue,        /* default type value (text) */
778                                    defaultValueBin,             /* default type value (binary) */
779                                    byValue,             /* passed by value */
780                                    alignment,   /* required alignment */
781                                    storage,             /* TOAST strategy */
782                                    stmt->typename->typmod,              /* typeMod value */
783                                    typNDims,    /* Array dimensions for base type */
784                                    typNotNull); /* Type NOT NULL */
785
786         /*
787          * Process constraints which refer to the domain ID returned by TypeCreate
788          */
789         foreach(listptr, schema)
790         {
791                 Constraint *constr = lfirst(listptr);
792
793                 /* it must be a Constraint, per check above */
794
795                 switch (constr->contype)
796                 {
797                         case CONSTR_CHECK:
798                                 domainAddConstraint(domainoid, domainNamespace,
799                                                                         basetypeoid, stmt->typename->typmod,
800                                                                         constr, domainName);
801                                 break;
802
803                                 /* Other constraint types were fully processed above */
804
805                         default:
806                                 break;
807                 }
808
809                 /* CCI so we can detect duplicate constraint names */
810                 CommandCounterIncrement();
811         }
812
813         /*
814          * Now we can clean up.
815          */
816         ReleaseSysCache(typeTup);
817 }
818
819
820 /*
821  *      RemoveDomain
822  *              Removes a domain.
823  *
824  * This is identical to RemoveType except we insist it be a domain.
825  */
826 void
827 RemoveDomain(List *names, DropBehavior behavior, bool missing_ok)
828 {
829         TypeName   *typename;
830         Oid                     typeoid;
831         HeapTuple       tup;
832         char            typtype;
833         ObjectAddress object;
834
835         /* Make a TypeName so we can use standard type lookup machinery */
836         typename = makeTypeNameFromNameList(names);
837
838         /* Use LookupTypeName here so that shell types can be removed. */
839         typeoid = LookupTypeName(NULL, typename);
840         if (!OidIsValid(typeoid))
841         {
842                 if (!missing_ok)
843                 {
844                         ereport(ERROR,
845                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
846                                          errmsg("type \"%s\" does not exist",
847                                                         TypeNameToString(typename))));
848                 }
849                 else
850                 {
851                         ereport(NOTICE,
852                                         (errmsg("type \"%s\" does not exist, skipping",
853                                                         TypeNameToString(typename))));
854                 }
855
856                 return;
857         }
858
859         tup = SearchSysCache(TYPEOID,
860                                                  ObjectIdGetDatum(typeoid),
861                                                  0, 0, 0);
862         if (!HeapTupleIsValid(tup))
863                 elog(ERROR, "cache lookup failed for type %u", typeoid);
864
865         /* Permission check: must own type or its namespace */
866         if (!pg_type_ownercheck(typeoid, GetUserId()) &&
867           !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace,
868                                                            GetUserId()))
869                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
870                                            TypeNameToString(typename));
871
872         /* Check that this is actually a domain */
873         typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
874
875         if (typtype != 'd')
876                 ereport(ERROR,
877                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
878                                  errmsg("\"%s\" is not a domain",
879                                                 TypeNameToString(typename))));
880
881         ReleaseSysCache(tup);
882
883         /*
884          * Do the deletion
885          */
886         object.classId = TypeRelationId;
887         object.objectId = typeoid;
888         object.objectSubId = 0;
889
890         performDeletion(&object, behavior);
891 }
892
893
894 /*
895  * Find suitable I/O functions for a type.
896  *
897  * typeOid is the type's OID (which will already exist, if only as a shell
898  * type).
899  */
900
901 static Oid
902 findTypeInputFunction(List *procname, Oid typeOid)
903 {
904         Oid                     argList[3];
905         Oid                     procOid;
906
907         /*
908          * Input functions can take a single argument of type CSTRING, or three
909          * arguments (string, typioparam OID, typmod).
910          *
911          * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
912          * see this, we issue a warning and fix up the pg_proc entry.
913          */
914         argList[0] = CSTRINGOID;
915
916         procOid = LookupFuncName(procname, 1, argList, true);
917         if (OidIsValid(procOid))
918                 return procOid;
919
920         argList[1] = OIDOID;
921         argList[2] = INT4OID;
922
923         procOid = LookupFuncName(procname, 3, argList, true);
924         if (OidIsValid(procOid))
925                 return procOid;
926
927         /* No luck, try it with OPAQUE */
928         argList[0] = OPAQUEOID;
929
930         procOid = LookupFuncName(procname, 1, argList, true);
931
932         if (!OidIsValid(procOid))
933         {
934                 argList[1] = OIDOID;
935                 argList[2] = INT4OID;
936
937                 procOid = LookupFuncName(procname, 3, argList, true);
938         }
939
940         if (OidIsValid(procOid))
941         {
942                 /* Found, but must complain and fix the pg_proc entry */
943                 ereport(WARNING,
944                                 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
945                                                 NameListToString(procname))));
946                 SetFunctionArgType(procOid, 0, CSTRINGOID);
947
948                 /*
949                  * Need CommandCounterIncrement since DefineType will likely try to
950                  * alter the pg_proc tuple again.
951                  */
952                 CommandCounterIncrement();
953
954                 return procOid;
955         }
956
957         /* Use CSTRING (preferred) in the error message */
958         argList[0] = CSTRINGOID;
959
960         ereport(ERROR,
961                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
962                          errmsg("function %s does not exist",
963                                         func_signature_string(procname, 1, argList))));
964
965         return InvalidOid;                      /* keep compiler quiet */
966 }
967
968 static Oid
969 findTypeOutputFunction(List *procname, Oid typeOid)
970 {
971         Oid                     argList[1];
972         Oid                     procOid;
973
974         /*
975          * Output functions can take a single argument of the type.
976          *
977          * For backwards compatibility we allow OPAQUE in place of the actual type
978          * name; if we see this, we issue a warning and fix up the pg_proc entry.
979          */
980         argList[0] = typeOid;
981
982         procOid = LookupFuncName(procname, 1, argList, true);
983         if (OidIsValid(procOid))
984                 return procOid;
985
986         /* No luck, try it with OPAQUE */
987         argList[0] = OPAQUEOID;
988
989         procOid = LookupFuncName(procname, 1, argList, true);
990
991         if (OidIsValid(procOid))
992         {
993                 /* Found, but must complain and fix the pg_proc entry */
994                 ereport(WARNING,
995                 (errmsg("changing argument type of function %s from \"opaque\" to %s",
996                                 NameListToString(procname), format_type_be(typeOid))));
997                 SetFunctionArgType(procOid, 0, typeOid);
998
999                 /*
1000                  * Need CommandCounterIncrement since DefineType will likely try to
1001                  * alter the pg_proc tuple again.
1002                  */
1003                 CommandCounterIncrement();
1004
1005                 return procOid;
1006         }
1007
1008         /* Use type name, not OPAQUE, in the failure message. */
1009         argList[0] = typeOid;
1010
1011         ereport(ERROR,
1012                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
1013                          errmsg("function %s does not exist",
1014                                         func_signature_string(procname, 1, argList))));
1015
1016         return InvalidOid;                      /* keep compiler quiet */
1017 }
1018
1019 static Oid
1020 findTypeReceiveFunction(List *procname, Oid typeOid)
1021 {
1022         Oid                     argList[3];
1023         Oid                     procOid;
1024
1025         /*
1026          * Receive functions can take a single argument of type INTERNAL, or three
1027          * arguments (internal, typioparam OID, typmod).
1028          */
1029         argList[0] = INTERNALOID;
1030
1031         procOid = LookupFuncName(procname, 1, argList, true);
1032         if (OidIsValid(procOid))
1033                 return procOid;
1034
1035         argList[1] = OIDOID;
1036         argList[2] = INT4OID;
1037
1038         procOid = LookupFuncName(procname, 3, argList, true);
1039         if (OidIsValid(procOid))
1040                 return procOid;
1041
1042         ereport(ERROR,
1043                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
1044                          errmsg("function %s does not exist",
1045                                         func_signature_string(procname, 1, argList))));
1046
1047         return InvalidOid;                      /* keep compiler quiet */
1048 }
1049
1050 static Oid
1051 findTypeSendFunction(List *procname, Oid typeOid)
1052 {
1053         Oid                     argList[1];
1054         Oid                     procOid;
1055
1056         /*
1057          * Send functions can take a single argument of the type.
1058          */
1059         argList[0] = typeOid;
1060
1061         procOid = LookupFuncName(procname, 1, argList, true);
1062         if (OidIsValid(procOid))
1063                 return procOid;
1064
1065         ereport(ERROR,
1066                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
1067                          errmsg("function %s does not exist",
1068                                         func_signature_string(procname, 1, argList))));
1069
1070         return InvalidOid;                      /* keep compiler quiet */
1071 }
1072
1073 static Oid
1074 findTypeAnalyzeFunction(List *procname, Oid typeOid)
1075 {
1076         Oid                     argList[1];
1077         Oid                     procOid;
1078
1079         /*
1080          * Analyze functions always take one INTERNAL argument and return bool.
1081          */
1082         argList[0] = INTERNALOID;
1083
1084         procOid = LookupFuncName(procname, 1, argList, true);
1085         if (!OidIsValid(procOid))
1086                 ereport(ERROR,
1087                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1088                                  errmsg("function %s does not exist",
1089                                                 func_signature_string(procname, 1, argList))));
1090
1091         if (get_func_rettype(procOid) != BOOLOID)
1092                 ereport(ERROR,
1093                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1094                           errmsg("type analyze function %s must return type \"boolean\"",
1095                                          NameListToString(procname))));
1096
1097         return procOid;
1098 }
1099
1100
1101 /*-------------------------------------------------------------------
1102  * DefineCompositeType
1103  *
1104  * Create a Composite Type relation.
1105  * `DefineRelation' does all the work, we just provide the correct
1106  * arguments!
1107  *
1108  * If the relation already exists, then 'DefineRelation' will abort
1109  * the xact...
1110  *
1111  * DefineCompositeType returns relid for use when creating
1112  * an implicit composite type during function creation
1113  *-------------------------------------------------------------------
1114  */
1115 Oid
1116 DefineCompositeType(const RangeVar *typevar, List *coldeflist)
1117 {
1118         CreateStmt *createStmt = makeNode(CreateStmt);
1119
1120         if (coldeflist == NIL)
1121                 ereport(ERROR,
1122                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1123                                  errmsg("composite type must have at least one attribute")));
1124
1125         /*
1126          * now set the parameters for keys/inheritance etc. All of these are
1127          * uninteresting for composite types...
1128          */
1129         createStmt->relation = (RangeVar *) typevar;
1130         createStmt->tableElts = coldeflist;
1131         createStmt->inhRelations = NIL;
1132         createStmt->constraints = NIL;
1133         createStmt->hasoids = MUST_NOT_HAVE_OIDS;
1134         createStmt->oncommit = ONCOMMIT_NOOP;
1135         createStmt->tablespacename = NULL;
1136
1137         /*
1138          * finally create the relation...
1139          */
1140         return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);
1141 }
1142
1143 /*
1144  * AlterDomainDefault
1145  *
1146  * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
1147  */
1148 void
1149 AlterDomainDefault(List *names, Node *defaultRaw)
1150 {
1151         TypeName   *typename;
1152         Oid                     domainoid;
1153         HeapTuple       tup;
1154         ParseState *pstate;
1155         Relation        rel;
1156         char       *defaultValue;
1157         Node       *defaultExpr = NULL;         /* NULL if no default specified */
1158         Datum           new_record[Natts_pg_type];
1159         char            new_record_nulls[Natts_pg_type];
1160         char            new_record_repl[Natts_pg_type];
1161         HeapTuple       newtuple;
1162         Form_pg_type typTup;
1163
1164         /* Make a TypeName so we can use standard type lookup machinery */
1165         typename = makeTypeNameFromNameList(names);
1166         domainoid = typenameTypeId(NULL, typename);
1167
1168         /* Look up the domain in the type table */
1169         rel = heap_open(TypeRelationId, RowExclusiveLock);
1170
1171         tup = SearchSysCacheCopy(TYPEOID,
1172                                                          ObjectIdGetDatum(domainoid),
1173                                                          0, 0, 0);
1174         if (!HeapTupleIsValid(tup))
1175                 elog(ERROR, "cache lookup failed for type %u", domainoid);
1176         typTup = (Form_pg_type) GETSTRUCT(tup);
1177
1178         /* Check it's a domain and check user has permission for ALTER DOMAIN */
1179         checkDomainOwner(tup, typename);
1180
1181         /* Setup new tuple */
1182         MemSet(new_record, (Datum) 0, sizeof(new_record));
1183         MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
1184         MemSet(new_record_repl, ' ', sizeof(new_record_repl));
1185
1186         /* Store the new default, if null then skip this step */
1187         if (defaultRaw)
1188         {
1189                 /* Create a dummy ParseState for transformExpr */
1190                 pstate = make_parsestate(NULL);
1191
1192                 /*
1193                  * Cook the colDef->raw_expr into an expression. Note: Name is
1194                  * strictly for error message
1195                  */
1196                 defaultExpr = cookDefault(pstate, defaultRaw,
1197                                                                   typTup->typbasetype,
1198                                                                   typTup->typtypmod,
1199                                                                   NameStr(typTup->typname));
1200
1201                 /*
1202                  * Expression must be stored as a nodeToString result, but we also
1203                  * require a valid textual representation (mainly to make life easier
1204                  * for pg_dump).
1205                  */
1206                 defaultValue = deparse_expression(defaultExpr,
1207                                                                 deparse_context_for(NameStr(typTup->typname),
1208                                                                                                         InvalidOid),
1209                                                                                   false, false);
1210
1211                 /*
1212                  * Form an updated tuple with the new default and write it back.
1213                  */
1214                 new_record[Anum_pg_type_typdefaultbin - 1] = DirectFunctionCall1(textin,
1215                                                                                                                          CStringGetDatum(
1216                                                                                                  nodeToString(defaultExpr)));
1217
1218                 new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
1219                 new_record[Anum_pg_type_typdefault - 1] = DirectFunctionCall1(textin,
1220                                                                                           CStringGetDatum(defaultValue));
1221                 new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
1222         }
1223         else
1224                 /* Default is NULL, drop it */
1225         {
1226                 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = 'n';
1227                 new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';
1228                 new_record_nulls[Anum_pg_type_typdefault - 1] = 'n';
1229                 new_record_repl[Anum_pg_type_typdefault - 1] = 'r';
1230         }
1231
1232         newtuple = heap_modifytuple(tup, RelationGetDescr(rel),
1233                                                                 new_record, new_record_nulls,
1234                                                                 new_record_repl);
1235
1236         simple_heap_update(rel, &tup->t_self, newtuple);
1237
1238         CatalogUpdateIndexes(rel, newtuple);
1239
1240         /* Rebuild dependencies */
1241         GenerateTypeDependencies(typTup->typnamespace,
1242                                                          domainoid,
1243                                                          typTup->typrelid,
1244                                                          0, /* relation kind is n/a */
1245                                                          typTup->typowner,
1246                                                          typTup->typinput,
1247                                                          typTup->typoutput,
1248                                                          typTup->typreceive,
1249                                                          typTup->typsend,
1250                                                          typTup->typanalyze,
1251                                                          typTup->typelem,
1252                                                          typTup->typbasetype,
1253                                                          defaultExpr,
1254                                                          true);         /* Rebuild is true */
1255
1256         /* Clean up */
1257         heap_close(rel, NoLock);
1258         heap_freetuple(newtuple);
1259 }
1260
1261 /*
1262  * AlterDomainNotNull
1263  *
1264  * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
1265  */
1266 void
1267 AlterDomainNotNull(List *names, bool notNull)
1268 {
1269         TypeName   *typename;
1270         Oid                     domainoid;
1271         Relation        typrel;
1272         HeapTuple       tup;
1273         Form_pg_type typTup;
1274
1275         /* Make a TypeName so we can use standard type lookup machinery */
1276         typename = makeTypeNameFromNameList(names);
1277         domainoid = typenameTypeId(NULL, typename);
1278
1279         /* Look up the domain in the type table */
1280         typrel = heap_open(TypeRelationId, RowExclusiveLock);
1281
1282         tup = SearchSysCacheCopy(TYPEOID,
1283                                                          ObjectIdGetDatum(domainoid),
1284                                                          0, 0, 0);
1285         if (!HeapTupleIsValid(tup))
1286                 elog(ERROR, "cache lookup failed for type %u", domainoid);
1287         typTup = (Form_pg_type) GETSTRUCT(tup);
1288
1289         /* Check it's a domain and check user has permission for ALTER DOMAIN */
1290         checkDomainOwner(tup, typename);
1291
1292         /* Is the domain already set to the desired constraint? */
1293         if (typTup->typnotnull == notNull)
1294         {
1295                 heap_close(typrel, RowExclusiveLock);
1296                 return;
1297         }
1298
1299         /* Adding a NOT NULL constraint requires checking existing columns */
1300         if (notNull)
1301         {
1302                 List       *rels;
1303                 ListCell   *rt;
1304
1305                 /* Fetch relation list with attributes based on this domain */
1306                 /* ShareLock is sufficient to prevent concurrent data changes */
1307
1308                 rels = get_rels_with_domain(domainoid, ShareLock);
1309
1310                 foreach(rt, rels)
1311                 {
1312                         RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1313                         Relation        testrel = rtc->rel;
1314                         TupleDesc       tupdesc = RelationGetDescr(testrel);
1315                         HeapScanDesc scan;
1316                         HeapTuple       tuple;
1317
1318                         /* Scan all tuples in this relation */
1319                         scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1320                         while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1321                         {
1322                                 int                     i;
1323
1324                                 /* Test attributes that are of the domain */
1325                                 for (i = 0; i < rtc->natts; i++)
1326                                 {
1327                                         int                     attnum = rtc->atts[i];
1328
1329                                         if (heap_attisnull(tuple, attnum))
1330                                                 ereport(ERROR,
1331                                                                 (errcode(ERRCODE_NOT_NULL_VIOLATION),
1332                                                                  errmsg("column \"%s\" of table \"%s\" contains null values",
1333                                                                 NameStr(tupdesc->attrs[attnum - 1]->attname),
1334                                                                                 RelationGetRelationName(testrel))));
1335                                 }
1336                         }
1337                         heap_endscan(scan);
1338
1339                         /* Close each rel after processing, but keep lock */
1340                         heap_close(testrel, NoLock);
1341                 }
1342         }
1343
1344         /*
1345          * Okay to update pg_type row.  We can scribble on typTup because it's a
1346          * copy.
1347          */
1348         typTup->typnotnull = notNull;
1349
1350         simple_heap_update(typrel, &tup->t_self, tup);
1351
1352         CatalogUpdateIndexes(typrel, tup);
1353
1354         /* Clean up */
1355         heap_freetuple(tup);
1356         heap_close(typrel, RowExclusiveLock);
1357 }
1358
1359 /*
1360  * AlterDomainDropConstraint
1361  *
1362  * Implements the ALTER DOMAIN DROP CONSTRAINT statement
1363  */
1364 void
1365 AlterDomainDropConstraint(List *names, const char *constrName,
1366                                                   DropBehavior behavior)
1367 {
1368         TypeName   *typename;
1369         Oid                     domainoid;
1370         HeapTuple       tup;
1371         Relation        rel;
1372         Relation        conrel;
1373         SysScanDesc conscan;
1374         ScanKeyData key[1];
1375         HeapTuple       contup;
1376
1377         /* Make a TypeName so we can use standard type lookup machinery */
1378         typename = makeTypeNameFromNameList(names);
1379         domainoid = typenameTypeId(NULL, typename);
1380
1381         /* Look up the domain in the type table */
1382         rel = heap_open(TypeRelationId, RowExclusiveLock);
1383
1384         tup = SearchSysCacheCopy(TYPEOID,
1385                                                          ObjectIdGetDatum(domainoid),
1386                                                          0, 0, 0);
1387         if (!HeapTupleIsValid(tup))
1388                 elog(ERROR, "cache lookup failed for type %u", domainoid);
1389
1390         /* Check it's a domain and check user has permission for ALTER DOMAIN */
1391         checkDomainOwner(tup, typename);
1392
1393         /* Grab an appropriate lock on the pg_constraint relation */
1394         conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
1395
1396         /* Use the index to scan only constraints of the target relation */
1397         ScanKeyInit(&key[0],
1398                                 Anum_pg_constraint_contypid,
1399                                 BTEqualStrategyNumber, F_OIDEQ,
1400                                 ObjectIdGetDatum(HeapTupleGetOid(tup)));
1401
1402         conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
1403                                                                  SnapshotNow, 1, key);
1404
1405         /*
1406          * Scan over the result set, removing any matching entries.
1407          */
1408         while ((contup = systable_getnext(conscan)) != NULL)
1409         {
1410                 Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
1411
1412                 if (strcmp(NameStr(con->conname), constrName) == 0)
1413                 {
1414                         ObjectAddress conobj;
1415
1416                         conobj.classId = ConstraintRelationId;
1417                         conobj.objectId = HeapTupleGetOid(contup);
1418                         conobj.objectSubId = 0;
1419
1420                         performDeletion(&conobj, behavior);
1421                 }
1422         }
1423         /* Clean up after the scan */
1424         systable_endscan(conscan);
1425         heap_close(conrel, RowExclusiveLock);
1426
1427         heap_close(rel, NoLock);
1428 }
1429
1430 /*
1431  * AlterDomainAddConstraint
1432  *
1433  * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
1434  */
1435 void
1436 AlterDomainAddConstraint(List *names, Node *newConstraint)
1437 {
1438         TypeName   *typename;
1439         Oid                     domainoid;
1440         Relation        typrel;
1441         HeapTuple       tup;
1442         Form_pg_type typTup;
1443         List       *rels;
1444         ListCell   *rt;
1445         EState     *estate;
1446         ExprContext *econtext;
1447         char       *ccbin;
1448         Expr       *expr;
1449         ExprState  *exprstate;
1450         Constraint *constr;
1451
1452         /* Make a TypeName so we can use standard type lookup machinery */
1453         typename = makeTypeNameFromNameList(names);
1454         domainoid = typenameTypeId(NULL, typename);
1455
1456         /* Look up the domain in the type table */
1457         typrel = heap_open(TypeRelationId, RowExclusiveLock);
1458
1459         tup = SearchSysCacheCopy(TYPEOID,
1460                                                          ObjectIdGetDatum(domainoid),
1461                                                          0, 0, 0);
1462         if (!HeapTupleIsValid(tup))
1463                 elog(ERROR, "cache lookup failed for type %u", domainoid);
1464         typTup = (Form_pg_type) GETSTRUCT(tup);
1465
1466         /* Check it's a domain and check user has permission for ALTER DOMAIN */
1467         checkDomainOwner(tup, typename);
1468
1469         /* Check for unsupported constraint types */
1470         if (IsA(newConstraint, FkConstraint))
1471                 ereport(ERROR,
1472                                 (errcode(ERRCODE_SYNTAX_ERROR),
1473                                  errmsg("foreign key constraints not possible for domains")));
1474
1475         /* otherwise it should be a plain Constraint */
1476         if (!IsA(newConstraint, Constraint))
1477                 elog(ERROR, "unrecognized node type: %d",
1478                          (int) nodeTag(newConstraint));
1479
1480         constr = (Constraint *) newConstraint;
1481
1482         switch (constr->contype)
1483         {
1484                 case CONSTR_CHECK:
1485                         /* processed below */
1486                         break;
1487
1488                 case CONSTR_UNIQUE:
1489                         ereport(ERROR,
1490                                         (errcode(ERRCODE_SYNTAX_ERROR),
1491                                          errmsg("unique constraints not possible for domains")));
1492                         break;
1493
1494                 case CONSTR_PRIMARY:
1495                         ereport(ERROR,
1496                                         (errcode(ERRCODE_SYNTAX_ERROR),
1497                                 errmsg("primary key constraints not possible for domains")));
1498                         break;
1499
1500                 case CONSTR_ATTR_DEFERRABLE:
1501                 case CONSTR_ATTR_NOT_DEFERRABLE:
1502                 case CONSTR_ATTR_DEFERRED:
1503                 case CONSTR_ATTR_IMMEDIATE:
1504                         ereport(ERROR,
1505                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1506                                          errmsg("specifying constraint deferrability not supported for domains")));
1507                         break;
1508
1509                 default:
1510                         elog(ERROR, "unrecognized constraint subtype: %d",
1511                                  (int) constr->contype);
1512                         break;
1513         }
1514
1515         /*
1516          * Since all other constraint types throw errors, this must be a check
1517          * constraint.  First, process the constraint expression and add an entry
1518          * to pg_constraint.
1519          */
1520
1521         ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,
1522                                                                 typTup->typbasetype, typTup->typtypmod,
1523                                                                 constr, NameStr(typTup->typname));
1524
1525         /*
1526          * Test all values stored in the attributes based on the domain the
1527          * constraint is being added to.
1528          */
1529         expr = (Expr *) stringToNode(ccbin);
1530
1531         /* Need an EState to run ExecEvalExpr */
1532         estate = CreateExecutorState();
1533         econtext = GetPerTupleExprContext(estate);
1534
1535         /* build execution state for expr */
1536         exprstate = ExecPrepareExpr(expr, estate);
1537
1538         /* Fetch relation list with attributes based on this domain */
1539         /* ShareLock is sufficient to prevent concurrent data changes */
1540
1541         rels = get_rels_with_domain(domainoid, ShareLock);
1542
1543         foreach(rt, rels)
1544         {
1545                 RelToCheck *rtc = (RelToCheck *) lfirst(rt);
1546                 Relation        testrel = rtc->rel;
1547                 TupleDesc       tupdesc = RelationGetDescr(testrel);
1548                 HeapScanDesc scan;
1549                 HeapTuple       tuple;
1550
1551                 /* Scan all tuples in this relation */
1552                 scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
1553                 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
1554                 {
1555                         int                     i;
1556
1557                         /* Test attributes that are of the domain */
1558                         for (i = 0; i < rtc->natts; i++)
1559                         {
1560                                 int                     attnum = rtc->atts[i];
1561                                 Datum           d;
1562                                 bool            isNull;
1563                                 Datum           conResult;
1564
1565                                 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
1566
1567                                 econtext->domainValue_datum = d;
1568                                 econtext->domainValue_isNull = isNull;
1569
1570                                 conResult = ExecEvalExprSwitchContext(exprstate,
1571                                                                                                           econtext,
1572                                                                                                           &isNull, NULL);
1573
1574                                 if (!isNull && !DatumGetBool(conResult))
1575                                         ereport(ERROR,
1576                                                         (errcode(ERRCODE_CHECK_VIOLATION),
1577                                                          errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
1578                                                                 NameStr(tupdesc->attrs[attnum - 1]->attname),
1579                                                                         RelationGetRelationName(testrel))));
1580                         }
1581
1582                         ResetExprContext(econtext);
1583                 }
1584                 heap_endscan(scan);
1585
1586                 /* Hold relation lock till commit (XXX bad for concurrency) */
1587                 heap_close(testrel, NoLock);
1588         }
1589
1590         FreeExecutorState(estate);
1591
1592         /* Clean up */
1593         heap_close(typrel, RowExclusiveLock);
1594 }
1595
1596 /*
1597  * get_rels_with_domain
1598  *
1599  * Fetch all relations / attributes which are using the domain
1600  *
1601  * The result is a list of RelToCheck structs, one for each distinct
1602  * relation, each containing one or more attribute numbers that are of
1603  * the domain type.  We have opened each rel and acquired the specified lock
1604  * type on it.
1605  *
1606  * XXX this is completely broken because there is no way to lock the domain
1607  * to prevent columns from being added or dropped while our command runs.
1608  * We can partially protect against column drops by locking relations as we
1609  * come across them, but there is still a race condition (the window between
1610  * seeing a pg_depend entry and acquiring lock on the relation it references).
1611  * Also, holding locks on all these relations simultaneously creates a non-
1612  * trivial risk of deadlock.  We can minimize but not eliminate the deadlock
1613  * risk by using the weakest suitable lock (ShareLock for most callers).
1614  *
1615  * XXX to support domains over domains, we'd need to make this smarter,
1616  * or make its callers smarter, so that we could find columns of derived
1617  * domains.  Arrays of domains would be a problem too.
1618  *
1619  * Generally used for retrieving a list of tests when adding
1620  * new constraints to a domain.
1621  */
1622 static List *
1623 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
1624 {
1625         List       *result = NIL;
1626         Relation        depRel;
1627         ScanKeyData key[2];
1628         SysScanDesc depScan;
1629         HeapTuple       depTup;
1630
1631         /*
1632          * We scan pg_depend to find those things that depend on the domain. (We
1633          * assume we can ignore refobjsubid for a domain.)
1634          */
1635         depRel = heap_open(DependRelationId, AccessShareLock);
1636
1637         ScanKeyInit(&key[0],
1638                                 Anum_pg_depend_refclassid,
1639                                 BTEqualStrategyNumber, F_OIDEQ,
1640                                 ObjectIdGetDatum(TypeRelationId));
1641         ScanKeyInit(&key[1],
1642                                 Anum_pg_depend_refobjid,
1643                                 BTEqualStrategyNumber, F_OIDEQ,
1644                                 ObjectIdGetDatum(domainOid));
1645
1646         depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
1647                                                                  SnapshotNow, 2, key);
1648
1649         while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
1650         {
1651                 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
1652                 RelToCheck *rtc = NULL;
1653                 ListCell   *rellist;
1654                 Form_pg_attribute pg_att;
1655                 int                     ptr;
1656
1657                 /* Ignore dependees that aren't user columns of relations */
1658                 /* (we assume system columns are never of domain types) */
1659                 if (pg_depend->classid != RelationRelationId ||
1660                         pg_depend->objsubid <= 0)
1661                         continue;
1662
1663                 /* See if we already have an entry for this relation */
1664                 foreach(rellist, result)
1665                 {
1666                         RelToCheck *rt = (RelToCheck *) lfirst(rellist);
1667
1668                         if (RelationGetRelid(rt->rel) == pg_depend->objid)
1669                         {
1670                                 rtc = rt;
1671                                 break;
1672                         }
1673                 }
1674
1675                 if (rtc == NULL)
1676                 {
1677                         /* First attribute found for this relation */
1678                         Relation        rel;
1679
1680                         /* Acquire requested lock on relation */
1681                         rel = relation_open(pg_depend->objid, lockmode);
1682
1683                         /* It could be a view or composite type; if so ignore it */
1684                         if (rel->rd_rel->relkind != RELKIND_RELATION)
1685                         {
1686                                 relation_close(rel, lockmode);
1687                                 continue;
1688                         }
1689
1690                         /* Build the RelToCheck entry with enough space for all atts */
1691                         rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
1692                         rtc->rel = rel;
1693                         rtc->natts = 0;
1694                         rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
1695                         result = lcons(rtc, result);
1696                 }
1697
1698                 /*
1699                  * Confirm column has not been dropped, and is of the expected type.
1700                  * This defends against an ALTER DROP COLUMN occuring just before we
1701                  * acquired lock ... but if the whole table were dropped, we'd still
1702                  * have a problem.
1703                  */
1704                 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
1705                         continue;
1706                 pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
1707                 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
1708                         continue;
1709
1710                 /*
1711                  * Okay, add column to result.  We store the columns in column-number
1712                  * order; this is just a hack to improve predictability of regression
1713                  * test output ...
1714                  */
1715                 Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
1716
1717                 ptr = rtc->natts++;
1718                 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
1719                 {
1720                         rtc->atts[ptr] = rtc->atts[ptr - 1];
1721                         ptr--;
1722                 }
1723                 rtc->atts[ptr] = pg_depend->objsubid;
1724         }
1725
1726         systable_endscan(depScan);
1727
1728         relation_close(depRel, AccessShareLock);
1729
1730         return result;
1731 }
1732
1733 /*
1734  * checkDomainOwner
1735  *
1736  * Check that the type is actually a domain and that the current user
1737  * has permission to do ALTER DOMAIN on it.  Throw an error if not.
1738  */
1739 static void
1740 checkDomainOwner(HeapTuple tup, TypeName *typename)
1741 {
1742         Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1743
1744         /* Check that this is actually a domain */
1745         if (typTup->typtype != 'd')
1746                 ereport(ERROR,
1747                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1748                                  errmsg("\"%s\" is not a domain",
1749                                                 TypeNameToString(typename))));
1750
1751         /* Permission check: must own type */
1752         if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
1753                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
1754                                            TypeNameToString(typename));
1755 }
1756
1757 /*
1758  * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
1759  */
1760 static char *
1761 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
1762                                         int typMod, Constraint *constr,
1763                                         char *domainName)
1764 {
1765         Node       *expr;
1766         char       *ccsrc;
1767         char       *ccbin;
1768         ParseState *pstate;
1769         CoerceToDomainValue *domVal;
1770
1771         /*
1772          * Assign or validate constraint name
1773          */
1774         if (constr->name)
1775         {
1776                 if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
1777                                                                  domainOid,
1778                                                                  domainNamespace,
1779                                                                  constr->name))
1780                         ereport(ERROR,
1781                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
1782                                  errmsg("constraint \"%s\" for domain \"%s\" already exists",
1783                                                 constr->name, domainName)));
1784         }
1785         else
1786                 constr->name = ChooseConstraintName(domainName,
1787                                                                                         NULL,
1788                                                                                         "check",
1789                                                                                         domainNamespace,
1790                                                                                         NIL);
1791
1792         /*
1793          * Convert the A_EXPR in raw_expr into an EXPR
1794          */
1795         pstate = make_parsestate(NULL);
1796
1797         /*
1798          * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
1799          * the expression.      Note that it will appear to have the type of the base
1800          * type, not the domain.  This seems correct since within the check
1801          * expression, we should not assume the input value can be considered a
1802          * member of the domain.
1803          */
1804         domVal = makeNode(CoerceToDomainValue);
1805         domVal->typeId = baseTypeOid;
1806         domVal->typeMod = typMod;
1807
1808         pstate->p_value_substitute = (Node *) domVal;
1809
1810         expr = transformExpr(pstate, constr->raw_expr);
1811
1812         /*
1813          * Make sure it yields a boolean result.
1814          */
1815         expr = coerce_to_boolean(pstate, expr, "CHECK");
1816
1817         /*
1818          * Make sure no outside relations are referred to.
1819          */
1820         if (list_length(pstate->p_rtable) != 0)
1821                 ereport(ERROR,
1822                                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1823                   errmsg("cannot use table references in domain check constraint")));
1824
1825         /*
1826          * Domains don't allow var clauses (this should be redundant with the
1827          * above check, but make it anyway)
1828          */
1829         if (contain_var_clause(expr))
1830                 ereport(ERROR,
1831                                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
1832                   errmsg("cannot use table references in domain check constraint")));
1833
1834         /*
1835          * No subplans or aggregates, either...
1836          */
1837         if (pstate->p_hasSubLinks)
1838                 ereport(ERROR,
1839                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1840                                  errmsg("cannot use subquery in check constraint")));
1841         if (pstate->p_hasAggs)
1842                 ereport(ERROR,
1843                                 (errcode(ERRCODE_GROUPING_ERROR),
1844                                  errmsg("cannot use aggregate function in check constraint")));
1845
1846         /*
1847          * Convert to string form for storage.
1848          */
1849         ccbin = nodeToString(expr);
1850
1851         /*
1852          * Deparse it to produce text for consrc.
1853          *
1854          * Since VARNOs aren't allowed in domain constraints, relation context
1855          * isn't required as anything other than a shell.
1856          */
1857         ccsrc = deparse_expression(expr,
1858                                                            deparse_context_for(domainName,
1859                                                                                                    InvalidOid),
1860                                                            false, false);
1861
1862         /*
1863          * Store the constraint in pg_constraint
1864          */
1865         CreateConstraintEntry(constr->name, /* Constraint Name */
1866                                                   domainNamespace,              /* namespace */
1867                                                   CONSTRAINT_CHECK,             /* Constraint Type */
1868                                                   false,        /* Is Deferrable */
1869                                                   false,        /* Is Deferred */
1870                                                   InvalidOid,   /* not a relation constraint */
1871                                                   NULL,
1872                                                   0,
1873                                                   domainOid,    /* domain constraint */
1874                                                   InvalidOid,   /* Foreign key fields */
1875                                                   NULL,
1876                                                   0,
1877                                                   ' ',
1878                                                   ' ',
1879                                                   ' ',
1880                                                   InvalidOid,
1881                                                   expr, /* Tree form check constraint */
1882                                                   ccbin,        /* Binary form check constraint */
1883                                                   ccsrc);               /* Source form check constraint */
1884
1885         /*
1886          * Return the compiled constraint expression so the calling routine can
1887          * perform any additional required tests.
1888          */
1889         return ccbin;
1890 }
1891
1892 /*
1893  * GetDomainConstraints - get a list of the current constraints of domain
1894  *
1895  * Returns a possibly-empty list of DomainConstraintState nodes.
1896  *
1897  * This is called by the executor during plan startup for a CoerceToDomain
1898  * expression node.  The given constraints will be checked for each value
1899  * passed through the node.
1900  *
1901  * We allow this to be called for non-domain types, in which case the result
1902  * is always NIL.
1903  */
1904 List *
1905 GetDomainConstraints(Oid typeOid)
1906 {
1907         List       *result = NIL;
1908         bool            notNull = false;
1909         Relation        conRel;
1910
1911         conRel = heap_open(ConstraintRelationId, AccessShareLock);
1912
1913         for (;;)
1914         {
1915                 HeapTuple       tup;
1916                 HeapTuple       conTup;
1917                 Form_pg_type typTup;
1918                 ScanKeyData key[1];
1919                 SysScanDesc scan;
1920
1921                 tup = SearchSysCache(TYPEOID,
1922                                                          ObjectIdGetDatum(typeOid),
1923                                                          0, 0, 0);
1924                 if (!HeapTupleIsValid(tup))
1925                         elog(ERROR, "cache lookup failed for type %u", typeOid);
1926                 typTup = (Form_pg_type) GETSTRUCT(tup);
1927
1928                 if (typTup->typtype != 'd')
1929                 {
1930                         /* Not a domain, so done */
1931                         ReleaseSysCache(tup);
1932                         break;
1933                 }
1934
1935                 /* Test for NOT NULL Constraint */
1936                 if (typTup->typnotnull)
1937                         notNull = true;
1938
1939                 /* Look for CHECK Constraints on this domain */
1940                 ScanKeyInit(&key[0],
1941                                         Anum_pg_constraint_contypid,
1942                                         BTEqualStrategyNumber, F_OIDEQ,
1943                                         ObjectIdGetDatum(typeOid));
1944
1945                 scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
1946                                                                   SnapshotNow, 1, key);
1947
1948                 while (HeapTupleIsValid(conTup = systable_getnext(scan)))
1949                 {
1950                         Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
1951                         Datum           val;
1952                         bool            isNull;
1953                         Expr       *check_expr;
1954                         DomainConstraintState *r;
1955
1956                         /* Ignore non-CHECK constraints (presently, shouldn't be any) */
1957                         if (c->contype != CONSTRAINT_CHECK)
1958                                 continue;
1959
1960                         /*
1961                          * Not expecting conbin to be NULL, but we'll test for it anyway
1962                          */
1963                         val = fastgetattr(conTup, Anum_pg_constraint_conbin,
1964                                                           conRel->rd_att, &isNull);
1965                         if (isNull)
1966                                 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
1967                                          NameStr(typTup->typname), NameStr(c->conname));
1968
1969                         check_expr = (Expr *)
1970                                 stringToNode(DatumGetCString(DirectFunctionCall1(textout,
1971                                                                                                                                  val)));
1972
1973                         /* ExecInitExpr assumes we already fixed opfuncids */
1974                         fix_opfuncids((Node *) check_expr);
1975
1976                         r = makeNode(DomainConstraintState);
1977                         r->constrainttype = DOM_CONSTRAINT_CHECK;
1978                         r->name = pstrdup(NameStr(c->conname));
1979                         r->check_expr = ExecInitExpr(check_expr, NULL);
1980
1981                         /*
1982                          * use lcons() here because constraints of lower domains should be
1983                          * applied earlier.
1984                          */
1985                         result = lcons(r, result);
1986                 }
1987
1988                 systable_endscan(scan);
1989
1990                 /* loop to next domain in stack */
1991                 typeOid = typTup->typbasetype;
1992                 ReleaseSysCache(tup);
1993         }
1994
1995         heap_close(conRel, AccessShareLock);
1996
1997         /*
1998          * Only need to add one NOT NULL check regardless of how many domains in
1999          * the stack request it.
2000          */
2001         if (notNull)
2002         {
2003                 DomainConstraintState *r = makeNode(DomainConstraintState);
2004
2005                 r->constrainttype = DOM_CONSTRAINT_NOTNULL;
2006                 r->name = pstrdup("NOT NULL");
2007                 r->check_expr = NULL;
2008
2009                 /* lcons to apply the nullness check FIRST */
2010                 result = lcons(r, result);
2011         }
2012
2013         return result;
2014 }
2015
2016 /*
2017  * Change the owner of a type.
2018  */
2019 void
2020 AlterTypeOwner(List *names, Oid newOwnerId)
2021 {
2022         TypeName   *typename;
2023         Oid                     typeOid;
2024         Relation        rel;
2025         HeapTuple       tup;
2026         Form_pg_type typTup;
2027         AclResult       aclresult;
2028
2029         /* Make a TypeName so we can use standard type lookup machinery */
2030         typename = makeTypeNameFromNameList(names);
2031
2032         /* Use LookupTypeName here so that shell types can be processed */
2033         typeOid = LookupTypeName(NULL, typename);
2034         if (!OidIsValid(typeOid))
2035                 ereport(ERROR,
2036                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2037                                  errmsg("type \"%s\" does not exist",
2038                                                 TypeNameToString(typename))));
2039
2040         /* Look up the type in the type table */
2041         rel = heap_open(TypeRelationId, RowExclusiveLock);
2042
2043         tup = SearchSysCacheCopy(TYPEOID,
2044                                                          ObjectIdGetDatum(typeOid),
2045                                                          0, 0, 0);
2046         if (!HeapTupleIsValid(tup))
2047                 elog(ERROR, "cache lookup failed for type %u", typeOid);
2048         typTup = (Form_pg_type) GETSTRUCT(tup);
2049
2050         /*
2051          * If it's a composite type, we need to check that it really is a
2052          * free-standing composite type, and not a table's underlying type. We
2053          * want people to use ALTER TABLE not ALTER TYPE for that case.
2054          */
2055         if (typTup->typtype == 'c' &&
2056                 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
2057                 ereport(ERROR,
2058                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2059                                  errmsg("\"%s\" is a table's row type",
2060                                                 TypeNameToString(typename))));
2061
2062         /*
2063          * If the new owner is the same as the existing owner, consider the
2064          * command to have succeeded.  This is for dump restoration purposes.
2065          */
2066         if (typTup->typowner != newOwnerId)
2067         {
2068                 /* Superusers can always do it */
2069                 if (!superuser())
2070                 {
2071                         /* Otherwise, must be owner of the existing object */
2072                         if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
2073                                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2074                                                            TypeNameToString(typename));
2075
2076                         /* Must be able to become new owner */
2077                         check_is_member_of_role(GetUserId(), newOwnerId);
2078
2079                         /* New owner must have CREATE privilege on namespace */
2080                         aclresult = pg_namespace_aclcheck(typTup->typnamespace,
2081                                                                                           newOwnerId,
2082                                                                                           ACL_CREATE);
2083                         if (aclresult != ACLCHECK_OK)
2084                                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
2085                                                            get_namespace_name(typTup->typnamespace));
2086                 }
2087
2088                 /*
2089                  * Modify the owner --- okay to scribble on typTup because it's a copy
2090                  */
2091                 typTup->typowner = newOwnerId;
2092
2093                 simple_heap_update(rel, &tup->t_self, tup);
2094
2095                 CatalogUpdateIndexes(rel, tup);
2096
2097                 /* Update owner dependency reference */
2098                 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2099         }
2100
2101         /* Clean up */
2102         heap_close(rel, RowExclusiveLock);
2103 }
2104
2105 /*
2106  * AlterTypeOwnerInternal - change type owner unconditionally
2107  *
2108  * This is currently only used to propagate ALTER TABLE OWNER to the
2109  * table's rowtype, and to implement REASSIGN OWNED BY.  It assumes the
2110  * caller has done all needed checks.
2111  */
2112 void
2113 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
2114 {
2115         Relation        rel;
2116         HeapTuple       tup;
2117         Form_pg_type typTup;
2118
2119         rel = heap_open(TypeRelationId, RowExclusiveLock);
2120
2121         tup = SearchSysCacheCopy(TYPEOID,
2122                                                          ObjectIdGetDatum(typeOid),
2123                                                          0, 0, 0);
2124         if (!HeapTupleIsValid(tup))
2125                 elog(ERROR, "cache lookup failed for type %u", typeOid);
2126         typTup = (Form_pg_type) GETSTRUCT(tup);
2127
2128         /*
2129          * Modify the owner --- okay to scribble on typTup because it's a copy
2130          */
2131         typTup->typowner = newOwnerId;
2132
2133         simple_heap_update(rel, &tup->t_self, tup);
2134
2135         CatalogUpdateIndexes(rel, tup);
2136
2137         /* Update owner dependency reference */
2138         changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
2139
2140         /* Clean up */
2141         heap_close(rel, RowExclusiveLock);
2142 }
2143
2144 /*
2145  * Execute ALTER TYPE SET SCHEMA
2146  */
2147 void
2148 AlterTypeNamespace(List *names, const char *newschema)
2149 {
2150         TypeName   *typename;
2151         Oid                     typeOid;
2152         Oid                     nspOid;
2153
2154         /* Make a TypeName so we can use standard type lookup machinery */
2155         typename = makeTypeNameFromNameList(names);
2156         typeOid = typenameTypeId(NULL, typename);
2157
2158         /* check permissions on type */
2159         if (!pg_type_ownercheck(typeOid, GetUserId()))
2160                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
2161                                            format_type_be(typeOid));
2162
2163         /* get schema OID and check its permissions */
2164         nspOid = LookupCreationNamespace(newschema);
2165
2166         /* and do the work */
2167         AlterTypeNamespaceInternal(typeOid, nspOid, true);
2168 }
2169
2170 /*
2171  * Move specified type to new namespace.
2172  *
2173  * Caller must have already checked privileges.
2174  *
2175  * If errorOnTableType is TRUE, the function errors out if the type is
2176  * a table type.  ALTER TABLE has to be used to move a table to a new
2177  * namespace.
2178  */
2179 void
2180 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
2181                                                    bool errorOnTableType)
2182 {
2183         Relation        rel;
2184         HeapTuple       tup;
2185         Form_pg_type typform;
2186         Oid                     oldNspOid;
2187         bool            isCompositeType;
2188
2189         rel = heap_open(TypeRelationId, RowExclusiveLock);
2190
2191         tup = SearchSysCacheCopy(TYPEOID,
2192                                                          ObjectIdGetDatum(typeOid),
2193                                                          0, 0, 0);
2194         if (!HeapTupleIsValid(tup))
2195                 elog(ERROR, "cache lookup failed for type %u", typeOid);
2196         typform = (Form_pg_type) GETSTRUCT(tup);
2197
2198         oldNspOid = typform->typnamespace;
2199
2200         if (oldNspOid == nspOid)
2201                 ereport(ERROR,
2202                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
2203                                  errmsg("type %s is already in schema \"%s\"",
2204                                                 format_type_be(typeOid),
2205                                                 get_namespace_name(nspOid))));
2206
2207         /* disallow renaming into or out of temp schemas */
2208         if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid))
2209                 ereport(ERROR,
2210                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2211                         errmsg("cannot move objects into or out of temporary schemas")));
2212
2213         /* same for TOAST schema */
2214         if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE)
2215                 ereport(ERROR,
2216                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2217                                  errmsg("cannot move objects into or out of TOAST schema")));
2218
2219         /* check for duplicate name (more friendly than unique-index failure) */
2220         if (SearchSysCacheExists(TYPENAMENSP,
2221                                                          CStringGetDatum(NameStr(typform->typname)),
2222                                                          ObjectIdGetDatum(nspOid),
2223                                                          0, 0))
2224                 ereport(ERROR,
2225                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
2226                                  errmsg("type \"%s\" already exists in schema \"%s\"",
2227                                                 NameStr(typform->typname),
2228                                                 get_namespace_name(nspOid))));
2229
2230         /* Detect whether type is a composite type (but not a table rowtype) */
2231         isCompositeType =
2232                 (typform->typtype == 'c' &&
2233                  get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
2234
2235         /* Enforce not-table-type if requested */
2236         if (typform->typtype == 'c' && !isCompositeType && errorOnTableType)
2237                 ereport(ERROR,
2238                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2239                                  errmsg("%s is a table's row type",
2240                                                 format_type_be(typeOid)),
2241                                  errhint("Use ALTER TABLE SET SCHEMA instead.")));
2242
2243         /* OK, modify the pg_type row */
2244
2245         /* tup is a copy, so we can scribble directly on it */
2246         typform->typnamespace = nspOid;
2247
2248         simple_heap_update(rel, &tup->t_self, tup);
2249         CatalogUpdateIndexes(rel, tup);
2250
2251         /*
2252          * Composite types have pg_class entries.
2253          *
2254          * We need to modify the pg_class tuple as well to reflect the change of
2255          * schema.
2256          */
2257         if (isCompositeType)
2258         {
2259                 Relation        classRel;
2260
2261                 classRel = heap_open(RelationRelationId, RowExclusiveLock);
2262
2263                 /*
2264                  * The dependency on the schema is listed under the pg_class entry, so
2265                  * tell AlterRelationNamespaceInternal to fix it.
2266                  */
2267                 AlterRelationNamespaceInternal(classRel, typform->typrelid,
2268                                                                            oldNspOid, nspOid,
2269                                                                            true);
2270
2271                 heap_close(classRel, RowExclusiveLock);
2272
2273                 /*
2274                  * Check for constraints associated with the composite type (we don't
2275                  * currently support this, but probably will someday).
2276                  */
2277                 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
2278                                                                   nspOid, false);
2279         }
2280         else
2281         {
2282                 /* If it's a domain, it might have constraints */
2283                 if (typform->typtype == 'd')
2284                         AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
2285
2286                 /*
2287                  * Update dependency on schema, if any --- a table rowtype has not got
2288                  * one.
2289                  */
2290                 if (typform->typtype != 'c')
2291                         if (changeDependencyFor(TypeRelationId, typeOid,
2292                                                                 NamespaceRelationId, oldNspOid, nspOid) != 1)
2293                                 elog(ERROR, "failed to change schema dependency for type %s",
2294                                          format_type_be(typeOid));
2295         }
2296
2297         heap_freetuple(tup);
2298
2299         heap_close(rel, RowExclusiveLock);
2300 }