Header And Logo

PostgreSQL
| The world's most advanced open source database.

typecmds.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * typecmds.c
00004  *    Routines for SQL commands that manipulate types (and domains).
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/commands/typecmds.c
00012  *
00013  * DESCRIPTION
00014  *    The "DefineFoo" routines take the parse tree and pick out the
00015  *    appropriate arguments/flags, passing the results to the
00016  *    corresponding "FooDefine" routines (in src/catalog) that do
00017  *    the actual catalog-munging.  These routines also verify permission
00018  *    of the user to execute the command.
00019  *
00020  * NOTES
00021  *    These things must be defined and committed in the following order:
00022  *      "create function":
00023  *              input/output, recv/send functions
00024  *      "create type":
00025  *              type
00026  *      "create operator":
00027  *              operators
00028  *
00029  *
00030  *-------------------------------------------------------------------------
00031  */
00032 #include "postgres.h"
00033 
00034 #include "access/genam.h"
00035 #include "access/heapam.h"
00036 #include "access/htup_details.h"
00037 #include "access/xact.h"
00038 #include "catalog/catalog.h"
00039 #include "catalog/dependency.h"
00040 #include "catalog/heap.h"
00041 #include "catalog/indexing.h"
00042 #include "catalog/objectaccess.h"
00043 #include "catalog/pg_authid.h"
00044 #include "catalog/pg_collation.h"
00045 #include "catalog/pg_constraint.h"
00046 #include "catalog/pg_depend.h"
00047 #include "catalog/pg_enum.h"
00048 #include "catalog/pg_language.h"
00049 #include "catalog/pg_namespace.h"
00050 #include "catalog/pg_proc.h"
00051 #include "catalog/pg_proc_fn.h"
00052 #include "catalog/pg_range.h"
00053 #include "catalog/pg_type.h"
00054 #include "catalog/pg_type_fn.h"
00055 #include "commands/defrem.h"
00056 #include "commands/tablecmds.h"
00057 #include "commands/typecmds.h"
00058 #include "executor/executor.h"
00059 #include "miscadmin.h"
00060 #include "nodes/makefuncs.h"
00061 #include "optimizer/planner.h"
00062 #include "optimizer/var.h"
00063 #include "parser/parse_coerce.h"
00064 #include "parser/parse_collate.h"
00065 #include "parser/parse_expr.h"
00066 #include "parser/parse_func.h"
00067 #include "parser/parse_type.h"
00068 #include "utils/acl.h"
00069 #include "utils/builtins.h"
00070 #include "utils/fmgroids.h"
00071 #include "utils/lsyscache.h"
00072 #include "utils/memutils.h"
00073 #include "utils/rel.h"
00074 #include "utils/syscache.h"
00075 #include "utils/tqual.h"
00076 
00077 
00078 /* result structure for get_rels_with_domain() */
00079 typedef struct
00080 {
00081     Relation    rel;            /* opened and locked relation */
00082     int         natts;          /* number of attributes of interest */
00083     int        *atts;           /* attribute numbers */
00084     /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
00085 } RelToCheck;
00086 
00087 /* Potentially set by contrib/pg_upgrade_support functions */
00088 Oid         binary_upgrade_next_array_pg_type_oid = InvalidOid;
00089 
00090 static void makeRangeConstructors(const char *name, Oid namespace,
00091                       Oid rangeOid, Oid subtype);
00092 static Oid  findTypeInputFunction(List *procname, Oid typeOid);
00093 static Oid  findTypeOutputFunction(List *procname, Oid typeOid);
00094 static Oid  findTypeReceiveFunction(List *procname, Oid typeOid);
00095 static Oid  findTypeSendFunction(List *procname, Oid typeOid);
00096 static Oid  findTypeTypmodinFunction(List *procname);
00097 static Oid  findTypeTypmodoutFunction(List *procname);
00098 static Oid  findTypeAnalyzeFunction(List *procname, Oid typeOid);
00099 static Oid  findRangeSubOpclass(List *opcname, Oid subtype);
00100 static Oid  findRangeCanonicalFunction(List *procname, Oid typeOid);
00101 static Oid  findRangeSubtypeDiffFunction(List *procname, Oid subtype);
00102 static void validateDomainConstraint(Oid domainoid, char *ccbin);
00103 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
00104 static void checkEnumOwner(HeapTuple tup);
00105 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
00106                     Oid baseTypeOid,
00107                     int typMod, Constraint *constr,
00108                     char *domainName);
00109 
00110 
00111 /*
00112  * DefineType
00113  *      Registers a new base type.
00114  */
00115 Oid
00116 DefineType(List *names, List *parameters)
00117 {
00118     char       *typeName;
00119     Oid         typeNamespace;
00120     int16       internalLength = -1;    /* default: variable-length */
00121     List       *inputName = NIL;
00122     List       *outputName = NIL;
00123     List       *receiveName = NIL;
00124     List       *sendName = NIL;
00125     List       *typmodinName = NIL;
00126     List       *typmodoutName = NIL;
00127     List       *analyzeName = NIL;
00128     char        category = TYPCATEGORY_USER;
00129     bool        preferred = false;
00130     char        delimiter = DEFAULT_TYPDELIM;
00131     Oid         elemType = InvalidOid;
00132     char       *defaultValue = NULL;
00133     bool        byValue = false;
00134     char        alignment = 'i';    /* default alignment */
00135     char        storage = 'p';  /* default TOAST storage method */
00136     Oid         collation = InvalidOid;
00137     DefElem    *likeTypeEl = NULL;
00138     DefElem    *internalLengthEl = NULL;
00139     DefElem    *inputNameEl = NULL;
00140     DefElem    *outputNameEl = NULL;
00141     DefElem    *receiveNameEl = NULL;
00142     DefElem    *sendNameEl = NULL;
00143     DefElem    *typmodinNameEl = NULL;
00144     DefElem    *typmodoutNameEl = NULL;
00145     DefElem    *analyzeNameEl = NULL;
00146     DefElem    *categoryEl = NULL;
00147     DefElem    *preferredEl = NULL;
00148     DefElem    *delimiterEl = NULL;
00149     DefElem    *elemTypeEl = NULL;
00150     DefElem    *defaultValueEl = NULL;
00151     DefElem    *byValueEl = NULL;
00152     DefElem    *alignmentEl = NULL;
00153     DefElem    *storageEl = NULL;
00154     DefElem    *collatableEl = NULL;
00155     Oid         inputOid;
00156     Oid         outputOid;
00157     Oid         receiveOid = InvalidOid;
00158     Oid         sendOid = InvalidOid;
00159     Oid         typmodinOid = InvalidOid;
00160     Oid         typmodoutOid = InvalidOid;
00161     Oid         analyzeOid = InvalidOid;
00162     char       *array_type;
00163     Oid         array_oid;
00164     Oid         typoid;
00165     Oid         resulttype;
00166     ListCell   *pl;
00167 
00168     /*
00169      * As of Postgres 8.4, we require superuser privilege to create a base
00170      * type.  This is simple paranoia: there are too many ways to mess up the
00171      * system with an incorrect type definition (for instance, representation
00172      * parameters that don't match what the C code expects).  In practice it
00173      * takes superuser privilege to create the I/O functions, and so the
00174      * former requirement that you own the I/O functions pretty much forced
00175      * superuserness anyway.  We're just making doubly sure here.
00176      *
00177      * XXX re-enable NOT_USED code sections below if you remove this test.
00178      */
00179     if (!superuser())
00180         ereport(ERROR,
00181                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00182                  errmsg("must be superuser to create a base type")));
00183 
00184     /* Convert list of names to a name and namespace */
00185     typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
00186 
00187 #ifdef NOT_USED
00188     /* XXX this is unnecessary given the superuser check above */
00189     /* Check we have creation rights in target namespace */
00190     aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
00191     if (aclresult != ACLCHECK_OK)
00192         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00193                        get_namespace_name(typeNamespace));
00194 #endif
00195 
00196     /*
00197      * Look to see if type already exists (presumably as a shell; if not,
00198      * TypeCreate will complain).
00199      */
00200     typoid = GetSysCacheOid2(TYPENAMENSP,
00201                              CStringGetDatum(typeName),
00202                              ObjectIdGetDatum(typeNamespace));
00203 
00204     /*
00205      * If it's not a shell, see if it's an autogenerated array type, and if so
00206      * rename it out of the way.
00207      */
00208     if (OidIsValid(typoid) && get_typisdefined(typoid))
00209     {
00210         if (moveArrayTypeName(typoid, typeName, typeNamespace))
00211             typoid = InvalidOid;
00212     }
00213 
00214     /*
00215      * If it doesn't exist, create it as a shell, so that the OID is known for
00216      * use in the I/O function definitions.
00217      */
00218     if (!OidIsValid(typoid))
00219     {
00220         typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
00221         /* Make new shell type visible for modification below */
00222         CommandCounterIncrement();
00223 
00224         /*
00225          * If the command was a parameterless CREATE TYPE, we're done ---
00226          * creating the shell type was all we're supposed to do.
00227          */
00228         if (parameters == NIL)
00229             return InvalidOid;
00230     }
00231     else
00232     {
00233         /* Complain if dummy CREATE TYPE and entry already exists */
00234         if (parameters == NIL)
00235             ereport(ERROR,
00236                     (errcode(ERRCODE_DUPLICATE_OBJECT),
00237                      errmsg("type \"%s\" already exists", typeName)));
00238     }
00239 
00240     /* Extract the parameters from the parameter list */
00241     foreach(pl, parameters)
00242     {
00243         DefElem    *defel = (DefElem *) lfirst(pl);
00244         DefElem   **defelp;
00245 
00246         if (pg_strcasecmp(defel->defname, "like") == 0)
00247             defelp = &likeTypeEl;
00248         else if (pg_strcasecmp(defel->defname, "internallength") == 0)
00249             defelp = &internalLengthEl;
00250         else if (pg_strcasecmp(defel->defname, "input") == 0)
00251             defelp = &inputNameEl;
00252         else if (pg_strcasecmp(defel->defname, "output") == 0)
00253             defelp = &outputNameEl;
00254         else if (pg_strcasecmp(defel->defname, "receive") == 0)
00255             defelp = &receiveNameEl;
00256         else if (pg_strcasecmp(defel->defname, "send") == 0)
00257             defelp = &sendNameEl;
00258         else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
00259             defelp = &typmodinNameEl;
00260         else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
00261             defelp = &typmodoutNameEl;
00262         else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
00263                  pg_strcasecmp(defel->defname, "analyse") == 0)
00264             defelp = &analyzeNameEl;
00265         else if (pg_strcasecmp(defel->defname, "category") == 0)
00266             defelp = &categoryEl;
00267         else if (pg_strcasecmp(defel->defname, "preferred") == 0)
00268             defelp = &preferredEl;
00269         else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
00270             defelp = &delimiterEl;
00271         else if (pg_strcasecmp(defel->defname, "element") == 0)
00272             defelp = &elemTypeEl;
00273         else if (pg_strcasecmp(defel->defname, "default") == 0)
00274             defelp = &defaultValueEl;
00275         else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
00276             defelp = &byValueEl;
00277         else if (pg_strcasecmp(defel->defname, "alignment") == 0)
00278             defelp = &alignmentEl;
00279         else if (pg_strcasecmp(defel->defname, "storage") == 0)
00280             defelp = &storageEl;
00281         else if (pg_strcasecmp(defel->defname, "collatable") == 0)
00282             defelp = &collatableEl;
00283         else
00284         {
00285             /* WARNING, not ERROR, for historical backwards-compatibility */
00286             ereport(WARNING,
00287                     (errcode(ERRCODE_SYNTAX_ERROR),
00288                      errmsg("type attribute \"%s\" not recognized",
00289                             defel->defname)));
00290             continue;
00291         }
00292         if (*defelp != NULL)
00293             ereport(ERROR,
00294                     (errcode(ERRCODE_SYNTAX_ERROR),
00295                      errmsg("conflicting or redundant options")));
00296         *defelp = defel;
00297     }
00298 
00299     /*
00300      * Now interpret the options; we do this separately so that LIKE can be
00301      * overridden by other options regardless of the ordering in the parameter
00302      * list.
00303      */
00304     if (likeTypeEl)
00305     {
00306         Type        likeType;
00307         Form_pg_type likeForm;
00308 
00309         likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
00310         likeForm = (Form_pg_type) GETSTRUCT(likeType);
00311         internalLength = likeForm->typlen;
00312         byValue = likeForm->typbyval;
00313         alignment = likeForm->typalign;
00314         storage = likeForm->typstorage;
00315         ReleaseSysCache(likeType);
00316     }
00317     if (internalLengthEl)
00318         internalLength = defGetTypeLength(internalLengthEl);
00319     if (inputNameEl)
00320         inputName = defGetQualifiedName(inputNameEl);
00321     if (outputNameEl)
00322         outputName = defGetQualifiedName(outputNameEl);
00323     if (receiveNameEl)
00324         receiveName = defGetQualifiedName(receiveNameEl);
00325     if (sendNameEl)
00326         sendName = defGetQualifiedName(sendNameEl);
00327     if (typmodinNameEl)
00328         typmodinName = defGetQualifiedName(typmodinNameEl);
00329     if (typmodoutNameEl)
00330         typmodoutName = defGetQualifiedName(typmodoutNameEl);
00331     if (analyzeNameEl)
00332         analyzeName = defGetQualifiedName(analyzeNameEl);
00333     if (categoryEl)
00334     {
00335         char       *p = defGetString(categoryEl);
00336 
00337         category = p[0];
00338         /* restrict to non-control ASCII */
00339         if (category < 32 || category > 126)
00340             ereport(ERROR,
00341                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00342                  errmsg("invalid type category \"%s\": must be simple ASCII",
00343                         p)));
00344     }
00345     if (preferredEl)
00346         preferred = defGetBoolean(preferredEl);
00347     if (delimiterEl)
00348     {
00349         char       *p = defGetString(delimiterEl);
00350 
00351         delimiter = p[0];
00352         /* XXX shouldn't we restrict the delimiter? */
00353     }
00354     if (elemTypeEl)
00355     {
00356         elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
00357         /* disallow arrays of pseudotypes */
00358         if (get_typtype(elemType) == TYPTYPE_PSEUDO)
00359             ereport(ERROR,
00360                     (errcode(ERRCODE_DATATYPE_MISMATCH),
00361                      errmsg("array element type cannot be %s",
00362                             format_type_be(elemType))));
00363     }
00364     if (defaultValueEl)
00365         defaultValue = defGetString(defaultValueEl);
00366     if (byValueEl)
00367         byValue = defGetBoolean(byValueEl);
00368     if (alignmentEl)
00369     {
00370         char       *a = defGetString(alignmentEl);
00371 
00372         /*
00373          * Note: if argument was an unquoted identifier, parser will have
00374          * applied translations to it, so be prepared to recognize translated
00375          * type names as well as the nominal form.
00376          */
00377         if (pg_strcasecmp(a, "double") == 0 ||
00378             pg_strcasecmp(a, "float8") == 0 ||
00379             pg_strcasecmp(a, "pg_catalog.float8") == 0)
00380             alignment = 'd';
00381         else if (pg_strcasecmp(a, "int4") == 0 ||
00382                  pg_strcasecmp(a, "pg_catalog.int4") == 0)
00383             alignment = 'i';
00384         else if (pg_strcasecmp(a, "int2") == 0 ||
00385                  pg_strcasecmp(a, "pg_catalog.int2") == 0)
00386             alignment = 's';
00387         else if (pg_strcasecmp(a, "char") == 0 ||
00388                  pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
00389             alignment = 'c';
00390         else
00391             ereport(ERROR,
00392                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00393                      errmsg("alignment \"%s\" not recognized", a)));
00394     }
00395     if (storageEl)
00396     {
00397         char       *a = defGetString(storageEl);
00398 
00399         if (pg_strcasecmp(a, "plain") == 0)
00400             storage = 'p';
00401         else if (pg_strcasecmp(a, "external") == 0)
00402             storage = 'e';
00403         else if (pg_strcasecmp(a, "extended") == 0)
00404             storage = 'x';
00405         else if (pg_strcasecmp(a, "main") == 0)
00406             storage = 'm';
00407         else
00408             ereport(ERROR,
00409                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00410                      errmsg("storage \"%s\" not recognized", a)));
00411     }
00412     if (collatableEl)
00413         collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
00414 
00415     /*
00416      * make sure we have our required definitions
00417      */
00418     if (inputName == NIL)
00419         ereport(ERROR,
00420                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00421                  errmsg("type input function must be specified")));
00422     if (outputName == NIL)
00423         ereport(ERROR,
00424                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00425                  errmsg("type output function must be specified")));
00426 
00427     if (typmodinName == NIL && typmodoutName != NIL)
00428         ereport(ERROR,
00429                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00430                  errmsg("type modifier output function is useless without a type modifier input function")));
00431 
00432     /*
00433      * Convert I/O proc names to OIDs
00434      */
00435     inputOid = findTypeInputFunction(inputName, typoid);
00436     outputOid = findTypeOutputFunction(outputName, typoid);
00437     if (receiveName)
00438         receiveOid = findTypeReceiveFunction(receiveName, typoid);
00439     if (sendName)
00440         sendOid = findTypeSendFunction(sendName, typoid);
00441 
00442     /*
00443      * Verify that I/O procs return the expected thing.  If we see OPAQUE,
00444      * complain and change it to the correct type-safe choice.
00445      */
00446     resulttype = get_func_rettype(inputOid);
00447     if (resulttype != typoid)
00448     {
00449         if (resulttype == OPAQUEOID)
00450         {
00451             /* backwards-compatibility hack */
00452             ereport(WARNING,
00453                     (errmsg("changing return type of function %s from \"opaque\" to %s",
00454                             NameListToString(inputName), typeName)));
00455             SetFunctionReturnType(inputOid, typoid);
00456         }
00457         else
00458             ereport(ERROR,
00459                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00460                      errmsg("type input function %s must return type %s",
00461                             NameListToString(inputName), typeName)));
00462     }
00463     resulttype = get_func_rettype(outputOid);
00464     if (resulttype != CSTRINGOID)
00465     {
00466         if (resulttype == OPAQUEOID)
00467         {
00468             /* backwards-compatibility hack */
00469             ereport(WARNING,
00470                     (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
00471                             NameListToString(outputName))));
00472             SetFunctionReturnType(outputOid, CSTRINGOID);
00473         }
00474         else
00475             ereport(ERROR,
00476                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00477                errmsg("type output function %s must return type \"cstring\"",
00478                       NameListToString(outputName))));
00479     }
00480     if (receiveOid)
00481     {
00482         resulttype = get_func_rettype(receiveOid);
00483         if (resulttype != typoid)
00484             ereport(ERROR,
00485                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00486                      errmsg("type receive function %s must return type %s",
00487                             NameListToString(receiveName), typeName)));
00488     }
00489     if (sendOid)
00490     {
00491         resulttype = get_func_rettype(sendOid);
00492         if (resulttype != BYTEAOID)
00493             ereport(ERROR,
00494                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00495                    errmsg("type send function %s must return type \"bytea\"",
00496                           NameListToString(sendName))));
00497     }
00498 
00499     /*
00500      * Convert typmodin/out function proc names to OIDs.
00501      */
00502     if (typmodinName)
00503         typmodinOid = findTypeTypmodinFunction(typmodinName);
00504     if (typmodoutName)
00505         typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
00506 
00507     /*
00508      * Convert analysis function proc name to an OID. If no analysis function
00509      * is specified, we'll use zero to select the built-in default algorithm.
00510      */
00511     if (analyzeName)
00512         analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
00513 
00514     /*
00515      * Check permissions on functions.  We choose to require the creator/owner
00516      * of a type to also own the underlying functions.  Since creating a type
00517      * is tantamount to granting public execute access on the functions, the
00518      * minimum sane check would be for execute-with-grant-option.  But we
00519      * don't have a way to make the type go away if the grant option is
00520      * revoked, so ownership seems better.
00521      */
00522 #ifdef NOT_USED
00523     /* XXX this is unnecessary given the superuser check above */
00524     if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
00525         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00526                        NameListToString(inputName));
00527     if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
00528         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00529                        NameListToString(outputName));
00530     if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
00531         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00532                        NameListToString(receiveName));
00533     if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
00534         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00535                        NameListToString(sendName));
00536     if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
00537         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00538                        NameListToString(typmodinName));
00539     if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
00540         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00541                        NameListToString(typmodoutName));
00542     if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
00543         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00544                        NameListToString(analyzeName));
00545 #endif
00546 
00547     array_oid = AssignTypeArrayOid();
00548 
00549     /*
00550      * now have TypeCreate do all the real work.
00551      *
00552      * Note: the pg_type.oid is stored in user tables as array elements (base
00553      * types) in ArrayType and in composite types in DatumTupleFields.  This
00554      * oid must be preserved by binary upgrades.
00555      */
00556     typoid =
00557         TypeCreate(InvalidOid,  /* no predetermined type OID */
00558                    typeName,    /* type name */
00559                    typeNamespace,       /* namespace */
00560                    InvalidOid,  /* relation oid (n/a here) */
00561                    0,           /* relation kind (ditto) */
00562                    GetUserId(), /* owner's ID */
00563                    internalLength,      /* internal size */
00564                    TYPTYPE_BASE,    /* type-type (base type) */
00565                    category,    /* type-category */
00566                    preferred,   /* is it a preferred type? */
00567                    delimiter,   /* array element delimiter */
00568                    inputOid,    /* input procedure */
00569                    outputOid,   /* output procedure */
00570                    receiveOid,  /* receive procedure */
00571                    sendOid,     /* send procedure */
00572                    typmodinOid, /* typmodin procedure */
00573                    typmodoutOid,    /* typmodout procedure */
00574                    analyzeOid,  /* analyze procedure */
00575                    elemType,    /* element type ID */
00576                    false,       /* this is not an array type */
00577                    array_oid,   /* array type we are about to create */
00578                    InvalidOid,  /* base type ID (only for domains) */
00579                    defaultValue,    /* default type value */
00580                    NULL,        /* no binary form available */
00581                    byValue,     /* passed by value */
00582                    alignment,   /* required alignment */
00583                    storage,     /* TOAST strategy */
00584                    -1,          /* typMod (Domains only) */
00585                    0,           /* Array Dimensions of typbasetype */
00586                    false,       /* Type NOT NULL */
00587                    collation);  /* type's collation */
00588 
00589     /*
00590      * Create the array type that goes with it.
00591      */
00592     array_type = makeArrayTypeName(typeName, typeNamespace);
00593 
00594     /* alignment must be 'i' or 'd' for arrays */
00595     alignment = (alignment == 'd') ? 'd' : 'i';
00596 
00597     typoid = TypeCreate(array_oid,      /* force assignment of this type OID */
00598                         array_type,     /* type name */
00599                         typeNamespace,  /* namespace */
00600                         InvalidOid,     /* relation oid (n/a here) */
00601                         0,              /* relation kind (ditto) */
00602                         GetUserId(),        /* owner's ID */
00603                         -1,             /* internal size (always varlena) */
00604                         TYPTYPE_BASE,   /* type-type (base type) */
00605                         TYPCATEGORY_ARRAY,      /* type-category (array) */
00606                         false,          /* array types are never preferred */
00607                         delimiter,      /* array element delimiter */
00608                         F_ARRAY_IN,     /* input procedure */
00609                         F_ARRAY_OUT,        /* output procedure */
00610                         F_ARRAY_RECV,   /* receive procedure */
00611                         F_ARRAY_SEND,   /* send procedure */
00612                         typmodinOid,        /* typmodin procedure */
00613                         typmodoutOid,   /* typmodout procedure */
00614                         F_ARRAY_TYPANALYZE,     /* analyze procedure */
00615                         typoid,         /* element type ID */
00616                         true,           /* yes this is an array type */
00617                         InvalidOid,     /* no further array type */
00618                         InvalidOid,     /* base type ID */
00619                         NULL,           /* never a default type value */
00620                         NULL,           /* binary default isn't sent either */
00621                         false,          /* never passed by value */
00622                         alignment,      /* see above */
00623                         'x',                /* ARRAY is always toastable */
00624                         -1,             /* typMod (Domains only) */
00625                         0,              /* Array dimensions of typbasetype */
00626                         false,          /* Type NOT NULL */
00627                         collation);     /* type's collation */
00628 
00629     pfree(array_type);
00630 
00631     return typoid;
00632 }
00633 
00634 /*
00635  * Guts of type deletion.
00636  */
00637 void
00638 RemoveTypeById(Oid typeOid)
00639 {
00640     Relation    relation;
00641     HeapTuple   tup;
00642 
00643     relation = heap_open(TypeRelationId, RowExclusiveLock);
00644 
00645     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
00646     if (!HeapTupleIsValid(tup))
00647         elog(ERROR, "cache lookup failed for type %u", typeOid);
00648 
00649     simple_heap_delete(relation, &tup->t_self);
00650 
00651     /*
00652      * If it is an enum, delete the pg_enum entries too; we don't bother with
00653      * making dependency entries for those, so it has to be done "by hand"
00654      * here.
00655      */
00656     if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
00657         EnumValuesDelete(typeOid);
00658 
00659     /*
00660      * If it is a range type, delete the pg_range entry too; we don't bother
00661      * with making a dependency entry for that, so it has to be done "by hand"
00662      * here.
00663      */
00664     if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
00665         RangeDelete(typeOid);
00666 
00667     ReleaseSysCache(tup);
00668 
00669     heap_close(relation, RowExclusiveLock);
00670 }
00671 
00672 
00673 /*
00674  * DefineDomain
00675  *      Registers a new domain.
00676  */
00677 Oid
00678 DefineDomain(CreateDomainStmt *stmt)
00679 {
00680     char       *domainName;
00681     Oid         domainNamespace;
00682     AclResult   aclresult;
00683     int16       internalLength;
00684     Oid         inputProcedure;
00685     Oid         outputProcedure;
00686     Oid         receiveProcedure;
00687     Oid         sendProcedure;
00688     Oid         analyzeProcedure;
00689     bool        byValue;
00690     char        category;
00691     char        delimiter;
00692     char        alignment;
00693     char        storage;
00694     char        typtype;
00695     Datum       datum;
00696     bool        isnull;
00697     char       *defaultValue = NULL;
00698     char       *defaultValueBin = NULL;
00699     bool        saw_default = false;
00700     bool        typNotNull = false;
00701     bool        nullDefined = false;
00702     int32       typNDims = list_length(stmt->typeName->arrayBounds);
00703     HeapTuple   typeTup;
00704     List       *schema = stmt->constraints;
00705     ListCell   *listptr;
00706     Oid         basetypeoid;
00707     Oid         domainoid;
00708     Oid         old_type_oid;
00709     Oid         domaincoll;
00710     Form_pg_type baseType;
00711     int32       basetypeMod;
00712     Oid         baseColl;
00713 
00714     /* Convert list of names to a name and namespace */
00715     domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
00716                                                         &domainName);
00717 
00718     /* Check we have creation rights in target namespace */
00719     aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
00720                                       ACL_CREATE);
00721     if (aclresult != ACLCHECK_OK)
00722         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00723                        get_namespace_name(domainNamespace));
00724 
00725     /*
00726      * Check for collision with an existing type name.  If there is one and
00727      * it's an autogenerated array, we can rename it out of the way.
00728      */
00729     old_type_oid = GetSysCacheOid2(TYPENAMENSP,
00730                                    CStringGetDatum(domainName),
00731                                    ObjectIdGetDatum(domainNamespace));
00732     if (OidIsValid(old_type_oid))
00733     {
00734         if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
00735             ereport(ERROR,
00736                     (errcode(ERRCODE_DUPLICATE_OBJECT),
00737                      errmsg("type \"%s\" already exists", domainName)));
00738     }
00739 
00740     /*
00741      * Look up the base type.
00742      */
00743     typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
00744     baseType = (Form_pg_type) GETSTRUCT(typeTup);
00745     basetypeoid = HeapTupleGetOid(typeTup);
00746 
00747     /*
00748      * Base type must be a plain base type, another domain, an enum or a range
00749      * type. Domains over pseudotypes would create a security hole.  Domains
00750      * over composite types might be made to work in the future, but not
00751      * today.
00752      */
00753     typtype = baseType->typtype;
00754     if (typtype != TYPTYPE_BASE &&
00755         typtype != TYPTYPE_DOMAIN &&
00756         typtype != TYPTYPE_ENUM &&
00757         typtype != TYPTYPE_RANGE)
00758         ereport(ERROR,
00759                 (errcode(ERRCODE_DATATYPE_MISMATCH),
00760                  errmsg("\"%s\" is not a valid base type for a domain",
00761                         TypeNameToString(stmt->typeName))));
00762 
00763     aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
00764     if (aclresult != ACLCHECK_OK)
00765         aclcheck_error_type(aclresult, basetypeoid);
00766 
00767     /*
00768      * Identify the collation if any
00769      */
00770     baseColl = baseType->typcollation;
00771     if (stmt->collClause)
00772         domaincoll = get_collation_oid(stmt->collClause->collname, false);
00773     else
00774         domaincoll = baseColl;
00775 
00776     /* Complain if COLLATE is applied to an uncollatable type */
00777     if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
00778         ereport(ERROR,
00779                 (errcode(ERRCODE_DATATYPE_MISMATCH),
00780                  errmsg("collations are not supported by type %s",
00781                         format_type_be(basetypeoid))));
00782 
00783     /* passed by value */
00784     byValue = baseType->typbyval;
00785 
00786     /* Required Alignment */
00787     alignment = baseType->typalign;
00788 
00789     /* TOAST Strategy */
00790     storage = baseType->typstorage;
00791 
00792     /* Storage Length */
00793     internalLength = baseType->typlen;
00794 
00795     /* Type Category */
00796     category = baseType->typcategory;
00797 
00798     /* Array element Delimiter */
00799     delimiter = baseType->typdelim;
00800 
00801     /* I/O Functions */
00802     inputProcedure = F_DOMAIN_IN;
00803     outputProcedure = baseType->typoutput;
00804     receiveProcedure = F_DOMAIN_RECV;
00805     sendProcedure = baseType->typsend;
00806 
00807     /* Domains never accept typmods, so no typmodin/typmodout needed */
00808 
00809     /* Analysis function */
00810     analyzeProcedure = baseType->typanalyze;
00811 
00812     /* Inherited default value */
00813     datum = SysCacheGetAttr(TYPEOID, typeTup,
00814                             Anum_pg_type_typdefault, &isnull);
00815     if (!isnull)
00816         defaultValue = TextDatumGetCString(datum);
00817 
00818     /* Inherited default binary value */
00819     datum = SysCacheGetAttr(TYPEOID, typeTup,
00820                             Anum_pg_type_typdefaultbin, &isnull);
00821     if (!isnull)
00822         defaultValueBin = TextDatumGetCString(datum);
00823 
00824     /*
00825      * Run through constraints manually to avoid the additional processing
00826      * conducted by DefineRelation() and friends.
00827      */
00828     foreach(listptr, schema)
00829     {
00830         Constraint *constr = lfirst(listptr);
00831 
00832         if (!IsA(constr, Constraint))
00833             elog(ERROR, "unrecognized node type: %d",
00834                  (int) nodeTag(constr));
00835         switch (constr->contype)
00836         {
00837             case CONSTR_DEFAULT:
00838 
00839                 /*
00840                  * The inherited default value may be overridden by the user
00841                  * with the DEFAULT <expr> clause ... but only once.
00842                  */
00843                 if (saw_default)
00844                     ereport(ERROR,
00845                             (errcode(ERRCODE_SYNTAX_ERROR),
00846                              errmsg("multiple default expressions")));
00847                 saw_default = true;
00848 
00849                 if (constr->raw_expr)
00850                 {
00851                     ParseState *pstate;
00852                     Node       *defaultExpr;
00853 
00854                     /* Create a dummy ParseState for transformExpr */
00855                     pstate = make_parsestate(NULL);
00856 
00857                     /*
00858                      * Cook the constr->raw_expr into an expression. Note:
00859                      * name is strictly for error message
00860                      */
00861                     defaultExpr = cookDefault(pstate, constr->raw_expr,
00862                                               basetypeoid,
00863                                               basetypeMod,
00864                                               domainName);
00865 
00866                     /*
00867                      * If the expression is just a NULL constant, we treat it
00868                      * like not having a default.
00869                      *
00870                      * Note that if the basetype is another domain, we'll see
00871                      * a CoerceToDomain expr here and not discard the default.
00872                      * This is critical because the domain default needs to be
00873                      * retained to override any default that the base domain
00874                      * might have.
00875                      */
00876                     if (defaultExpr == NULL ||
00877                         (IsA(defaultExpr, Const) &&
00878                          ((Const *) defaultExpr)->constisnull))
00879                     {
00880                         defaultValue = NULL;
00881                         defaultValueBin = NULL;
00882                     }
00883                     else
00884                     {
00885                         /*
00886                          * Expression must be stored as a nodeToString result,
00887                          * but we also require a valid textual representation
00888                          * (mainly to make life easier for pg_dump).
00889                          */
00890                         defaultValue =
00891                             deparse_expression(defaultExpr,
00892                                                NIL, false, false);
00893                         defaultValueBin = nodeToString(defaultExpr);
00894                     }
00895                 }
00896                 else
00897                 {
00898                     /* No default (can this still happen?) */
00899                     defaultValue = NULL;
00900                     defaultValueBin = NULL;
00901                 }
00902                 break;
00903 
00904             case CONSTR_NOTNULL:
00905                 if (nullDefined && !typNotNull)
00906                     ereport(ERROR,
00907                             (errcode(ERRCODE_SYNTAX_ERROR),
00908                            errmsg("conflicting NULL/NOT NULL constraints")));
00909                 typNotNull = true;
00910                 nullDefined = true;
00911                 break;
00912 
00913             case CONSTR_NULL:
00914                 if (nullDefined && typNotNull)
00915                     ereport(ERROR,
00916                             (errcode(ERRCODE_SYNTAX_ERROR),
00917                            errmsg("conflicting NULL/NOT NULL constraints")));
00918                 typNotNull = false;
00919                 nullDefined = true;
00920                 break;
00921 
00922             case CONSTR_CHECK:
00923 
00924                 /*
00925                  * Check constraints are handled after domain creation, as
00926                  * they require the Oid of the domain; at this point we can
00927                  * only check that they're not marked NO INHERIT, because
00928                  * that would be bogus.
00929                  */
00930                 if (constr->is_no_inherit)
00931                     ereport(ERROR,
00932                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00933                              errmsg("check constraints for domains cannot be marked NO INHERIT")));
00934                 break;
00935 
00936                 /*
00937                  * All else are error cases
00938                  */
00939             case CONSTR_UNIQUE:
00940                 ereport(ERROR,
00941                         (errcode(ERRCODE_SYNTAX_ERROR),
00942                      errmsg("unique constraints not possible for domains")));
00943                 break;
00944 
00945             case CONSTR_PRIMARY:
00946                 ereport(ERROR,
00947                         (errcode(ERRCODE_SYNTAX_ERROR),
00948                 errmsg("primary key constraints not possible for domains")));
00949                 break;
00950 
00951             case CONSTR_EXCLUSION:
00952                 ereport(ERROR,
00953                         (errcode(ERRCODE_SYNTAX_ERROR),
00954                   errmsg("exclusion constraints not possible for domains")));
00955                 break;
00956 
00957             case CONSTR_FOREIGN:
00958                 ereport(ERROR,
00959                         (errcode(ERRCODE_SYNTAX_ERROR),
00960                 errmsg("foreign key constraints not possible for domains")));
00961                 break;
00962 
00963             case CONSTR_ATTR_DEFERRABLE:
00964             case CONSTR_ATTR_NOT_DEFERRABLE:
00965             case CONSTR_ATTR_DEFERRED:
00966             case CONSTR_ATTR_IMMEDIATE:
00967                 ereport(ERROR,
00968                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00969                          errmsg("specifying constraint deferrability not supported for domains")));
00970                 break;
00971 
00972             default:
00973                 elog(ERROR, "unrecognized constraint subtype: %d",
00974                      (int) constr->contype);
00975                 break;
00976         }
00977     }
00978 
00979     /*
00980      * Have TypeCreate do all the real work.
00981      */
00982     domainoid =
00983         TypeCreate(InvalidOid,  /* no predetermined type OID */
00984                    domainName,  /* type name */
00985                    domainNamespace,     /* namespace */
00986                    InvalidOid,  /* relation oid (n/a here) */
00987                    0,           /* relation kind (ditto) */
00988                    GetUserId(), /* owner's ID */
00989                    internalLength,      /* internal size */
00990                    TYPTYPE_DOMAIN,      /* type-type (domain type) */
00991                    category,    /* type-category */
00992                    false,       /* domain types are never preferred */
00993                    delimiter,   /* array element delimiter */
00994                    inputProcedure,      /* input procedure */
00995                    outputProcedure,     /* output procedure */
00996                    receiveProcedure,    /* receive procedure */
00997                    sendProcedure,       /* send procedure */
00998                    InvalidOid,  /* typmodin procedure - none */
00999                    InvalidOid,  /* typmodout procedure - none */
01000                    analyzeProcedure,    /* analyze procedure */
01001                    InvalidOid,  /* no array element type */
01002                    false,       /* this isn't an array */
01003                    InvalidOid,  /* no arrays for domains (yet) */
01004                    basetypeoid, /* base type ID */
01005                    defaultValue,    /* default type value (text) */
01006                    defaultValueBin,     /* default type value (binary) */
01007                    byValue,     /* passed by value */
01008                    alignment,   /* required alignment */
01009                    storage,     /* TOAST strategy */
01010                    basetypeMod, /* typeMod value */
01011                    typNDims,    /* Array dimensions for base type */
01012                    typNotNull,  /* Type NOT NULL */
01013                    domaincoll); /* type's collation */
01014 
01015     /*
01016      * Process constraints which refer to the domain ID returned by TypeCreate
01017      */
01018     foreach(listptr, schema)
01019     {
01020         Constraint *constr = lfirst(listptr);
01021 
01022         /* it must be a Constraint, per check above */
01023 
01024         switch (constr->contype)
01025         {
01026             case CONSTR_CHECK:
01027                 domainAddConstraint(domainoid, domainNamespace,
01028                                     basetypeoid, basetypeMod,
01029                                     constr, domainName);
01030                 break;
01031 
01032                 /* Other constraint types were fully processed above */
01033 
01034             default:
01035                 break;
01036         }
01037 
01038         /* CCI so we can detect duplicate constraint names */
01039         CommandCounterIncrement();
01040     }
01041 
01042     /*
01043      * Now we can clean up.
01044      */
01045     ReleaseSysCache(typeTup);
01046 
01047     return domainoid;
01048 }
01049 
01050 
01051 /*
01052  * DefineEnum
01053  *      Registers a new enum.
01054  */
01055 Oid
01056 DefineEnum(CreateEnumStmt *stmt)
01057 {
01058     char       *enumName;
01059     char       *enumArrayName;
01060     Oid         enumNamespace;
01061     Oid         enumTypeOid;
01062     AclResult   aclresult;
01063     Oid         old_type_oid;
01064     Oid         enumArrayOid;
01065 
01066     /* Convert list of names to a name and namespace */
01067     enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
01068                                                       &enumName);
01069 
01070     /* Check we have creation rights in target namespace */
01071     aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
01072     if (aclresult != ACLCHECK_OK)
01073         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
01074                        get_namespace_name(enumNamespace));
01075 
01076     /*
01077      * Check for collision with an existing type name.  If there is one and
01078      * it's an autogenerated array, we can rename it out of the way.
01079      */
01080     old_type_oid = GetSysCacheOid2(TYPENAMENSP,
01081                                    CStringGetDatum(enumName),
01082                                    ObjectIdGetDatum(enumNamespace));
01083     if (OidIsValid(old_type_oid))
01084     {
01085         if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
01086             ereport(ERROR,
01087                     (errcode(ERRCODE_DUPLICATE_OBJECT),
01088                      errmsg("type \"%s\" already exists", enumName)));
01089     }
01090 
01091     enumArrayOid = AssignTypeArrayOid();
01092 
01093     /* Create the pg_type entry */
01094     enumTypeOid =
01095         TypeCreate(InvalidOid,  /* no predetermined type OID */
01096                    enumName,    /* type name */
01097                    enumNamespace,       /* namespace */
01098                    InvalidOid,  /* relation oid (n/a here) */
01099                    0,           /* relation kind (ditto) */
01100                    GetUserId(), /* owner's ID */
01101                    sizeof(Oid), /* internal size */
01102                    TYPTYPE_ENUM,    /* type-type (enum type) */
01103                    TYPCATEGORY_ENUM,    /* type-category (enum type) */
01104                    false,       /* enum types are never preferred */
01105                    DEFAULT_TYPDELIM,    /* array element delimiter */
01106                    F_ENUM_IN,   /* input procedure */
01107                    F_ENUM_OUT,  /* output procedure */
01108                    F_ENUM_RECV, /* receive procedure */
01109                    F_ENUM_SEND, /* send procedure */
01110                    InvalidOid,  /* typmodin procedure - none */
01111                    InvalidOid,  /* typmodout procedure - none */
01112                    InvalidOid,  /* analyze procedure - default */
01113                    InvalidOid,  /* element type ID */
01114                    false,       /* this is not an array type */
01115                    enumArrayOid,    /* array type we are about to create */
01116                    InvalidOid,  /* base type ID (only for domains) */
01117                    NULL,        /* never a default type value */
01118                    NULL,        /* binary default isn't sent either */
01119                    true,        /* always passed by value */
01120                    'i',         /* int alignment */
01121                    'p',         /* TOAST strategy always plain */
01122                    -1,          /* typMod (Domains only) */
01123                    0,           /* Array dimensions of typbasetype */
01124                    false,       /* Type NOT NULL */
01125                    InvalidOid); /* type's collation */
01126 
01127     /* Enter the enum's values into pg_enum */
01128     EnumValuesCreate(enumTypeOid, stmt->vals);
01129 
01130     /*
01131      * Create the array type that goes with it.
01132      */
01133     enumArrayName = makeArrayTypeName(enumName, enumNamespace);
01134 
01135     TypeCreate(enumArrayOid,    /* force assignment of this type OID */
01136                enumArrayName,   /* type name */
01137                enumNamespace,   /* namespace */
01138                InvalidOid,      /* relation oid (n/a here) */
01139                0,               /* relation kind (ditto) */
01140                GetUserId(),     /* owner's ID */
01141                -1,              /* internal size (always varlena) */
01142                TYPTYPE_BASE,    /* type-type (base type) */
01143                TYPCATEGORY_ARRAY,       /* type-category (array) */
01144                false,           /* array types are never preferred */
01145                DEFAULT_TYPDELIM,    /* array element delimiter */
01146                F_ARRAY_IN,      /* input procedure */
01147                F_ARRAY_OUT,     /* output procedure */
01148                F_ARRAY_RECV,    /* receive procedure */
01149                F_ARRAY_SEND,    /* send procedure */
01150                InvalidOid,      /* typmodin procedure - none */
01151                InvalidOid,      /* typmodout procedure - none */
01152                F_ARRAY_TYPANALYZE,      /* analyze procedure */
01153                enumTypeOid,     /* element type ID */
01154                true,            /* yes this is an array type */
01155                InvalidOid,      /* no further array type */
01156                InvalidOid,      /* base type ID */
01157                NULL,            /* never a default type value */
01158                NULL,            /* binary default isn't sent either */
01159                false,           /* never passed by value */
01160                'i',             /* enums have align i, so do their arrays */
01161                'x',             /* ARRAY is always toastable */
01162                -1,              /* typMod (Domains only) */
01163                0,               /* Array dimensions of typbasetype */
01164                false,           /* Type NOT NULL */
01165                InvalidOid);     /* type's collation */
01166 
01167     pfree(enumArrayName);
01168 
01169     return enumTypeOid;
01170 }
01171 
01172 /*
01173  * AlterEnum
01174  *      Adds a new label to an existing enum.
01175  */
01176 Oid
01177 AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
01178 {
01179     Oid         enum_type_oid;
01180     TypeName   *typename;
01181     HeapTuple   tup;
01182 
01183     /* Make a TypeName so we can use standard type lookup machinery */
01184     typename = makeTypeNameFromNameList(stmt->typeName);
01185     enum_type_oid = typenameTypeId(NULL, typename);
01186 
01187     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
01188     if (!HeapTupleIsValid(tup))
01189         elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
01190 
01191     /*
01192      * Ordinarily we disallow adding values within transaction blocks, because
01193      * we can't cope with enum OID values getting into indexes and then having
01194      * their defining pg_enum entries go away.  However, it's okay if the enum
01195      * type was created in the current transaction, since then there can be
01196      * no such indexes that wouldn't themselves go away on rollback.  (We
01197      * support this case because pg_dump --binary-upgrade needs it.)  We test
01198      * this by seeing if the pg_type row has xmin == current XID and is not
01199      * HEAP_UPDATED.  If it is HEAP_UPDATED, we can't be sure whether the
01200      * type was created or only modified in this xact.  So we are disallowing
01201      * some cases that could theoretically be safe; but fortunately pg_dump
01202      * only needs the simplest case.
01203      */
01204     if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
01205         !(tup->t_data->t_infomask & HEAP_UPDATED))
01206         /* safe to do inside transaction block */ ;
01207     else
01208         PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
01209 
01210     /* Check it's an enum and check user has permission to ALTER the enum */
01211     checkEnumOwner(tup);
01212 
01213     /* Add the new label */
01214     AddEnumLabel(enum_type_oid, stmt->newVal,
01215                  stmt->newValNeighbor, stmt->newValIsAfter,
01216                  stmt->skipIfExists);
01217 
01218     InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
01219 
01220     ReleaseSysCache(tup);
01221 
01222     return enum_type_oid;
01223 }
01224 
01225 
01226 /*
01227  * checkEnumOwner
01228  *
01229  * Check that the type is actually an enum and that the current user
01230  * has permission to do ALTER TYPE on it.  Throw an error if not.
01231  */
01232 static void
01233 checkEnumOwner(HeapTuple tup)
01234 {
01235     Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
01236 
01237     /* Check that this is actually an enum */
01238     if (typTup->typtype != TYPTYPE_ENUM)
01239         ereport(ERROR,
01240                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01241                  errmsg("%s is not an enum",
01242                         format_type_be(HeapTupleGetOid(tup)))));
01243 
01244     /* Permission check: must own type */
01245     if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
01246         aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
01247 }
01248 
01249 
01250 /*
01251  * DefineRange
01252  *      Registers a new range type.
01253  */
01254 Oid
01255 DefineRange(CreateRangeStmt *stmt)
01256 {
01257     char       *typeName;
01258     Oid         typeNamespace;
01259     Oid         typoid;
01260     char       *rangeArrayName;
01261     Oid         rangeArrayOid;
01262     Oid         rangeSubtype = InvalidOid;
01263     List       *rangeSubOpclassName = NIL;
01264     List       *rangeCollationName = NIL;
01265     List       *rangeCanonicalName = NIL;
01266     List       *rangeSubtypeDiffName = NIL;
01267     Oid         rangeSubOpclass;
01268     Oid         rangeCollation;
01269     regproc     rangeCanonical;
01270     regproc     rangeSubtypeDiff;
01271     int16       subtyplen;
01272     bool        subtypbyval;
01273     char        subtypalign;
01274     char        alignment;
01275     AclResult   aclresult;
01276     ListCell   *lc;
01277 
01278     /* Convert list of names to a name and namespace */
01279     typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
01280                                                       &typeName);
01281 
01282     /* Check we have creation rights in target namespace */
01283     aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
01284     if (aclresult != ACLCHECK_OK)
01285         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
01286                        get_namespace_name(typeNamespace));
01287 
01288     /*
01289      * Look to see if type already exists.
01290      */
01291     typoid = GetSysCacheOid2(TYPENAMENSP,
01292                              CStringGetDatum(typeName),
01293                              ObjectIdGetDatum(typeNamespace));
01294 
01295     /*
01296      * If it's not a shell, see if it's an autogenerated array type, and if so
01297      * rename it out of the way.
01298      */
01299     if (OidIsValid(typoid) && get_typisdefined(typoid))
01300     {
01301         if (moveArrayTypeName(typoid, typeName, typeNamespace))
01302             typoid = InvalidOid;
01303         else
01304             ereport(ERROR,
01305                     (errcode(ERRCODE_DUPLICATE_OBJECT),
01306                      errmsg("type \"%s\" already exists", typeName)));
01307     }
01308 
01309     /*
01310      * If it doesn't exist, create it as a shell, so that the OID is known for
01311      * use in the range function definitions.
01312      */
01313     if (!OidIsValid(typoid))
01314     {
01315         typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
01316         /* Make new shell type visible for modification below */
01317         CommandCounterIncrement();
01318     }
01319 
01320     /* Extract the parameters from the parameter list */
01321     foreach(lc, stmt->params)
01322     {
01323         DefElem    *defel = (DefElem *) lfirst(lc);
01324 
01325         if (pg_strcasecmp(defel->defname, "subtype") == 0)
01326         {
01327             if (OidIsValid(rangeSubtype))
01328                 ereport(ERROR,
01329                         (errcode(ERRCODE_SYNTAX_ERROR),
01330                          errmsg("conflicting or redundant options")));
01331             /* we can look up the subtype name immediately */
01332             rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
01333         }
01334         else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
01335         {
01336             if (rangeSubOpclassName != NIL)
01337                 ereport(ERROR,
01338                         (errcode(ERRCODE_SYNTAX_ERROR),
01339                          errmsg("conflicting or redundant options")));
01340             rangeSubOpclassName = defGetQualifiedName(defel);
01341         }
01342         else if (pg_strcasecmp(defel->defname, "collation") == 0)
01343         {
01344             if (rangeCollationName != NIL)
01345                 ereport(ERROR,
01346                         (errcode(ERRCODE_SYNTAX_ERROR),
01347                          errmsg("conflicting or redundant options")));
01348             rangeCollationName = defGetQualifiedName(defel);
01349         }
01350         else if (pg_strcasecmp(defel->defname, "canonical") == 0)
01351         {
01352             if (rangeCanonicalName != NIL)
01353                 ereport(ERROR,
01354                         (errcode(ERRCODE_SYNTAX_ERROR),
01355                          errmsg("conflicting or redundant options")));
01356             rangeCanonicalName = defGetQualifiedName(defel);
01357         }
01358         else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
01359         {
01360             if (rangeSubtypeDiffName != NIL)
01361                 ereport(ERROR,
01362                         (errcode(ERRCODE_SYNTAX_ERROR),
01363                          errmsg("conflicting or redundant options")));
01364             rangeSubtypeDiffName = defGetQualifiedName(defel);
01365         }
01366         else
01367             ereport(ERROR,
01368                     (errcode(ERRCODE_SYNTAX_ERROR),
01369                      errmsg("type attribute \"%s\" not recognized",
01370                             defel->defname)));
01371     }
01372 
01373     /* Must have a subtype */
01374     if (!OidIsValid(rangeSubtype))
01375         ereport(ERROR,
01376                 (errcode(ERRCODE_SYNTAX_ERROR),
01377                  errmsg("type attribute \"subtype\" is required")));
01378     /* disallow ranges of pseudotypes */
01379     if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
01380         ereport(ERROR,
01381                 (errcode(ERRCODE_DATATYPE_MISMATCH),
01382                  errmsg("range subtype cannot be %s",
01383                         format_type_be(rangeSubtype))));
01384 
01385     /* Identify subopclass */
01386     rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
01387 
01388     /* Identify collation to use, if any */
01389     if (type_is_collatable(rangeSubtype))
01390     {
01391         if (rangeCollationName != NIL)
01392             rangeCollation = get_collation_oid(rangeCollationName, false);
01393         else
01394             rangeCollation = get_typcollation(rangeSubtype);
01395     }
01396     else
01397     {
01398         if (rangeCollationName != NIL)
01399             ereport(ERROR,
01400                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01401                      errmsg("range collation specified but subtype does not support collation")));
01402         rangeCollation = InvalidOid;
01403     }
01404 
01405     /* Identify support functions, if provided */
01406     if (rangeCanonicalName != NIL)
01407         rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
01408                                                     typoid);
01409     else
01410         rangeCanonical = InvalidOid;
01411 
01412     if (rangeSubtypeDiffName != NIL)
01413         rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
01414                                                         rangeSubtype);
01415     else
01416         rangeSubtypeDiff = InvalidOid;
01417 
01418     get_typlenbyvalalign(rangeSubtype,
01419                          &subtyplen, &subtypbyval, &subtypalign);
01420 
01421     /* alignment must be 'i' or 'd' for ranges */
01422     alignment = (subtypalign == 'd') ? 'd' : 'i';
01423 
01424     /* Allocate OID for array type */
01425     rangeArrayOid = AssignTypeArrayOid();
01426 
01427     /* Create the pg_type entry */
01428     typoid =
01429         TypeCreate(InvalidOid,  /* no predetermined type OID */
01430                    typeName,    /* type name */
01431                    typeNamespace,       /* namespace */
01432                    InvalidOid,  /* relation oid (n/a here) */
01433                    0,           /* relation kind (ditto) */
01434                    GetUserId(), /* owner's ID */
01435                    -1,          /* internal size (always varlena) */
01436                    TYPTYPE_RANGE,       /* type-type (range type) */
01437                    TYPCATEGORY_RANGE,   /* type-category (range type) */
01438                    false,       /* range types are never preferred */
01439                    DEFAULT_TYPDELIM,    /* array element delimiter */
01440                    F_RANGE_IN,  /* input procedure */
01441                    F_RANGE_OUT, /* output procedure */
01442                    F_RANGE_RECV,    /* receive procedure */
01443                    F_RANGE_SEND,    /* send procedure */
01444                    InvalidOid,  /* typmodin procedure - none */
01445                    InvalidOid,  /* typmodout procedure - none */
01446                    F_RANGE_TYPANALYZE,  /* analyze procedure */
01447                    InvalidOid,  /* element type ID - none */
01448                    false,       /* this is not an array type */
01449                    rangeArrayOid,       /* array type we are about to create */
01450                    InvalidOid,  /* base type ID (only for domains) */
01451                    NULL,        /* never a default type value */
01452                    NULL,        /* no binary form available either */
01453                    false,       /* never passed by value */
01454                    alignment,   /* alignment */
01455                    'x',         /* TOAST strategy (always extended) */
01456                    -1,          /* typMod (Domains only) */
01457                    0,           /* Array dimensions of typbasetype */
01458                    false,       /* Type NOT NULL */
01459                    InvalidOid); /* type's collation (ranges never have one) */
01460 
01461     /* Create the entry in pg_range */
01462     RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
01463                 rangeCanonical, rangeSubtypeDiff);
01464 
01465     /*
01466      * Create the array type that goes with it.
01467      */
01468     rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
01469 
01470     TypeCreate(rangeArrayOid,   /* force assignment of this type OID */
01471                rangeArrayName,  /* type name */
01472                typeNamespace,   /* namespace */
01473                InvalidOid,      /* relation oid (n/a here) */
01474                0,               /* relation kind (ditto) */
01475                GetUserId(),     /* owner's ID */
01476                -1,              /* internal size (always varlena) */
01477                TYPTYPE_BASE,    /* type-type (base type) */
01478                TYPCATEGORY_ARRAY,       /* type-category (array) */
01479                false,           /* array types are never preferred */
01480                DEFAULT_TYPDELIM,    /* array element delimiter */
01481                F_ARRAY_IN,      /* input procedure */
01482                F_ARRAY_OUT,     /* output procedure */
01483                F_ARRAY_RECV,    /* receive procedure */
01484                F_ARRAY_SEND,    /* send procedure */
01485                InvalidOid,      /* typmodin procedure - none */
01486                InvalidOid,      /* typmodout procedure - none */
01487                F_ARRAY_TYPANALYZE,      /* analyze procedure */
01488                typoid,          /* element type ID */
01489                true,            /* yes this is an array type */
01490                InvalidOid,      /* no further array type */
01491                InvalidOid,      /* base type ID */
01492                NULL,            /* never a default type value */
01493                NULL,            /* binary default isn't sent either */
01494                false,           /* never passed by value */
01495                alignment,       /* alignment - same as range's */
01496                'x',             /* ARRAY is always toastable */
01497                -1,              /* typMod (Domains only) */
01498                0,               /* Array dimensions of typbasetype */
01499                false,           /* Type NOT NULL */
01500                InvalidOid);     /* typcollation */
01501 
01502     pfree(rangeArrayName);
01503 
01504     /* And create the constructor functions for this range type */
01505     makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
01506 
01507     return typoid;
01508 }
01509 
01510 /*
01511  * Because there may exist several range types over the same subtype, the
01512  * range type can't be uniquely determined from the subtype.  So it's
01513  * impossible to define a polymorphic constructor; we have to generate new
01514  * constructor functions explicitly for each range type.
01515  *
01516  * We actually define 4 functions, with 0 through 3 arguments.  This is just
01517  * to offer more convenience for the user.
01518  */
01519 static void
01520 makeRangeConstructors(const char *name, Oid namespace,
01521                       Oid rangeOid, Oid subtype)
01522 {
01523     static const char *const prosrc[2] = {"range_constructor2",
01524     "range_constructor3"};
01525     static const int pronargs[2] = {2, 3};
01526 
01527     Oid         constructorArgTypes[3];
01528     ObjectAddress myself,
01529                 referenced;
01530     int         i;
01531 
01532     constructorArgTypes[0] = subtype;
01533     constructorArgTypes[1] = subtype;
01534     constructorArgTypes[2] = TEXTOID;
01535 
01536     referenced.classId = TypeRelationId;
01537     referenced.objectId = rangeOid;
01538     referenced.objectSubId = 0;
01539 
01540     for (i = 0; i < lengthof(prosrc); i++)
01541     {
01542         oidvector  *constructorArgTypesVector;
01543         Oid         procOid;
01544 
01545         constructorArgTypesVector = buildoidvector(constructorArgTypes,
01546                                                    pronargs[i]);
01547 
01548         procOid = ProcedureCreate(name, /* name: same as range type */
01549                                   namespace,    /* namespace */
01550                                   false,        /* replace */
01551                                   false,        /* returns set */
01552                                   rangeOid,     /* return type */
01553                                   BOOTSTRAP_SUPERUSERID,        /* proowner */
01554                                   INTERNALlanguageId,   /* language */
01555                                   F_FMGR_INTERNAL_VALIDATOR,    /* language validator */
01556                                   prosrc[i],    /* prosrc */
01557                                   NULL, /* probin */
01558                                   false,        /* isAgg */
01559                                   false,        /* isWindowFunc */
01560                                   false,        /* security_definer */
01561                                   false,        /* leakproof */
01562                                   false,        /* isStrict */
01563                                   PROVOLATILE_IMMUTABLE,        /* volatility */
01564                                   constructorArgTypesVector,    /* parameterTypes */
01565                                   PointerGetDatum(NULL),        /* allParameterTypes */
01566                                   PointerGetDatum(NULL),        /* parameterModes */
01567                                   PointerGetDatum(NULL),        /* parameterNames */
01568                                   NIL,  /* parameterDefaults */
01569                                   PointerGetDatum(NULL),        /* proconfig */
01570                                   1.0,  /* procost */
01571                                   0.0); /* prorows */
01572 
01573         /*
01574          * Make the constructors internally-dependent on the range type so
01575          * that they go away silently when the type is dropped.  Note that
01576          * pg_dump depends on this choice to avoid dumping the constructors.
01577          */
01578         myself.classId = ProcedureRelationId;
01579         myself.objectId = procOid;
01580         myself.objectSubId = 0;
01581 
01582         recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
01583     }
01584 }
01585 
01586 
01587 /*
01588  * Find suitable I/O functions for a type.
01589  *
01590  * typeOid is the type's OID (which will already exist, if only as a shell
01591  * type).
01592  */
01593 
01594 static Oid
01595 findTypeInputFunction(List *procname, Oid typeOid)
01596 {
01597     Oid         argList[3];
01598     Oid         procOid;
01599 
01600     /*
01601      * Input functions can take a single argument of type CSTRING, or three
01602      * arguments (string, typioparam OID, typmod).
01603      *
01604      * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
01605      * see this, we issue a warning and fix up the pg_proc entry.
01606      */
01607     argList[0] = CSTRINGOID;
01608 
01609     procOid = LookupFuncName(procname, 1, argList, true);
01610     if (OidIsValid(procOid))
01611         return procOid;
01612 
01613     argList[1] = OIDOID;
01614     argList[2] = INT4OID;
01615 
01616     procOid = LookupFuncName(procname, 3, argList, true);
01617     if (OidIsValid(procOid))
01618         return procOid;
01619 
01620     /* No luck, try it with OPAQUE */
01621     argList[0] = OPAQUEOID;
01622 
01623     procOid = LookupFuncName(procname, 1, argList, true);
01624 
01625     if (!OidIsValid(procOid))
01626     {
01627         argList[1] = OIDOID;
01628         argList[2] = INT4OID;
01629 
01630         procOid = LookupFuncName(procname, 3, argList, true);
01631     }
01632 
01633     if (OidIsValid(procOid))
01634     {
01635         /* Found, but must complain and fix the pg_proc entry */
01636         ereport(WARNING,
01637                 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
01638                         NameListToString(procname))));
01639         SetFunctionArgType(procOid, 0, CSTRINGOID);
01640 
01641         /*
01642          * Need CommandCounterIncrement since DefineType will likely try to
01643          * alter the pg_proc tuple again.
01644          */
01645         CommandCounterIncrement();
01646 
01647         return procOid;
01648     }
01649 
01650     /* Use CSTRING (preferred) in the error message */
01651     argList[0] = CSTRINGOID;
01652 
01653     ereport(ERROR,
01654             (errcode(ERRCODE_UNDEFINED_FUNCTION),
01655              errmsg("function %s does not exist",
01656                     func_signature_string(procname, 1, NIL, argList))));
01657 
01658     return InvalidOid;          /* keep compiler quiet */
01659 }
01660 
01661 static Oid
01662 findTypeOutputFunction(List *procname, Oid typeOid)
01663 {
01664     Oid         argList[1];
01665     Oid         procOid;
01666 
01667     /*
01668      * Output functions can take a single argument of the type.
01669      *
01670      * For backwards compatibility we allow OPAQUE in place of the actual type
01671      * name; if we see this, we issue a warning and fix up the pg_proc entry.
01672      */
01673     argList[0] = typeOid;
01674 
01675     procOid = LookupFuncName(procname, 1, argList, true);
01676     if (OidIsValid(procOid))
01677         return procOid;
01678 
01679     /* No luck, try it with OPAQUE */
01680     argList[0] = OPAQUEOID;
01681 
01682     procOid = LookupFuncName(procname, 1, argList, true);
01683 
01684     if (OidIsValid(procOid))
01685     {
01686         /* Found, but must complain and fix the pg_proc entry */
01687         ereport(WARNING,
01688         (errmsg("changing argument type of function %s from \"opaque\" to %s",
01689                 NameListToString(procname), format_type_be(typeOid))));
01690         SetFunctionArgType(procOid, 0, typeOid);
01691 
01692         /*
01693          * Need CommandCounterIncrement since DefineType will likely try to
01694          * alter the pg_proc tuple again.
01695          */
01696         CommandCounterIncrement();
01697 
01698         return procOid;
01699     }
01700 
01701     /* Use type name, not OPAQUE, in the failure message. */
01702     argList[0] = typeOid;
01703 
01704     ereport(ERROR,
01705             (errcode(ERRCODE_UNDEFINED_FUNCTION),
01706              errmsg("function %s does not exist",
01707                     func_signature_string(procname, 1, NIL, argList))));
01708 
01709     return InvalidOid;          /* keep compiler quiet */
01710 }
01711 
01712 static Oid
01713 findTypeReceiveFunction(List *procname, Oid typeOid)
01714 {
01715     Oid         argList[3];
01716     Oid         procOid;
01717 
01718     /*
01719      * Receive functions can take a single argument of type INTERNAL, or three
01720      * arguments (internal, typioparam OID, typmod).
01721      */
01722     argList[0] = INTERNALOID;
01723 
01724     procOid = LookupFuncName(procname, 1, argList, true);
01725     if (OidIsValid(procOid))
01726         return procOid;
01727 
01728     argList[1] = OIDOID;
01729     argList[2] = INT4OID;
01730 
01731     procOid = LookupFuncName(procname, 3, argList, true);
01732     if (OidIsValid(procOid))
01733         return procOid;
01734 
01735     ereport(ERROR,
01736             (errcode(ERRCODE_UNDEFINED_FUNCTION),
01737              errmsg("function %s does not exist",
01738                     func_signature_string(procname, 1, NIL, argList))));
01739 
01740     return InvalidOid;          /* keep compiler quiet */
01741 }
01742 
01743 static Oid
01744 findTypeSendFunction(List *procname, Oid typeOid)
01745 {
01746     Oid         argList[1];
01747     Oid         procOid;
01748 
01749     /*
01750      * Send functions can take a single argument of the type.
01751      */
01752     argList[0] = typeOid;
01753 
01754     procOid = LookupFuncName(procname, 1, argList, true);
01755     if (OidIsValid(procOid))
01756         return procOid;
01757 
01758     ereport(ERROR,
01759             (errcode(ERRCODE_UNDEFINED_FUNCTION),
01760              errmsg("function %s does not exist",
01761                     func_signature_string(procname, 1, NIL, argList))));
01762 
01763     return InvalidOid;          /* keep compiler quiet */
01764 }
01765 
01766 static Oid
01767 findTypeTypmodinFunction(List *procname)
01768 {
01769     Oid         argList[1];
01770     Oid         procOid;
01771 
01772     /*
01773      * typmodin functions always take one cstring[] argument and return int4.
01774      */
01775     argList[0] = CSTRINGARRAYOID;
01776 
01777     procOid = LookupFuncName(procname, 1, argList, true);
01778     if (!OidIsValid(procOid))
01779         ereport(ERROR,
01780                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
01781                  errmsg("function %s does not exist",
01782                         func_signature_string(procname, 1, NIL, argList))));
01783 
01784     if (get_func_rettype(procOid) != INT4OID)
01785         ereport(ERROR,
01786                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01787                  errmsg("typmod_in function %s must return type \"integer\"",
01788                         NameListToString(procname))));
01789 
01790     return procOid;
01791 }
01792 
01793 static Oid
01794 findTypeTypmodoutFunction(List *procname)
01795 {
01796     Oid         argList[1];
01797     Oid         procOid;
01798 
01799     /*
01800      * typmodout functions always take one int4 argument and return cstring.
01801      */
01802     argList[0] = INT4OID;
01803 
01804     procOid = LookupFuncName(procname, 1, argList, true);
01805     if (!OidIsValid(procOid))
01806         ereport(ERROR,
01807                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
01808                  errmsg("function %s does not exist",
01809                         func_signature_string(procname, 1, NIL, argList))));
01810 
01811     if (get_func_rettype(procOid) != CSTRINGOID)
01812         ereport(ERROR,
01813                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01814                  errmsg("typmod_out function %s must return type \"cstring\"",
01815                         NameListToString(procname))));
01816 
01817     return procOid;
01818 }
01819 
01820 static Oid
01821 findTypeAnalyzeFunction(List *procname, Oid typeOid)
01822 {
01823     Oid         argList[1];
01824     Oid         procOid;
01825 
01826     /*
01827      * Analyze functions always take one INTERNAL argument and return bool.
01828      */
01829     argList[0] = INTERNALOID;
01830 
01831     procOid = LookupFuncName(procname, 1, argList, true);
01832     if (!OidIsValid(procOid))
01833         ereport(ERROR,
01834                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
01835                  errmsg("function %s does not exist",
01836                         func_signature_string(procname, 1, NIL, argList))));
01837 
01838     if (get_func_rettype(procOid) != BOOLOID)
01839         ereport(ERROR,
01840                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01841               errmsg("type analyze function %s must return type \"boolean\"",
01842                      NameListToString(procname))));
01843 
01844     return procOid;
01845 }
01846 
01847 /*
01848  * Find suitable support functions and opclasses for a range type.
01849  */
01850 
01851 /*
01852  * Find named btree opclass for subtype, or default btree opclass if
01853  * opcname is NIL.
01854  */
01855 static Oid
01856 findRangeSubOpclass(List *opcname, Oid subtype)
01857 {
01858     Oid         opcid;
01859     Oid         opInputType;
01860 
01861     if (opcname != NIL)
01862     {
01863         opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
01864 
01865         /*
01866          * Verify that the operator class accepts this datatype. Note we will
01867          * accept binary compatibility.
01868          */
01869         opInputType = get_opclass_input_type(opcid);
01870         if (!IsBinaryCoercible(subtype, opInputType))
01871             ereport(ERROR,
01872                     (errcode(ERRCODE_DATATYPE_MISMATCH),
01873                  errmsg("operator class \"%s\" does not accept data type %s",
01874                         NameListToString(opcname),
01875                         format_type_be(subtype))));
01876     }
01877     else
01878     {
01879         opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
01880         if (!OidIsValid(opcid))
01881         {
01882             /* We spell the error message identically to GetIndexOpClass */
01883             ereport(ERROR,
01884                     (errcode(ERRCODE_UNDEFINED_OBJECT),
01885                      errmsg("data type %s has no default operator class for access method \"%s\"",
01886                             format_type_be(subtype), "btree"),
01887                      errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
01888         }
01889     }
01890 
01891     return opcid;
01892 }
01893 
01894 static Oid
01895 findRangeCanonicalFunction(List *procname, Oid typeOid)
01896 {
01897     Oid         argList[1];
01898     Oid         procOid;
01899     AclResult   aclresult;
01900 
01901     /*
01902      * Range canonical functions must take and return the range type, and must
01903      * be immutable.
01904      */
01905     argList[0] = typeOid;
01906 
01907     procOid = LookupFuncName(procname, 1, argList, true);
01908 
01909     if (!OidIsValid(procOid))
01910         ereport(ERROR,
01911                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
01912                  errmsg("function %s does not exist",
01913                         func_signature_string(procname, 1, NIL, argList))));
01914 
01915     if (get_func_rettype(procOid) != typeOid)
01916         ereport(ERROR,
01917                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01918                  errmsg("range canonical function %s must return range type",
01919                         func_signature_string(procname, 1, NIL, argList))));
01920 
01921     if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
01922         ereport(ERROR,
01923                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01924                  errmsg("range canonical function %s must be immutable",
01925                         func_signature_string(procname, 1, NIL, argList))));
01926 
01927     /* Also, range type's creator must have permission to call function */
01928     aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
01929     if (aclresult != ACLCHECK_OK)
01930         aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
01931 
01932     return procOid;
01933 }
01934 
01935 static Oid
01936 findRangeSubtypeDiffFunction(List *procname, Oid subtype)
01937 {
01938     Oid         argList[2];
01939     Oid         procOid;
01940     AclResult   aclresult;
01941 
01942     /*
01943      * Range subtype diff functions must take two arguments of the subtype,
01944      * must return float8, and must be immutable.
01945      */
01946     argList[0] = subtype;
01947     argList[1] = subtype;
01948 
01949     procOid = LookupFuncName(procname, 2, argList, true);
01950 
01951     if (!OidIsValid(procOid))
01952         ereport(ERROR,
01953                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
01954                  errmsg("function %s does not exist",
01955                         func_signature_string(procname, 2, NIL, argList))));
01956 
01957     if (get_func_rettype(procOid) != FLOAT8OID)
01958         ereport(ERROR,
01959                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01960                  errmsg("range subtype diff function %s must return type double precision",
01961                         func_signature_string(procname, 2, NIL, argList))));
01962 
01963     if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
01964         ereport(ERROR,
01965                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01966                  errmsg("range subtype diff function %s must be immutable",
01967                         func_signature_string(procname, 2, NIL, argList))));
01968 
01969     /* Also, range type's creator must have permission to call function */
01970     aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
01971     if (aclresult != ACLCHECK_OK)
01972         aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
01973 
01974     return procOid;
01975 }
01976 
01977 /*
01978  *  AssignTypeArrayOid
01979  *
01980  *  Pre-assign the type's array OID for use in pg_type.typarray
01981  */
01982 Oid
01983 AssignTypeArrayOid(void)
01984 {
01985     Oid         type_array_oid;
01986 
01987     /* Use binary-upgrade override for pg_type.typarray, if supplied. */
01988     if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid))
01989     {
01990         type_array_oid = binary_upgrade_next_array_pg_type_oid;
01991         binary_upgrade_next_array_pg_type_oid = InvalidOid;
01992     }
01993     else
01994     {
01995         Relation    pg_type = heap_open(TypeRelationId, AccessShareLock);
01996 
01997         type_array_oid = GetNewOid(pg_type);
01998         heap_close(pg_type, AccessShareLock);
01999     }
02000 
02001     return type_array_oid;
02002 }
02003 
02004 
02005 /*-------------------------------------------------------------------
02006  * DefineCompositeType
02007  *
02008  * Create a Composite Type relation.
02009  * `DefineRelation' does all the work, we just provide the correct
02010  * arguments!
02011  *
02012  * If the relation already exists, then 'DefineRelation' will abort
02013  * the xact...
02014  *
02015  * DefineCompositeType returns relid for use when creating
02016  * an implicit composite type during function creation
02017  *-------------------------------------------------------------------
02018  */
02019 Oid
02020 DefineCompositeType(RangeVar *typevar, List *coldeflist)
02021 {
02022     CreateStmt *createStmt = makeNode(CreateStmt);
02023     Oid         old_type_oid;
02024     Oid         typeNamespace;
02025     Oid         relid;
02026 
02027     /*
02028      * now set the parameters for keys/inheritance etc. All of these are
02029      * uninteresting for composite types...
02030      */
02031     createStmt->relation = typevar;
02032     createStmt->tableElts = coldeflist;
02033     createStmt->inhRelations = NIL;
02034     createStmt->constraints = NIL;
02035     createStmt->options = NIL;
02036     createStmt->oncommit = ONCOMMIT_NOOP;
02037     createStmt->tablespacename = NULL;
02038     createStmt->if_not_exists = false;
02039 
02040     /*
02041      * Check for collision with an existing type name. If there is one and
02042      * it's an autogenerated array, we can rename it out of the way.  This
02043      * check is here mainly to get a better error message about a "type"
02044      * instead of below about a "relation".
02045      */
02046     typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
02047                                                          NoLock, NULL);
02048     RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
02049     old_type_oid =
02050         GetSysCacheOid2(TYPENAMENSP,
02051                         CStringGetDatum(createStmt->relation->relname),
02052                         ObjectIdGetDatum(typeNamespace));
02053     if (OidIsValid(old_type_oid))
02054     {
02055         if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
02056             ereport(ERROR,
02057                     (errcode(ERRCODE_DUPLICATE_OBJECT),
02058                      errmsg("type \"%s\" already exists", createStmt->relation->relname)));
02059     }
02060 
02061     /*
02062      * Finally create the relation.  This also creates the type.
02063      */
02064     relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
02065     Assert(relid != InvalidOid);
02066     return relid;
02067 }
02068 
02069 /*
02070  * AlterDomainDefault
02071  *
02072  * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
02073  */
02074 Oid
02075 AlterDomainDefault(List *names, Node *defaultRaw)
02076 {
02077     TypeName   *typename;
02078     Oid         domainoid;
02079     HeapTuple   tup;
02080     ParseState *pstate;
02081     Relation    rel;
02082     char       *defaultValue;
02083     Node       *defaultExpr = NULL;     /* NULL if no default specified */
02084     Datum       new_record[Natts_pg_type];
02085     bool        new_record_nulls[Natts_pg_type];
02086     bool        new_record_repl[Natts_pg_type];
02087     HeapTuple   newtuple;
02088     Form_pg_type typTup;
02089 
02090     /* Make a TypeName so we can use standard type lookup machinery */
02091     typename = makeTypeNameFromNameList(names);
02092     domainoid = typenameTypeId(NULL, typename);
02093 
02094     /* Look up the domain in the type table */
02095     rel = heap_open(TypeRelationId, RowExclusiveLock);
02096 
02097     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
02098     if (!HeapTupleIsValid(tup))
02099         elog(ERROR, "cache lookup failed for type %u", domainoid);
02100     typTup = (Form_pg_type) GETSTRUCT(tup);
02101 
02102     /* Check it's a domain and check user has permission for ALTER DOMAIN */
02103     checkDomainOwner(tup);
02104 
02105     /* Setup new tuple */
02106     MemSet(new_record, (Datum) 0, sizeof(new_record));
02107     MemSet(new_record_nulls, false, sizeof(new_record_nulls));
02108     MemSet(new_record_repl, false, sizeof(new_record_repl));
02109 
02110     /* Store the new default into the tuple */
02111     if (defaultRaw)
02112     {
02113         /* Create a dummy ParseState for transformExpr */
02114         pstate = make_parsestate(NULL);
02115 
02116         /*
02117          * Cook the colDef->raw_expr into an expression. Note: Name is
02118          * strictly for error message
02119          */
02120         defaultExpr = cookDefault(pstate, defaultRaw,
02121                                   typTup->typbasetype,
02122                                   typTup->typtypmod,
02123                                   NameStr(typTup->typname));
02124 
02125         /*
02126          * If the expression is just a NULL constant, we treat the command
02127          * like ALTER ... DROP DEFAULT.  (But see note for same test in
02128          * DefineDomain.)
02129          */
02130         if (defaultExpr == NULL ||
02131             (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
02132         {
02133             /* Default is NULL, drop it */
02134             new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
02135             new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
02136             new_record_nulls[Anum_pg_type_typdefault - 1] = true;
02137             new_record_repl[Anum_pg_type_typdefault - 1] = true;
02138         }
02139         else
02140         {
02141             /*
02142              * Expression must be stored as a nodeToString result, but we also
02143              * require a valid textual representation (mainly to make life
02144              * easier for pg_dump).
02145              */
02146             defaultValue = deparse_expression(defaultExpr,
02147                                               NIL, false, false);
02148 
02149             /*
02150              * Form an updated tuple with the new default and write it back.
02151              */
02152             new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
02153 
02154             new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
02155             new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
02156             new_record_repl[Anum_pg_type_typdefault - 1] = true;
02157         }
02158     }
02159     else
02160     {
02161         /* ALTER ... DROP DEFAULT */
02162         new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
02163         new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
02164         new_record_nulls[Anum_pg_type_typdefault - 1] = true;
02165         new_record_repl[Anum_pg_type_typdefault - 1] = true;
02166     }
02167 
02168     newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
02169                                  new_record, new_record_nulls,
02170                                  new_record_repl);
02171 
02172     simple_heap_update(rel, &tup->t_self, newtuple);
02173 
02174     CatalogUpdateIndexes(rel, newtuple);
02175 
02176     /* Rebuild dependencies */
02177     GenerateTypeDependencies(typTup->typnamespace,
02178                              domainoid,
02179                              InvalidOid,        /* typrelid is n/a */
02180                              0, /* relation kind is n/a */
02181                              typTup->typowner,
02182                              typTup->typinput,
02183                              typTup->typoutput,
02184                              typTup->typreceive,
02185                              typTup->typsend,
02186                              typTup->typmodin,
02187                              typTup->typmodout,
02188                              typTup->typanalyze,
02189                              InvalidOid,
02190                              false,     /* a domain isn't an implicit array */
02191                              typTup->typbasetype,
02192                              typTup->typcollation,
02193                              defaultExpr,
02194                              true);     /* Rebuild is true */
02195 
02196     InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
02197 
02198     /* Clean up */
02199     heap_close(rel, NoLock);
02200     heap_freetuple(newtuple);
02201 
02202     return domainoid;
02203 }
02204 
02205 /*
02206  * AlterDomainNotNull
02207  *
02208  * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
02209  */
02210 Oid
02211 AlterDomainNotNull(List *names, bool notNull)
02212 {
02213     TypeName   *typename;
02214     Oid         domainoid;
02215     Relation    typrel;
02216     HeapTuple   tup;
02217     Form_pg_type typTup;
02218 
02219     /* Make a TypeName so we can use standard type lookup machinery */
02220     typename = makeTypeNameFromNameList(names);
02221     domainoid = typenameTypeId(NULL, typename);
02222 
02223     /* Look up the domain in the type table */
02224     typrel = heap_open(TypeRelationId, RowExclusiveLock);
02225 
02226     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
02227     if (!HeapTupleIsValid(tup))
02228         elog(ERROR, "cache lookup failed for type %u", domainoid);
02229     typTup = (Form_pg_type) GETSTRUCT(tup);
02230 
02231     /* Check it's a domain and check user has permission for ALTER DOMAIN */
02232     checkDomainOwner(tup);
02233 
02234     /* Is the domain already set to the desired constraint? */
02235     if (typTup->typnotnull == notNull)
02236     {
02237         heap_close(typrel, RowExclusiveLock);
02238         return InvalidOid;
02239     }
02240 
02241     /* Adding a NOT NULL constraint requires checking existing columns */
02242     if (notNull)
02243     {
02244         List       *rels;
02245         ListCell   *rt;
02246 
02247         /* Fetch relation list with attributes based on this domain */
02248         /* ShareLock is sufficient to prevent concurrent data changes */
02249 
02250         rels = get_rels_with_domain(domainoid, ShareLock);
02251 
02252         foreach(rt, rels)
02253         {
02254             RelToCheck *rtc = (RelToCheck *) lfirst(rt);
02255             Relation    testrel = rtc->rel;
02256             TupleDesc   tupdesc = RelationGetDescr(testrel);
02257             HeapScanDesc scan;
02258             HeapTuple   tuple;
02259 
02260             /* Scan all tuples in this relation */
02261             scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
02262             while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
02263             {
02264                 int         i;
02265 
02266                 /* Test attributes that are of the domain */
02267                 for (i = 0; i < rtc->natts; i++)
02268                 {
02269                     int         attnum = rtc->atts[i];
02270 
02271                     if (heap_attisnull(tuple, attnum))
02272                     {
02273                         /*
02274                          * In principle the auxiliary information for this
02275                          * error should be errdatatype(), but errtablecol()
02276                          * seems considerably more useful in practice.  Since
02277                          * this code only executes in an ALTER DOMAIN command,
02278                          * the client should already know which domain is in
02279                          * question.
02280                          */
02281                         ereport(ERROR,
02282                                 (errcode(ERRCODE_NOT_NULL_VIOLATION),
02283                                  errmsg("column \"%s\" of table \"%s\" contains null values",
02284                                 NameStr(tupdesc->attrs[attnum - 1]->attname),
02285                                         RelationGetRelationName(testrel)),
02286                                  errtablecol(testrel, attnum)));
02287                     }
02288                 }
02289             }
02290             heap_endscan(scan);
02291 
02292             /* Close each rel after processing, but keep lock */
02293             heap_close(testrel, NoLock);
02294         }
02295     }
02296 
02297     /*
02298      * Okay to update pg_type row.  We can scribble on typTup because it's a
02299      * copy.
02300      */
02301     typTup->typnotnull = notNull;
02302 
02303     simple_heap_update(typrel, &tup->t_self, tup);
02304 
02305     CatalogUpdateIndexes(typrel, tup);
02306 
02307     InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
02308 
02309     /* Clean up */
02310     heap_freetuple(tup);
02311     heap_close(typrel, RowExclusiveLock);
02312 
02313     return domainoid;
02314 }
02315 
02316 /*
02317  * AlterDomainDropConstraint
02318  *
02319  * Implements the ALTER DOMAIN DROP CONSTRAINT statement
02320  */
02321 Oid
02322 AlterDomainDropConstraint(List *names, const char *constrName,
02323                           DropBehavior behavior, bool missing_ok)
02324 {
02325     TypeName   *typename;
02326     Oid         domainoid;
02327     HeapTuple   tup;
02328     Relation    rel;
02329     Relation    conrel;
02330     SysScanDesc conscan;
02331     ScanKeyData key[1];
02332     HeapTuple   contup;
02333     bool        found = false;
02334 
02335     /* Make a TypeName so we can use standard type lookup machinery */
02336     typename = makeTypeNameFromNameList(names);
02337     domainoid = typenameTypeId(NULL, typename);
02338 
02339     /* Look up the domain in the type table */
02340     rel = heap_open(TypeRelationId, RowExclusiveLock);
02341 
02342     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
02343     if (!HeapTupleIsValid(tup))
02344         elog(ERROR, "cache lookup failed for type %u", domainoid);
02345 
02346     /* Check it's a domain and check user has permission for ALTER DOMAIN */
02347     checkDomainOwner(tup);
02348 
02349     /* Grab an appropriate lock on the pg_constraint relation */
02350     conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
02351 
02352     /* Use the index to scan only constraints of the target relation */
02353     ScanKeyInit(&key[0],
02354                 Anum_pg_constraint_contypid,
02355                 BTEqualStrategyNumber, F_OIDEQ,
02356                 ObjectIdGetDatum(HeapTupleGetOid(tup)));
02357 
02358     conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
02359                                  SnapshotNow, 1, key);
02360 
02361     /*
02362      * Scan over the result set, removing any matching entries.
02363      */
02364     while ((contup = systable_getnext(conscan)) != NULL)
02365     {
02366         Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
02367 
02368         if (strcmp(NameStr(con->conname), constrName) == 0)
02369         {
02370             ObjectAddress conobj;
02371 
02372             conobj.classId = ConstraintRelationId;
02373             conobj.objectId = HeapTupleGetOid(contup);
02374             conobj.objectSubId = 0;
02375 
02376             performDeletion(&conobj, behavior, 0);
02377             found = true;
02378         }
02379     }
02380     /* Clean up after the scan */
02381     systable_endscan(conscan);
02382     heap_close(conrel, RowExclusiveLock);
02383 
02384     heap_close(rel, NoLock);
02385 
02386     if (!found)
02387     {
02388         if (!missing_ok)
02389             ereport(ERROR,
02390                     (errcode(ERRCODE_UNDEFINED_OBJECT),
02391                   errmsg("constraint \"%s\" of domain \"%s\" does not exist",
02392                          constrName, TypeNameToString(typename))));
02393         else
02394             ereport(NOTICE,
02395                     (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
02396                             constrName, TypeNameToString(typename))));
02397     }
02398 
02399     return domainoid;
02400 }
02401 
02402 /*
02403  * AlterDomainAddConstraint
02404  *
02405  * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
02406  */
02407 Oid
02408 AlterDomainAddConstraint(List *names, Node *newConstraint)
02409 {
02410     TypeName   *typename;
02411     Oid         domainoid;
02412     Relation    typrel;
02413     HeapTuple   tup;
02414     Form_pg_type typTup;
02415     Constraint *constr;
02416     char       *ccbin;
02417 
02418     /* Make a TypeName so we can use standard type lookup machinery */
02419     typename = makeTypeNameFromNameList(names);
02420     domainoid = typenameTypeId(NULL, typename);
02421 
02422     /* Look up the domain in the type table */
02423     typrel = heap_open(TypeRelationId, RowExclusiveLock);
02424 
02425     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
02426     if (!HeapTupleIsValid(tup))
02427         elog(ERROR, "cache lookup failed for type %u", domainoid);
02428     typTup = (Form_pg_type) GETSTRUCT(tup);
02429 
02430     /* Check it's a domain and check user has permission for ALTER DOMAIN */
02431     checkDomainOwner(tup);
02432 
02433     if (!IsA(newConstraint, Constraint))
02434         elog(ERROR, "unrecognized node type: %d",
02435              (int) nodeTag(newConstraint));
02436 
02437     constr = (Constraint *) newConstraint;
02438 
02439     switch (constr->contype)
02440     {
02441         case CONSTR_CHECK:
02442             /* processed below */
02443             break;
02444 
02445         case CONSTR_UNIQUE:
02446             ereport(ERROR,
02447                     (errcode(ERRCODE_SYNTAX_ERROR),
02448                      errmsg("unique constraints not possible for domains")));
02449             break;
02450 
02451         case CONSTR_PRIMARY:
02452             ereport(ERROR,
02453                     (errcode(ERRCODE_SYNTAX_ERROR),
02454                 errmsg("primary key constraints not possible for domains")));
02455             break;
02456 
02457         case CONSTR_EXCLUSION:
02458             ereport(ERROR,
02459                     (errcode(ERRCODE_SYNTAX_ERROR),
02460                   errmsg("exclusion constraints not possible for domains")));
02461             break;
02462 
02463         case CONSTR_FOREIGN:
02464             ereport(ERROR,
02465                     (errcode(ERRCODE_SYNTAX_ERROR),
02466                 errmsg("foreign key constraints not possible for domains")));
02467             break;
02468 
02469         case CONSTR_ATTR_DEFERRABLE:
02470         case CONSTR_ATTR_NOT_DEFERRABLE:
02471         case CONSTR_ATTR_DEFERRED:
02472         case CONSTR_ATTR_IMMEDIATE:
02473             ereport(ERROR,
02474                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02475                      errmsg("specifying constraint deferrability not supported for domains")));
02476             break;
02477 
02478         default:
02479             elog(ERROR, "unrecognized constraint subtype: %d",
02480                  (int) constr->contype);
02481             break;
02482     }
02483 
02484     /*
02485      * Since all other constraint types throw errors, this must be a check
02486      * constraint.  First, process the constraint expression and add an entry
02487      * to pg_constraint.
02488      */
02489 
02490     ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
02491                                 typTup->typbasetype, typTup->typtypmod,
02492                                 constr, NameStr(typTup->typname));
02493 
02494     /*
02495      * If requested to validate the constraint, test all values stored in the
02496      * attributes based on the domain the constraint is being added to.
02497      */
02498     if (!constr->skip_validation)
02499         validateDomainConstraint(domainoid, ccbin);
02500 
02501     /* Clean up */
02502     heap_close(typrel, RowExclusiveLock);
02503 
02504     return domainoid;
02505 }
02506 
02507 /*
02508  * AlterDomainValidateConstraint
02509  *
02510  * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
02511  */
02512 Oid
02513 AlterDomainValidateConstraint(List *names, char *constrName)
02514 {
02515     TypeName   *typename;
02516     Oid         domainoid;
02517     Relation    typrel;
02518     Relation    conrel;
02519     HeapTuple   tup;
02520     Form_pg_constraint con = NULL;
02521     Form_pg_constraint copy_con;
02522     char       *conbin;
02523     SysScanDesc scan;
02524     Datum       val;
02525     bool        found = false;
02526     bool        isnull;
02527     HeapTuple   tuple;
02528     HeapTuple   copyTuple;
02529     ScanKeyData key;
02530 
02531     /* Make a TypeName so we can use standard type lookup machinery */
02532     typename = makeTypeNameFromNameList(names);
02533     domainoid = typenameTypeId(NULL, typename);
02534 
02535     /* Look up the domain in the type table */
02536     typrel = heap_open(TypeRelationId, AccessShareLock);
02537 
02538     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
02539     if (!HeapTupleIsValid(tup))
02540         elog(ERROR, "cache lookup failed for type %u", domainoid);
02541 
02542     /* Check it's a domain and check user has permission for ALTER DOMAIN */
02543     checkDomainOwner(tup);
02544 
02545     /*
02546      * Find and check the target constraint
02547      */
02548     conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
02549     ScanKeyInit(&key,
02550                 Anum_pg_constraint_contypid,
02551                 BTEqualStrategyNumber, F_OIDEQ,
02552                 ObjectIdGetDatum(domainoid));
02553     scan = systable_beginscan(conrel, ConstraintTypidIndexId,
02554                               true, SnapshotNow, 1, &key);
02555 
02556     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
02557     {
02558         con = (Form_pg_constraint) GETSTRUCT(tuple);
02559         if (strcmp(NameStr(con->conname), constrName) == 0)
02560         {
02561             found = true;
02562             break;
02563         }
02564     }
02565 
02566     if (!found)
02567         ereport(ERROR,
02568                 (errcode(ERRCODE_UNDEFINED_OBJECT),
02569                  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
02570                         constrName, TypeNameToString(typename))));
02571 
02572     if (con->contype != CONSTRAINT_CHECK)
02573         ereport(ERROR,
02574                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
02575         errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
02576                constrName, TypeNameToString(typename))));
02577 
02578     val = SysCacheGetAttr(CONSTROID, tuple,
02579                           Anum_pg_constraint_conbin,
02580                           &isnull);
02581     if (isnull)
02582         elog(ERROR, "null conbin for constraint %u",
02583              HeapTupleGetOid(tuple));
02584     conbin = TextDatumGetCString(val);
02585 
02586     validateDomainConstraint(domainoid, conbin);
02587 
02588     /*
02589      * Now update the catalog, while we have the door open.
02590      */
02591     copyTuple = heap_copytuple(tuple);
02592     copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
02593     copy_con->convalidated = true;
02594     simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
02595     CatalogUpdateIndexes(conrel, copyTuple);
02596 
02597     InvokeObjectPostAlterHook(ConstraintRelationId,
02598                               HeapTupleGetOid(copyTuple), 0);
02599 
02600     heap_freetuple(copyTuple);
02601 
02602     systable_endscan(scan);
02603 
02604     heap_close(typrel, AccessShareLock);
02605     heap_close(conrel, RowExclusiveLock);
02606 
02607     ReleaseSysCache(tup);
02608 
02609     return domainoid;
02610 }
02611 
02612 static void
02613 validateDomainConstraint(Oid domainoid, char *ccbin)
02614 {
02615     Expr       *expr = (Expr *) stringToNode(ccbin);
02616     List       *rels;
02617     ListCell   *rt;
02618     EState     *estate;
02619     ExprContext *econtext;
02620     ExprState  *exprstate;
02621 
02622     /* Need an EState to run ExecEvalExpr */
02623     estate = CreateExecutorState();
02624     econtext = GetPerTupleExprContext(estate);
02625 
02626     /* build execution state for expr */
02627     exprstate = ExecPrepareExpr(expr, estate);
02628 
02629     /* Fetch relation list with attributes based on this domain */
02630     /* ShareLock is sufficient to prevent concurrent data changes */
02631 
02632     rels = get_rels_with_domain(domainoid, ShareLock);
02633 
02634     foreach(rt, rels)
02635     {
02636         RelToCheck *rtc = (RelToCheck *) lfirst(rt);
02637         Relation    testrel = rtc->rel;
02638         TupleDesc   tupdesc = RelationGetDescr(testrel);
02639         HeapScanDesc scan;
02640         HeapTuple   tuple;
02641 
02642         /* Scan all tuples in this relation */
02643         scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
02644         while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
02645         {
02646             int         i;
02647 
02648             /* Test attributes that are of the domain */
02649             for (i = 0; i < rtc->natts; i++)
02650             {
02651                 int         attnum = rtc->atts[i];
02652                 Datum       d;
02653                 bool        isNull;
02654                 Datum       conResult;
02655 
02656                 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
02657 
02658                 econtext->domainValue_datum = d;
02659                 econtext->domainValue_isNull = isNull;
02660 
02661                 conResult = ExecEvalExprSwitchContext(exprstate,
02662                                                       econtext,
02663                                                       &isNull, NULL);
02664 
02665                 if (!isNull && !DatumGetBool(conResult))
02666                 {
02667                     /*
02668                      * In principle the auxiliary information for this error
02669                      * should be errdomainconstraint(), but errtablecol()
02670                      * seems considerably more useful in practice.  Since this
02671                      * code only executes in an ALTER DOMAIN command, the
02672                      * client should already know which domain is in question,
02673                      * and which constraint too.
02674                      */
02675                     ereport(ERROR,
02676                             (errcode(ERRCODE_CHECK_VIOLATION),
02677                              errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
02678                                 NameStr(tupdesc->attrs[attnum - 1]->attname),
02679                                     RelationGetRelationName(testrel)),
02680                              errtablecol(testrel, attnum)));
02681                 }
02682             }
02683 
02684             ResetExprContext(econtext);
02685         }
02686         heap_endscan(scan);
02687 
02688         /* Hold relation lock till commit (XXX bad for concurrency) */
02689         heap_close(testrel, NoLock);
02690     }
02691 
02692     FreeExecutorState(estate);
02693 }
02694 
02695 /*
02696  * get_rels_with_domain
02697  *
02698  * Fetch all relations / attributes which are using the domain
02699  *
02700  * The result is a list of RelToCheck structs, one for each distinct
02701  * relation, each containing one or more attribute numbers that are of
02702  * the domain type.  We have opened each rel and acquired the specified lock
02703  * type on it.
02704  *
02705  * We support nested domains by including attributes that are of derived
02706  * domain types.  Current callers do not need to distinguish between attributes
02707  * that are of exactly the given domain and those that are of derived domains.
02708  *
02709  * XXX this is completely broken because there is no way to lock the domain
02710  * to prevent columns from being added or dropped while our command runs.
02711  * We can partially protect against column drops by locking relations as we
02712  * come across them, but there is still a race condition (the window between
02713  * seeing a pg_depend entry and acquiring lock on the relation it references).
02714  * Also, holding locks on all these relations simultaneously creates a non-
02715  * trivial risk of deadlock.  We can minimize but not eliminate the deadlock
02716  * risk by using the weakest suitable lock (ShareLock for most callers).
02717  *
02718  * XXX the API for this is not sufficient to support checking domain values
02719  * that are inside composite types or arrays.  Currently we just error out
02720  * if a composite type containing the target domain is stored anywhere.
02721  * There are not currently arrays of domains; if there were, we could take
02722  * the same approach, but it'd be nicer to fix it properly.
02723  *
02724  * Generally used for retrieving a list of tests when adding
02725  * new constraints to a domain.
02726  */
02727 static List *
02728 get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
02729 {
02730     List       *result = NIL;
02731     Relation    depRel;
02732     ScanKeyData key[2];
02733     SysScanDesc depScan;
02734     HeapTuple   depTup;
02735 
02736     Assert(lockmode != NoLock);
02737 
02738     /*
02739      * We scan pg_depend to find those things that depend on the domain. (We
02740      * assume we can ignore refobjsubid for a domain.)
02741      */
02742     depRel = heap_open(DependRelationId, AccessShareLock);
02743 
02744     ScanKeyInit(&key[0],
02745                 Anum_pg_depend_refclassid,
02746                 BTEqualStrategyNumber, F_OIDEQ,
02747                 ObjectIdGetDatum(TypeRelationId));
02748     ScanKeyInit(&key[1],
02749                 Anum_pg_depend_refobjid,
02750                 BTEqualStrategyNumber, F_OIDEQ,
02751                 ObjectIdGetDatum(domainOid));
02752 
02753     depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
02754                                  SnapshotNow, 2, key);
02755 
02756     while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
02757     {
02758         Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
02759         RelToCheck *rtc = NULL;
02760         ListCell   *rellist;
02761         Form_pg_attribute pg_att;
02762         int         ptr;
02763 
02764         /* Check for directly dependent types --- must be domains */
02765         if (pg_depend->classid == TypeRelationId)
02766         {
02767             Assert(get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN);
02768 
02769             /*
02770              * Recursively add dependent columns to the output list.  This is
02771              * a bit inefficient since we may fail to combine RelToCheck
02772              * entries when attributes of the same rel have different derived
02773              * domain types, but it's probably not worth improving.
02774              */
02775             result = list_concat(result,
02776                                  get_rels_with_domain(pg_depend->objid,
02777                                                       lockmode));
02778             continue;
02779         }
02780 
02781         /* Else, ignore dependees that aren't user columns of relations */
02782         /* (we assume system columns are never of domain types) */
02783         if (pg_depend->classid != RelationRelationId ||
02784             pg_depend->objsubid <= 0)
02785             continue;
02786 
02787         /* See if we already have an entry for this relation */
02788         foreach(rellist, result)
02789         {
02790             RelToCheck *rt = (RelToCheck *) lfirst(rellist);
02791 
02792             if (RelationGetRelid(rt->rel) == pg_depend->objid)
02793             {
02794                 rtc = rt;
02795                 break;
02796             }
02797         }
02798 
02799         if (rtc == NULL)
02800         {
02801             /* First attribute found for this relation */
02802             Relation    rel;
02803 
02804             /* Acquire requested lock on relation */
02805             rel = relation_open(pg_depend->objid, lockmode);
02806 
02807             /*
02808              * Check to see if rowtype is stored anyplace as a composite-type
02809              * column; if so we have to fail, for now anyway.
02810              */
02811             if (OidIsValid(rel->rd_rel->reltype))
02812                 find_composite_type_dependencies(rel->rd_rel->reltype,
02813                                                  NULL,
02814                                                  format_type_be(domainOid));
02815 
02816             /* Otherwise we can ignore views, composite types, etc */
02817             if (rel->rd_rel->relkind != RELKIND_RELATION &&
02818                 rel->rd_rel->relkind != RELKIND_MATVIEW)
02819             {
02820                 relation_close(rel, lockmode);
02821                 continue;
02822             }
02823 
02824             /* Build the RelToCheck entry with enough space for all atts */
02825             rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
02826             rtc->rel = rel;
02827             rtc->natts = 0;
02828             rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
02829             result = lcons(rtc, result);
02830         }
02831 
02832         /*
02833          * Confirm column has not been dropped, and is of the expected type.
02834          * This defends against an ALTER DROP COLUMN occurring just before we
02835          * acquired lock ... but if the whole table were dropped, we'd still
02836          * have a problem.
02837          */
02838         if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
02839             continue;
02840         pg_att = rtc->rel->rd_att->attrs[pg_depend->objsubid - 1];
02841         if (pg_att->attisdropped || pg_att->atttypid != domainOid)
02842             continue;
02843 
02844         /*
02845          * Okay, add column to result.  We store the columns in column-number
02846          * order; this is just a hack to improve predictability of regression
02847          * test output ...
02848          */
02849         Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
02850 
02851         ptr = rtc->natts++;
02852         while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
02853         {
02854             rtc->atts[ptr] = rtc->atts[ptr - 1];
02855             ptr--;
02856         }
02857         rtc->atts[ptr] = pg_depend->objsubid;
02858     }
02859 
02860     systable_endscan(depScan);
02861 
02862     relation_close(depRel, AccessShareLock);
02863 
02864     return result;
02865 }
02866 
02867 /*
02868  * checkDomainOwner
02869  *
02870  * Check that the type is actually a domain and that the current user
02871  * has permission to do ALTER DOMAIN on it.  Throw an error if not.
02872  */
02873 void
02874 checkDomainOwner(HeapTuple tup)
02875 {
02876     Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
02877 
02878     /* Check that this is actually a domain */
02879     if (typTup->typtype != TYPTYPE_DOMAIN)
02880         ereport(ERROR,
02881                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
02882                  errmsg("%s is not a domain",
02883                         format_type_be(HeapTupleGetOid(tup)))));
02884 
02885     /* Permission check: must own type */
02886     if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
02887         aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
02888 }
02889 
02890 /*
02891  * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
02892  */
02893 static char *
02894 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
02895                     int typMod, Constraint *constr,
02896                     char *domainName)
02897 {
02898     Node       *expr;
02899     char       *ccsrc;
02900     char       *ccbin;
02901     ParseState *pstate;
02902     CoerceToDomainValue *domVal;
02903 
02904     /*
02905      * Assign or validate constraint name
02906      */
02907     if (constr->conname)
02908     {
02909         if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
02910                                  domainOid,
02911                                  domainNamespace,
02912                                  constr->conname))
02913             ereport(ERROR,
02914                     (errcode(ERRCODE_DUPLICATE_OBJECT),
02915                  errmsg("constraint \"%s\" for domain \"%s\" already exists",
02916                         constr->conname, domainName)));
02917     }
02918     else
02919         constr->conname = ChooseConstraintName(domainName,
02920                                                NULL,
02921                                                "check",
02922                                                domainNamespace,
02923                                                NIL);
02924 
02925     /*
02926      * Convert the A_EXPR in raw_expr into an EXPR
02927      */
02928     pstate = make_parsestate(NULL);
02929 
02930     /*
02931      * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
02932      * the expression.  Note that it will appear to have the type of the base
02933      * type, not the domain.  This seems correct since within the check
02934      * expression, we should not assume the input value can be considered a
02935      * member of the domain.
02936      */
02937     domVal = makeNode(CoerceToDomainValue);
02938     domVal->typeId = baseTypeOid;
02939     domVal->typeMod = typMod;
02940     domVal->collation = get_typcollation(baseTypeOid);
02941     domVal->location = -1;      /* will be set when/if used */
02942 
02943     pstate->p_value_substitute = (Node *) domVal;
02944 
02945     expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
02946 
02947     /*
02948      * Make sure it yields a boolean result.
02949      */
02950     expr = coerce_to_boolean(pstate, expr, "CHECK");
02951 
02952     /*
02953      * Fix up collation information.
02954      */
02955     assign_expr_collations(pstate, expr);
02956 
02957     /*
02958      * Domains don't allow variables (this is probably dead code now that
02959      * add_missing_from is history, but let's be sure).
02960      */
02961     if (list_length(pstate->p_rtable) != 0 ||
02962         contain_var_clause(expr))
02963         ereport(ERROR,
02964                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
02965           errmsg("cannot use table references in domain check constraint")));
02966 
02967     /*
02968      * Convert to string form for storage.
02969      */
02970     ccbin = nodeToString(expr);
02971 
02972     /*
02973      * Deparse it to produce text for consrc.
02974      */
02975     ccsrc = deparse_expression(expr,
02976                                NIL, false, false);
02977 
02978     /*
02979      * Store the constraint in pg_constraint
02980      */
02981     CreateConstraintEntry(constr->conname,      /* Constraint Name */
02982                           domainNamespace,      /* namespace */
02983                           CONSTRAINT_CHECK,     /* Constraint Type */
02984                           false,    /* Is Deferrable */
02985                           false,    /* Is Deferred */
02986                           !constr->skip_validation,     /* Is Validated */
02987                           InvalidOid,   /* not a relation constraint */
02988                           NULL,
02989                           0,
02990                           domainOid,    /* domain constraint */
02991                           InvalidOid,   /* no associated index */
02992                           InvalidOid,   /* Foreign key fields */
02993                           NULL,
02994                           NULL,
02995                           NULL,
02996                           NULL,
02997                           0,
02998                           ' ',
02999                           ' ',
03000                           ' ',
03001                           NULL, /* not an exclusion constraint */
03002                           expr, /* Tree form of check constraint */
03003                           ccbin,    /* Binary form of check constraint */
03004                           ccsrc,    /* Source form of check constraint */
03005                           true, /* is local */
03006                           0,    /* inhcount */
03007                           false,    /* connoinherit */
03008                           false);   /* is_internal */
03009 
03010     /*
03011      * Return the compiled constraint expression so the calling routine can
03012      * perform any additional required tests.
03013      */
03014     return ccbin;
03015 }
03016 
03017 /*
03018  * GetDomainConstraints - get a list of the current constraints of domain
03019  *
03020  * Returns a possibly-empty list of DomainConstraintState nodes.
03021  *
03022  * This is called by the executor during plan startup for a CoerceToDomain
03023  * expression node.  The given constraints will be checked for each value
03024  * passed through the node.
03025  *
03026  * We allow this to be called for non-domain types, in which case the result
03027  * is always NIL.
03028  */
03029 List *
03030 GetDomainConstraints(Oid typeOid)
03031 {
03032     List       *result = NIL;
03033     bool        notNull = false;
03034     Relation    conRel;
03035 
03036     conRel = heap_open(ConstraintRelationId, AccessShareLock);
03037 
03038     for (;;)
03039     {
03040         HeapTuple   tup;
03041         HeapTuple   conTup;
03042         Form_pg_type typTup;
03043         ScanKeyData key[1];
03044         SysScanDesc scan;
03045 
03046         tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
03047         if (!HeapTupleIsValid(tup))
03048             elog(ERROR, "cache lookup failed for type %u", typeOid);
03049         typTup = (Form_pg_type) GETSTRUCT(tup);
03050 
03051         if (typTup->typtype != TYPTYPE_DOMAIN)
03052         {
03053             /* Not a domain, so done */
03054             ReleaseSysCache(tup);
03055             break;
03056         }
03057 
03058         /* Test for NOT NULL Constraint */
03059         if (typTup->typnotnull)
03060             notNull = true;
03061 
03062         /* Look for CHECK Constraints on this domain */
03063         ScanKeyInit(&key[0],
03064                     Anum_pg_constraint_contypid,
03065                     BTEqualStrategyNumber, F_OIDEQ,
03066                     ObjectIdGetDatum(typeOid));
03067 
03068         scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
03069                                   SnapshotNow, 1, key);
03070 
03071         while (HeapTupleIsValid(conTup = systable_getnext(scan)))
03072         {
03073             Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
03074             Datum       val;
03075             bool        isNull;
03076             Expr       *check_expr;
03077             DomainConstraintState *r;
03078 
03079             /* Ignore non-CHECK constraints (presently, shouldn't be any) */
03080             if (c->contype != CONSTRAINT_CHECK)
03081                 continue;
03082 
03083             /*
03084              * Not expecting conbin to be NULL, but we'll test for it anyway
03085              */
03086             val = fastgetattr(conTup, Anum_pg_constraint_conbin,
03087                               conRel->rd_att, &isNull);
03088             if (isNull)
03089                 elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
03090                      NameStr(typTup->typname), NameStr(c->conname));
03091 
03092             check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
03093 
03094             /* ExecInitExpr assumes we've planned the expression */
03095             check_expr = expression_planner(check_expr);
03096 
03097             r = makeNode(DomainConstraintState);
03098             r->constrainttype = DOM_CONSTRAINT_CHECK;
03099             r->name = pstrdup(NameStr(c->conname));
03100             r->check_expr = ExecInitExpr(check_expr, NULL);
03101 
03102             /*
03103              * use lcons() here because constraints of lower domains should be
03104              * applied earlier.
03105              */
03106             result = lcons(r, result);
03107         }
03108 
03109         systable_endscan(scan);
03110 
03111         /* loop to next domain in stack */
03112         typeOid = typTup->typbasetype;
03113         ReleaseSysCache(tup);
03114     }
03115 
03116     heap_close(conRel, AccessShareLock);
03117 
03118     /*
03119      * Only need to add one NOT NULL check regardless of how many domains in
03120      * the stack request it.
03121      */
03122     if (notNull)
03123     {
03124         DomainConstraintState *r = makeNode(DomainConstraintState);
03125 
03126         r->constrainttype = DOM_CONSTRAINT_NOTNULL;
03127         r->name = pstrdup("NOT NULL");
03128         r->check_expr = NULL;
03129 
03130         /* lcons to apply the nullness check FIRST */
03131         result = lcons(r, result);
03132     }
03133 
03134     return result;
03135 }
03136 
03137 
03138 /*
03139  * Execute ALTER TYPE RENAME
03140  */
03141 Oid
03142 RenameType(RenameStmt *stmt)
03143 {
03144     List       *names = stmt->object;
03145     const char *newTypeName = stmt->newname;
03146     TypeName   *typename;
03147     Oid         typeOid;
03148     Relation    rel;
03149     HeapTuple   tup;
03150     Form_pg_type typTup;
03151 
03152     /* Make a TypeName so we can use standard type lookup machinery */
03153     typename = makeTypeNameFromNameList(names);
03154     typeOid = typenameTypeId(NULL, typename);
03155 
03156     /* Look up the type in the type table */
03157     rel = heap_open(TypeRelationId, RowExclusiveLock);
03158 
03159     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
03160     if (!HeapTupleIsValid(tup))
03161         elog(ERROR, "cache lookup failed for type %u", typeOid);
03162     typTup = (Form_pg_type) GETSTRUCT(tup);
03163 
03164     /* check permissions on type */
03165     if (!pg_type_ownercheck(typeOid, GetUserId()))
03166         aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
03167 
03168     /* ALTER DOMAIN used on a non-domain? */
03169     if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
03170         ereport(ERROR,
03171                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
03172                  errmsg("\"%s\" is not a domain",
03173                         format_type_be(typeOid))));
03174 
03175     /*
03176      * If it's a composite type, we need to check that it really is a
03177      * free-standing composite type, and not a table's rowtype. We want people
03178      * to use ALTER TABLE not ALTER TYPE for that case.
03179      */
03180     if (typTup->typtype == TYPTYPE_COMPOSITE &&
03181         get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
03182         ereport(ERROR,
03183                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
03184                  errmsg("%s is a table's row type",
03185                         format_type_be(typeOid)),
03186                  errhint("Use ALTER TABLE instead.")));
03187 
03188     /* don't allow direct alteration of array types, either */
03189     if (OidIsValid(typTup->typelem) &&
03190         get_array_type(typTup->typelem) == typeOid)
03191         ereport(ERROR,
03192                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
03193                  errmsg("cannot alter array type %s",
03194                         format_type_be(typeOid)),
03195                  errhint("You can alter type %s, which will alter the array type as well.",
03196                          format_type_be(typTup->typelem))));
03197 
03198     /*
03199      * If type is composite we need to rename associated pg_class entry too.
03200      * RenameRelationInternal will call RenameTypeInternal automatically.
03201      */
03202     if (typTup->typtype == TYPTYPE_COMPOSITE)
03203         RenameRelationInternal(typTup->typrelid, newTypeName, false);
03204     else
03205         RenameTypeInternal(typeOid, newTypeName,
03206                            typTup->typnamespace);
03207 
03208     /* Clean up */
03209     heap_close(rel, RowExclusiveLock);
03210 
03211     return typeOid;
03212 }
03213 
03214 /*
03215  * Change the owner of a type.
03216  */
03217 Oid
03218 AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
03219 {
03220     TypeName   *typename;
03221     Oid         typeOid;
03222     Relation    rel;
03223     HeapTuple   tup;
03224     HeapTuple   newtup;
03225     Form_pg_type typTup;
03226     AclResult   aclresult;
03227 
03228     rel = heap_open(TypeRelationId, RowExclusiveLock);
03229 
03230     /* Make a TypeName so we can use standard type lookup machinery */
03231     typename = makeTypeNameFromNameList(names);
03232 
03233     /* Use LookupTypeName here so that shell types can be processed */
03234     tup = LookupTypeName(NULL, typename, NULL);
03235     if (tup == NULL)
03236         ereport(ERROR,
03237                 (errcode(ERRCODE_UNDEFINED_OBJECT),
03238                  errmsg("type \"%s\" does not exist",
03239                         TypeNameToString(typename))));
03240     typeOid = typeTypeId(tup);
03241 
03242     /* Copy the syscache entry so we can scribble on it below */
03243     newtup = heap_copytuple(tup);
03244     ReleaseSysCache(tup);
03245     tup = newtup;
03246     typTup = (Form_pg_type) GETSTRUCT(tup);
03247 
03248     /* Don't allow ALTER DOMAIN on a type */
03249     if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
03250         ereport(ERROR,
03251                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
03252                  errmsg("%s is not a domain",
03253                         format_type_be(typeOid))));
03254 
03255     /*
03256      * If it's a composite type, we need to check that it really is a
03257      * free-standing composite type, and not a table's rowtype. We want people
03258      * to use ALTER TABLE not ALTER TYPE for that case.
03259      */
03260     if (typTup->typtype == TYPTYPE_COMPOSITE &&
03261         get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
03262         ereport(ERROR,
03263                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
03264                  errmsg("%s is a table's row type",
03265                         format_type_be(typeOid)),
03266                  errhint("Use ALTER TABLE instead.")));
03267 
03268     /* don't allow direct alteration of array types, either */
03269     if (OidIsValid(typTup->typelem) &&
03270         get_array_type(typTup->typelem) == typeOid)
03271         ereport(ERROR,
03272                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
03273                  errmsg("cannot alter array type %s",
03274                         format_type_be(typeOid)),
03275                  errhint("You can alter type %s, which will alter the array type as well.",
03276                          format_type_be(typTup->typelem))));
03277 
03278     /*
03279      * If the new owner is the same as the existing owner, consider the
03280      * command to have succeeded.  This is for dump restoration purposes.
03281      */
03282     if (typTup->typowner != newOwnerId)
03283     {
03284         /* Superusers can always do it */
03285         if (!superuser())
03286         {
03287             /* Otherwise, must be owner of the existing object */
03288             if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
03289                 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
03290 
03291             /* Must be able to become new owner */
03292             check_is_member_of_role(GetUserId(), newOwnerId);
03293 
03294             /* New owner must have CREATE privilege on namespace */
03295             aclresult = pg_namespace_aclcheck(typTup->typnamespace,
03296                                               newOwnerId,
03297                                               ACL_CREATE);
03298             if (aclresult != ACLCHECK_OK)
03299                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
03300                                get_namespace_name(typTup->typnamespace));
03301         }
03302 
03303         /*
03304          * If it's a composite type, invoke ATExecChangeOwner so that we fix
03305          * up the pg_class entry properly.  That will call back to
03306          * AlterTypeOwnerInternal to take care of the pg_type entry(s).
03307          */
03308         if (typTup->typtype == TYPTYPE_COMPOSITE)
03309             ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
03310         else
03311         {
03312             /*
03313              * We can just apply the modification directly.
03314              *
03315              * okay to scribble on typTup because it's a copy
03316              */
03317             typTup->typowner = newOwnerId;
03318 
03319             simple_heap_update(rel, &tup->t_self, tup);
03320 
03321             CatalogUpdateIndexes(rel, tup);
03322 
03323             /* Update owner dependency reference */
03324             changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
03325 
03326             InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
03327 
03328             /* If it has an array type, update that too */
03329             if (OidIsValid(typTup->typarray))
03330                 AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
03331         }
03332     }
03333 
03334     /* Clean up */
03335     heap_close(rel, RowExclusiveLock);
03336 
03337     return typeOid;
03338 }
03339 
03340 /*
03341  * AlterTypeOwnerInternal - change type owner unconditionally
03342  *
03343  * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
03344  * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
03345  * It assumes the caller has done all needed checks.  The function will
03346  * automatically recurse to an array type if the type has one.
03347  *
03348  * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
03349  * entry (ie, it's not a table rowtype nor an array type).
03350  * is_primary_ops should be TRUE if this function is invoked with user's
03351  * direct operation (e.g, shdepReassignOwned). Elsewhere, 
03352  */
03353 void
03354 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
03355                        bool hasDependEntry)
03356 {
03357     Relation    rel;
03358     HeapTuple   tup;
03359     Form_pg_type typTup;
03360 
03361     rel = heap_open(TypeRelationId, RowExclusiveLock);
03362 
03363     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
03364     if (!HeapTupleIsValid(tup))
03365         elog(ERROR, "cache lookup failed for type %u", typeOid);
03366     typTup = (Form_pg_type) GETSTRUCT(tup);
03367 
03368     /*
03369      * Modify the owner --- okay to scribble on typTup because it's a copy
03370      */
03371     typTup->typowner = newOwnerId;
03372 
03373     simple_heap_update(rel, &tup->t_self, tup);
03374 
03375     CatalogUpdateIndexes(rel, tup);
03376 
03377     /* Update owner dependency reference, if it has one */
03378     if (hasDependEntry)
03379         changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
03380 
03381     /* If it has an array type, update that too */
03382     if (OidIsValid(typTup->typarray))
03383         AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
03384 
03385     InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
03386 
03387     /* Clean up */
03388     heap_close(rel, RowExclusiveLock);
03389 }
03390 
03391 /*
03392  * Execute ALTER TYPE SET SCHEMA
03393  */
03394 Oid
03395 AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype)
03396 {
03397     TypeName   *typename;
03398     Oid         typeOid;
03399     Oid         nspOid;
03400     ObjectAddresses *objsMoved;
03401 
03402     /* Make a TypeName so we can use standard type lookup machinery */
03403     typename = makeTypeNameFromNameList(names);
03404     typeOid = typenameTypeId(NULL, typename);
03405 
03406     /* Don't allow ALTER DOMAIN on a type */
03407     if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
03408         ereport(ERROR,
03409                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
03410                  errmsg("%s is not a domain",
03411                         format_type_be(typeOid))));
03412 
03413     /* get schema OID and check its permissions */
03414     nspOid = LookupCreationNamespace(newschema);
03415 
03416     objsMoved = new_object_addresses();
03417     AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
03418     free_object_addresses(objsMoved);
03419 
03420     return typeOid;
03421 }
03422 
03423 Oid
03424 AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
03425 {
03426     Oid         elemOid;
03427 
03428     /* check permissions on type */
03429     if (!pg_type_ownercheck(typeOid, GetUserId()))
03430         aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
03431 
03432     /* don't allow direct alteration of array types */
03433     elemOid = get_element_type(typeOid);
03434     if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
03435         ereport(ERROR,
03436                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
03437                  errmsg("cannot alter array type %s",
03438                         format_type_be(typeOid)),
03439                  errhint("You can alter type %s, which will alter the array type as well.",
03440                          format_type_be(elemOid))));
03441 
03442     /* and do the work */
03443     return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
03444 }
03445 
03446 /*
03447  * Move specified type to new namespace.
03448  *
03449  * Caller must have already checked privileges.
03450  *
03451  * The function automatically recurses to process the type's array type,
03452  * if any.  isImplicitArray should be TRUE only when doing this internal
03453  * recursion (outside callers must never try to move an array type directly).
03454  *
03455  * If errorOnTableType is TRUE, the function errors out if the type is
03456  * a table type.  ALTER TABLE has to be used to move a table to a new
03457  * namespace.
03458  *
03459  * Returns the type's old namespace OID.
03460  */
03461 Oid
03462 AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
03463                            bool isImplicitArray,
03464                            bool errorOnTableType,
03465                            ObjectAddresses *objsMoved)
03466 {
03467     Relation    rel;
03468     HeapTuple   tup;
03469     Form_pg_type typform;
03470     Oid         oldNspOid;
03471     Oid         arrayOid;
03472     bool        isCompositeType;
03473     ObjectAddress thisobj;
03474 
03475     /*
03476      * Make sure we haven't moved this object previously.
03477      */
03478     thisobj.classId = TypeRelationId;
03479     thisobj.objectId = typeOid;
03480     thisobj.objectSubId = 0;
03481 
03482     if (object_address_present(&thisobj, objsMoved))
03483         return InvalidOid;
03484 
03485     rel = heap_open(TypeRelationId, RowExclusiveLock);
03486 
03487     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
03488     if (!HeapTupleIsValid(tup))
03489         elog(ERROR, "cache lookup failed for type %u", typeOid);
03490     typform = (Form_pg_type) GETSTRUCT(tup);
03491 
03492     oldNspOid = typform->typnamespace;
03493     arrayOid = typform->typarray;
03494 
03495     /* common checks on switching namespaces */
03496     CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
03497 
03498     /* check for duplicate name (more friendly than unique-index failure) */
03499     if (SearchSysCacheExists2(TYPENAMENSP,
03500                               CStringGetDatum(NameStr(typform->typname)),
03501                               ObjectIdGetDatum(nspOid)))
03502         ereport(ERROR,
03503                 (errcode(ERRCODE_DUPLICATE_OBJECT),
03504                  errmsg("type \"%s\" already exists in schema \"%s\"",
03505                         NameStr(typform->typname),
03506                         get_namespace_name(nspOid))));
03507 
03508     /* Detect whether type is a composite type (but not a table rowtype) */
03509     isCompositeType =
03510         (typform->typtype == TYPTYPE_COMPOSITE &&
03511          get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
03512 
03513     /* Enforce not-table-type if requested */
03514     if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
03515         errorOnTableType)
03516         ereport(ERROR,
03517                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
03518                  errmsg("%s is a table's row type",
03519                         format_type_be(typeOid)),
03520                  errhint("Use ALTER TABLE instead.")));
03521 
03522     /* OK, modify the pg_type row */
03523 
03524     /* tup is a copy, so we can scribble directly on it */
03525     typform->typnamespace = nspOid;
03526 
03527     simple_heap_update(rel, &tup->t_self, tup);
03528     CatalogUpdateIndexes(rel, tup);
03529 
03530     /*
03531      * Composite types have pg_class entries.
03532      *
03533      * We need to modify the pg_class tuple as well to reflect the change of
03534      * schema.
03535      */
03536     if (isCompositeType)
03537     {
03538         Relation    classRel;
03539 
03540         classRel = heap_open(RelationRelationId, RowExclusiveLock);
03541 
03542         AlterRelationNamespaceInternal(classRel, typform->typrelid,
03543                                        oldNspOid, nspOid,
03544                                        false, objsMoved);
03545 
03546         heap_close(classRel, RowExclusiveLock);
03547 
03548         /*
03549          * Check for constraints associated with the composite type (we don't
03550          * currently support this, but probably will someday).
03551          */
03552         AlterConstraintNamespaces(typform->typrelid, oldNspOid,
03553                                   nspOid, false, objsMoved);
03554     }
03555     else
03556     {
03557         /* If it's a domain, it might have constraints */
03558         if (typform->typtype == TYPTYPE_DOMAIN)
03559             AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
03560                                       objsMoved);
03561     }
03562 
03563     /*
03564      * Update dependency on schema, if any --- a table rowtype has not got
03565      * one, and neither does an implicit array.
03566      */
03567     if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
03568         !isImplicitArray)
03569         if (changeDependencyFor(TypeRelationId, typeOid,
03570                                 NamespaceRelationId, oldNspOid, nspOid) != 1)
03571             elog(ERROR, "failed to change schema dependency for type %s",
03572                  format_type_be(typeOid));
03573 
03574     InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
03575 
03576     heap_freetuple(tup);
03577 
03578     heap_close(rel, RowExclusiveLock);
03579 
03580     add_exact_object_address(&thisobj, objsMoved);
03581 
03582     /* Recursively alter the associated array type, if any */
03583     if (OidIsValid(arrayOid))
03584         AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
03585 
03586     return oldNspOid;
03587 }