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