OSDN Git Service

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