LCOV - code coverage report
Current view: top level - src/backend/commands - typecmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 809 1071 75.5 %
Date: 2017-09-29 15:12:54 Functions: 32 37 86.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * typecmds.c
       4             :  *    Routines for SQL commands that manipulate types (and domains).
       5             :  *
       6             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/commands/typecmds.c
      12             :  *
      13             :  * DESCRIPTION
      14             :  *    The "DefineFoo" routines take the parse tree and pick out the
      15             :  *    appropriate arguments/flags, passing the results to the
      16             :  *    corresponding "FooDefine" routines (in src/catalog) that do
      17             :  *    the actual catalog-munging.  These routines also verify permission
      18             :  *    of the user to execute the command.
      19             :  *
      20             :  * NOTES
      21             :  *    These things must be defined and committed in the following order:
      22             :  *      "create function":
      23             :  *              input/output, recv/send functions
      24             :  *      "create type":
      25             :  *              type
      26             :  *      "create operator":
      27             :  *              operators
      28             :  *
      29             :  *
      30             :  *-------------------------------------------------------------------------
      31             :  */
      32             : #include "postgres.h"
      33             : 
      34             : #include "access/htup_details.h"
      35             : #include "access/xact.h"
      36             : #include "catalog/binary_upgrade.h"
      37             : #include "catalog/catalog.h"
      38             : #include "catalog/heap.h"
      39             : #include "catalog/objectaccess.h"
      40             : #include "catalog/pg_am.h"
      41             : #include "catalog/pg_authid.h"
      42             : #include "catalog/pg_collation.h"
      43             : #include "catalog/pg_constraint.h"
      44             : #include "catalog/pg_constraint_fn.h"
      45             : #include "catalog/pg_depend.h"
      46             : #include "catalog/pg_enum.h"
      47             : #include "catalog/pg_language.h"
      48             : #include "catalog/pg_namespace.h"
      49             : #include "catalog/pg_proc.h"
      50             : #include "catalog/pg_proc_fn.h"
      51             : #include "catalog/pg_range.h"
      52             : #include "catalog/pg_type.h"
      53             : #include "catalog/pg_type_fn.h"
      54             : #include "commands/defrem.h"
      55             : #include "commands/tablecmds.h"
      56             : #include "commands/typecmds.h"
      57             : #include "executor/executor.h"
      58             : #include "miscadmin.h"
      59             : #include "nodes/makefuncs.h"
      60             : #include "optimizer/var.h"
      61             : #include "parser/parse_coerce.h"
      62             : #include "parser/parse_collate.h"
      63             : #include "parser/parse_expr.h"
      64             : #include "parser/parse_func.h"
      65             : #include "parser/parse_type.h"
      66             : #include "utils/builtins.h"
      67             : #include "utils/fmgroids.h"
      68             : #include "utils/lsyscache.h"
      69             : #include "utils/memutils.h"
      70             : #include "utils/rel.h"
      71             : #include "utils/ruleutils.h"
      72             : #include "utils/snapmgr.h"
      73             : #include "utils/syscache.h"
      74             : 
      75             : 
      76             : /* result structure for get_rels_with_domain() */
      77             : typedef struct
      78             : {
      79             :     Relation    rel;            /* opened and locked relation */
      80             :     int         natts;          /* number of attributes of interest */
      81             :     int        *atts;           /* attribute numbers */
      82             :     /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
      83             : } RelToCheck;
      84             : 
      85             : /* Potentially set by pg_upgrade_support functions */
      86             : Oid         binary_upgrade_next_array_pg_type_oid = InvalidOid;
      87             : 
      88             : static void makeRangeConstructors(const char *name, Oid namespace,
      89             :                       Oid rangeOid, Oid subtype);
      90             : static Oid  findTypeInputFunction(List *procname, Oid typeOid);
      91             : static Oid  findTypeOutputFunction(List *procname, Oid typeOid);
      92             : static Oid  findTypeReceiveFunction(List *procname, Oid typeOid);
      93             : static Oid  findTypeSendFunction(List *procname, Oid typeOid);
      94             : static Oid  findTypeTypmodinFunction(List *procname);
      95             : static Oid  findTypeTypmodoutFunction(List *procname);
      96             : static Oid  findTypeAnalyzeFunction(List *procname, Oid typeOid);
      97             : static Oid  findRangeSubOpclass(List *opcname, Oid subtype);
      98             : static Oid  findRangeCanonicalFunction(List *procname, Oid typeOid);
      99             : static Oid  findRangeSubtypeDiffFunction(List *procname, Oid subtype);
     100             : static void validateDomainConstraint(Oid domainoid, char *ccbin);
     101             : static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
     102             : static void checkEnumOwner(HeapTuple tup);
     103             : static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
     104             :                     Oid baseTypeOid,
     105             :                     int typMod, Constraint *constr,
     106             :                     char *domainName, ObjectAddress *constrAddr);
     107             : static Node *replace_domain_constraint_value(ParseState *pstate,
     108             :                                 ColumnRef *cref);
     109             : 
     110             : 
     111             : /*
     112             :  * DefineType
     113             :  *      Registers a new base type.
     114             :  */
     115             : ObjectAddress
     116          18 : DefineType(ParseState *pstate, List *names, List *parameters)
     117             : {
     118             :     char       *typeName;
     119             :     Oid         typeNamespace;
     120          18 :     int16       internalLength = -1;    /* default: variable-length */
     121          18 :     List       *inputName = NIL;
     122          18 :     List       *outputName = NIL;
     123          18 :     List       *receiveName = NIL;
     124          18 :     List       *sendName = NIL;
     125          18 :     List       *typmodinName = NIL;
     126          18 :     List       *typmodoutName = NIL;
     127          18 :     List       *analyzeName = NIL;
     128          18 :     char        category = TYPCATEGORY_USER;
     129          18 :     bool        preferred = false;
     130          18 :     char        delimiter = DEFAULT_TYPDELIM;
     131          18 :     Oid         elemType = InvalidOid;
     132          18 :     char       *defaultValue = NULL;
     133          18 :     bool        byValue = false;
     134          18 :     char        alignment = 'i';    /* default alignment */
     135          18 :     char        storage = 'p';  /* default TOAST storage method */
     136          18 :     Oid         collation = InvalidOid;
     137          18 :     DefElem    *likeTypeEl = NULL;
     138          18 :     DefElem    *internalLengthEl = NULL;
     139          18 :     DefElem    *inputNameEl = NULL;
     140          18 :     DefElem    *outputNameEl = NULL;
     141          18 :     DefElem    *receiveNameEl = NULL;
     142          18 :     DefElem    *sendNameEl = NULL;
     143          18 :     DefElem    *typmodinNameEl = NULL;
     144          18 :     DefElem    *typmodoutNameEl = NULL;
     145          18 :     DefElem    *analyzeNameEl = NULL;
     146          18 :     DefElem    *categoryEl = NULL;
     147          18 :     DefElem    *preferredEl = NULL;
     148          18 :     DefElem    *delimiterEl = NULL;
     149          18 :     DefElem    *elemTypeEl = NULL;
     150          18 :     DefElem    *defaultValueEl = NULL;
     151          18 :     DefElem    *byValueEl = NULL;
     152          18 :     DefElem    *alignmentEl = NULL;
     153          18 :     DefElem    *storageEl = NULL;
     154          18 :     DefElem    *collatableEl = NULL;
     155             :     Oid         inputOid;
     156             :     Oid         outputOid;
     157          18 :     Oid         receiveOid = InvalidOid;
     158          18 :     Oid         sendOid = InvalidOid;
     159          18 :     Oid         typmodinOid = InvalidOid;
     160          18 :     Oid         typmodoutOid = InvalidOid;
     161          18 :     Oid         analyzeOid = InvalidOid;
     162             :     char       *array_type;
     163             :     Oid         array_oid;
     164             :     Oid         typoid;
     165             :     Oid         resulttype;
     166             :     ListCell   *pl;
     167             :     ObjectAddress address;
     168             : 
     169             :     /*
     170             :      * As of Postgres 8.4, we require superuser privilege to create a base
     171             :      * type.  This is simple paranoia: there are too many ways to mess up the
     172             :      * system with an incorrect type definition (for instance, representation
     173             :      * parameters that don't match what the C code expects).  In practice it
     174             :      * takes superuser privilege to create the I/O functions, and so the
     175             :      * former requirement that you own the I/O functions pretty much forced
     176             :      * superuserness anyway.  We're just making doubly sure here.
     177             :      *
     178             :      * XXX re-enable NOT_USED code sections below if you remove this test.
     179             :      */
     180          18 :     if (!superuser())
     181           0 :         ereport(ERROR,
     182             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     183             :                  errmsg("must be superuser to create a base type")));
     184             : 
     185             :     /* Convert list of names to a name and namespace */
     186          18 :     typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
     187             : 
     188             : #ifdef NOT_USED
     189             :     /* XXX this is unnecessary given the superuser check above */
     190             :     /* Check we have creation rights in target namespace */
     191             :     aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
     192             :     if (aclresult != ACLCHECK_OK)
     193             :         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
     194             :                        get_namespace_name(typeNamespace));
     195             : #endif
     196             : 
     197             :     /*
     198             :      * Look to see if type already exists (presumably as a shell; if not,
     199             :      * TypeCreate will complain).
     200             :      */
     201          18 :     typoid = GetSysCacheOid2(TYPENAMENSP,
     202             :                              CStringGetDatum(typeName),
     203             :                              ObjectIdGetDatum(typeNamespace));
     204             : 
     205             :     /*
     206             :      * If it's not a shell, see if it's an autogenerated array type, and if so
     207             :      * rename it out of the way.
     208             :      */
     209          18 :     if (OidIsValid(typoid) && get_typisdefined(typoid))
     210             :     {
     211           1 :         if (moveArrayTypeName(typoid, typeName, typeNamespace))
     212           0 :             typoid = InvalidOid;
     213             :     }
     214             : 
     215             :     /*
     216             :      * If it doesn't exist, create it as a shell, so that the OID is known for
     217             :      * use in the I/O function definitions.
     218             :      */
     219          18 :     if (!OidIsValid(typoid))
     220             :     {
     221           9 :         address = TypeShellMake(typeName, typeNamespace, GetUserId());
     222           9 :         typoid = address.objectId;
     223             :         /* Make new shell type visible for modification below */
     224           9 :         CommandCounterIncrement();
     225             : 
     226             :         /*
     227             :          * If the command was a parameterless CREATE TYPE, we're done ---
     228             :          * creating the shell type was all we're supposed to do.
     229             :          */
     230           9 :         if (parameters == NIL)
     231           7 :             return address;
     232             :     }
     233             :     else
     234             :     {
     235             :         /* Complain if dummy CREATE TYPE and entry already exists */
     236           9 :         if (parameters == NIL)
     237           2 :             ereport(ERROR,
     238             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
     239             :                      errmsg("type \"%s\" already exists", typeName)));
     240             :     }
     241             : 
     242             :     /* Extract the parameters from the parameter list */
     243          48 :     foreach(pl, parameters)
     244             :     {
     245          39 :         DefElem    *defel = (DefElem *) lfirst(pl);
     246             :         DefElem   **defelp;
     247             : 
     248          39 :         if (pg_strcasecmp(defel->defname, "like") == 0)
     249           2 :             defelp = &likeTypeEl;
     250          37 :         else if (pg_strcasecmp(defel->defname, "internallength") == 0)
     251           6 :             defelp = &internalLengthEl;
     252          31 :         else if (pg_strcasecmp(defel->defname, "input") == 0)
     253           9 :             defelp = &inputNameEl;
     254          22 :         else if (pg_strcasecmp(defel->defname, "output") == 0)
     255           9 :             defelp = &outputNameEl;
     256          13 :         else if (pg_strcasecmp(defel->defname, "receive") == 0)
     257           0 :             defelp = &receiveNameEl;
     258          13 :         else if (pg_strcasecmp(defel->defname, "send") == 0)
     259           0 :             defelp = &sendNameEl;
     260          13 :         else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
     261           1 :             defelp = &typmodinNameEl;
     262          12 :         else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
     263           1 :             defelp = &typmodoutNameEl;
     264          22 :         else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
     265          11 :                  pg_strcasecmp(defel->defname, "analyse") == 0)
     266           0 :             defelp = &analyzeNameEl;
     267          11 :         else if (pg_strcasecmp(defel->defname, "category") == 0)
     268           1 :             defelp = &categoryEl;
     269          10 :         else if (pg_strcasecmp(defel->defname, "preferred") == 0)
     270           1 :             defelp = &preferredEl;
     271           9 :         else if (pg_strcasecmp(defel->defname, "delimiter") == 0)
     272           0 :             defelp = &delimiterEl;
     273           9 :         else if (pg_strcasecmp(defel->defname, "element") == 0)
     274           2 :             defelp = &elemTypeEl;
     275           7 :         else if (pg_strcasecmp(defel->defname, "default") == 0)
     276           2 :             defelp = &defaultValueEl;
     277           5 :         else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0)
     278           1 :             defelp = &byValueEl;
     279           4 :         else if (pg_strcasecmp(defel->defname, "alignment") == 0)
     280           4 :             defelp = &alignmentEl;
     281           0 :         else if (pg_strcasecmp(defel->defname, "storage") == 0)
     282           0 :             defelp = &storageEl;
     283           0 :         else if (pg_strcasecmp(defel->defname, "collatable") == 0)
     284           0 :             defelp = &collatableEl;
     285             :         else
     286             :         {
     287             :             /* WARNING, not ERROR, for historical backwards-compatibility */
     288           0 :             ereport(WARNING,
     289             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     290             :                      errmsg("type attribute \"%s\" not recognized",
     291             :                             defel->defname),
     292             :                      parser_errposition(pstate, defel->location)));
     293           0 :             continue;
     294             :         }
     295          39 :         if (*defelp != NULL)
     296           0 :             ereport(ERROR,
     297             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     298             :                      errmsg("conflicting or redundant options"),
     299             :                      parser_errposition(pstate, defel->location)));
     300          39 :         *defelp = defel;
     301             :     }
     302             : 
     303             :     /*
     304             :      * Now interpret the options; we do this separately so that LIKE can be
     305             :      * overridden by other options regardless of the ordering in the parameter
     306             :      * list.
     307             :      */
     308           9 :     if (likeTypeEl)
     309             :     {
     310             :         Type        likeType;
     311             :         Form_pg_type likeForm;
     312             : 
     313           2 :         likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
     314           2 :         likeForm = (Form_pg_type) GETSTRUCT(likeType);
     315           2 :         internalLength = likeForm->typlen;
     316           2 :         byValue = likeForm->typbyval;
     317           2 :         alignment = likeForm->typalign;
     318           2 :         storage = likeForm->typstorage;
     319           2 :         ReleaseSysCache(likeType);
     320             :     }
     321           9 :     if (internalLengthEl)
     322           6 :         internalLength = defGetTypeLength(internalLengthEl);
     323           9 :     if (inputNameEl)
     324           9 :         inputName = defGetQualifiedName(inputNameEl);
     325           9 :     if (outputNameEl)
     326           9 :         outputName = defGetQualifiedName(outputNameEl);
     327           9 :     if (receiveNameEl)
     328           0 :         receiveName = defGetQualifiedName(receiveNameEl);
     329           9 :     if (sendNameEl)
     330           0 :         sendName = defGetQualifiedName(sendNameEl);
     331           9 :     if (typmodinNameEl)
     332           1 :         typmodinName = defGetQualifiedName(typmodinNameEl);
     333           9 :     if (typmodoutNameEl)
     334           1 :         typmodoutName = defGetQualifiedName(typmodoutNameEl);
     335           9 :     if (analyzeNameEl)
     336           0 :         analyzeName = defGetQualifiedName(analyzeNameEl);
     337           9 :     if (categoryEl)
     338             :     {
     339           1 :         char       *p = defGetString(categoryEl);
     340             : 
     341           1 :         category = p[0];
     342             :         /* restrict to non-control ASCII */
     343           1 :         if (category < 32 || category > 126)
     344           0 :             ereport(ERROR,
     345             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     346             :                      errmsg("invalid type category \"%s\": must be simple ASCII",
     347             :                             p)));
     348             :     }
     349           9 :     if (preferredEl)
     350           1 :         preferred = defGetBoolean(preferredEl);
     351           9 :     if (delimiterEl)
     352             :     {
     353           0 :         char       *p = defGetString(delimiterEl);
     354             : 
     355           0 :         delimiter = p[0];
     356             :         /* XXX shouldn't we restrict the delimiter? */
     357             :     }
     358           9 :     if (elemTypeEl)
     359             :     {
     360           2 :         elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
     361             :         /* disallow arrays of pseudotypes */
     362           2 :         if (get_typtype(elemType) == TYPTYPE_PSEUDO)
     363           0 :             ereport(ERROR,
     364             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
     365             :                      errmsg("array element type cannot be %s",
     366             :                             format_type_be(elemType))));
     367             :     }
     368           9 :     if (defaultValueEl)
     369           2 :         defaultValue = defGetString(defaultValueEl);
     370           9 :     if (byValueEl)
     371           1 :         byValue = defGetBoolean(byValueEl);
     372           9 :     if (alignmentEl)
     373             :     {
     374           4 :         char       *a = defGetString(alignmentEl);
     375             : 
     376             :         /*
     377             :          * Note: if argument was an unquoted identifier, parser will have
     378             :          * applied translations to it, so be prepared to recognize translated
     379             :          * type names as well as the nominal form.
     380             :          */
     381           7 :         if (pg_strcasecmp(a, "double") == 0 ||
     382           6 :             pg_strcasecmp(a, "float8") == 0 ||
     383           3 :             pg_strcasecmp(a, "pg_catalog.float8") == 0)
     384           1 :             alignment = 'd';
     385           3 :         else if (pg_strcasecmp(a, "int4") == 0 ||
     386           0 :                  pg_strcasecmp(a, "pg_catalog.int4") == 0)
     387           3 :             alignment = 'i';
     388           0 :         else if (pg_strcasecmp(a, "int2") == 0 ||
     389           0 :                  pg_strcasecmp(a, "pg_catalog.int2") == 0)
     390           0 :             alignment = 's';
     391           0 :         else if (pg_strcasecmp(a, "char") == 0 ||
     392           0 :                  pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
     393           0 :             alignment = 'c';
     394             :         else
     395           0 :             ereport(ERROR,
     396             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     397             :                      errmsg("alignment \"%s\" not recognized", a)));
     398             :     }
     399           9 :     if (storageEl)
     400             :     {
     401           0 :         char       *a = defGetString(storageEl);
     402             : 
     403           0 :         if (pg_strcasecmp(a, "plain") == 0)
     404           0 :             storage = 'p';
     405           0 :         else if (pg_strcasecmp(a, "external") == 0)
     406           0 :             storage = 'e';
     407           0 :         else if (pg_strcasecmp(a, "extended") == 0)
     408           0 :             storage = 'x';
     409           0 :         else if (pg_strcasecmp(a, "main") == 0)
     410           0 :             storage = 'm';
     411             :         else
     412           0 :             ereport(ERROR,
     413             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     414             :                      errmsg("storage \"%s\" not recognized", a)));
     415             :     }
     416           9 :     if (collatableEl)
     417           0 :         collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
     418             : 
     419             :     /*
     420             :      * make sure we have our required definitions
     421             :      */
     422           9 :     if (inputName == NIL)
     423           0 :         ereport(ERROR,
     424             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     425             :                  errmsg("type input function must be specified")));
     426           9 :     if (outputName == NIL)
     427           0 :         ereport(ERROR,
     428             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     429             :                  errmsg("type output function must be specified")));
     430             : 
     431           9 :     if (typmodinName == NIL && typmodoutName != NIL)
     432           0 :         ereport(ERROR,
     433             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     434             :                  errmsg("type modifier output function is useless without a type modifier input function")));
     435             : 
     436             :     /*
     437             :      * Convert I/O proc names to OIDs
     438             :      */
     439           9 :     inputOid = findTypeInputFunction(inputName, typoid);
     440           9 :     outputOid = findTypeOutputFunction(outputName, typoid);
     441           8 :     if (receiveName)
     442           0 :         receiveOid = findTypeReceiveFunction(receiveName, typoid);
     443           8 :     if (sendName)
     444           0 :         sendOid = findTypeSendFunction(sendName, typoid);
     445             : 
     446             :     /*
     447             :      * Verify that I/O procs return the expected thing.  If we see OPAQUE,
     448             :      * complain and change it to the correct type-safe choice.
     449             :      */
     450           8 :     resulttype = get_func_rettype(inputOid);
     451           8 :     if (resulttype != typoid)
     452             :     {
     453           1 :         if (resulttype == OPAQUEOID)
     454             :         {
     455             :             /* backwards-compatibility hack */
     456           1 :             ereport(WARNING,
     457             :                     (errmsg("changing return type of function %s from %s to %s",
     458             :                             NameListToString(inputName), "opaque", typeName)));
     459           1 :             SetFunctionReturnType(inputOid, typoid);
     460             :         }
     461             :         else
     462           0 :             ereport(ERROR,
     463             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     464             :                      errmsg("type input function %s must return type %s",
     465             :                             NameListToString(inputName), typeName)));
     466             :     }
     467           8 :     resulttype = get_func_rettype(outputOid);
     468           8 :     if (resulttype != CSTRINGOID)
     469             :     {
     470           1 :         if (resulttype == OPAQUEOID)
     471             :         {
     472             :             /* backwards-compatibility hack */
     473           1 :             ereport(WARNING,
     474             :                     (errmsg("changing return type of function %s from %s to %s",
     475             :                             NameListToString(outputName), "opaque", "cstring")));
     476           1 :             SetFunctionReturnType(outputOid, CSTRINGOID);
     477             :         }
     478             :         else
     479           0 :             ereport(ERROR,
     480             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     481             :                      errmsg("type output function %s must return type %s",
     482             :                             NameListToString(outputName), "cstring")));
     483             :     }
     484           8 :     if (receiveOid)
     485             :     {
     486           0 :         resulttype = get_func_rettype(receiveOid);
     487           0 :         if (resulttype != typoid)
     488           0 :             ereport(ERROR,
     489             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     490             :                      errmsg("type receive function %s must return type %s",
     491             :                             NameListToString(receiveName), typeName)));
     492             :     }
     493           8 :     if (sendOid)
     494             :     {
     495           0 :         resulttype = get_func_rettype(sendOid);
     496           0 :         if (resulttype != BYTEAOID)
     497           0 :             ereport(ERROR,
     498             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     499             :                      errmsg("type send function %s must return type %s",
     500             :                             NameListToString(sendName), "bytea")));
     501             :     }
     502             : 
     503             :     /*
     504             :      * Convert typmodin/out function proc names to OIDs.
     505             :      */
     506           8 :     if (typmodinName)
     507           1 :         typmodinOid = findTypeTypmodinFunction(typmodinName);
     508           8 :     if (typmodoutName)
     509           1 :         typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
     510             : 
     511             :     /*
     512             :      * Convert analysis function proc name to an OID. If no analysis function
     513             :      * is specified, we'll use zero to select the built-in default algorithm.
     514             :      */
     515           8 :     if (analyzeName)
     516           0 :         analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
     517             : 
     518             :     /*
     519             :      * Check permissions on functions.  We choose to require the creator/owner
     520             :      * of a type to also own the underlying functions.  Since creating a type
     521             :      * is tantamount to granting public execute access on the functions, the
     522             :      * minimum sane check would be for execute-with-grant-option.  But we
     523             :      * don't have a way to make the type go away if the grant option is
     524             :      * revoked, so ownership seems better.
     525             :      */
     526             : #ifdef NOT_USED
     527             :     /* XXX this is unnecessary given the superuser check above */
     528             :     if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
     529             :         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
     530             :                        NameListToString(inputName));
     531             :     if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
     532             :         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
     533             :                        NameListToString(outputName));
     534             :     if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
     535             :         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
     536             :                        NameListToString(receiveName));
     537             :     if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
     538             :         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
     539             :                        NameListToString(sendName));
     540             :     if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
     541             :         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
     542             :                        NameListToString(typmodinName));
     543             :     if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
     544             :         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
     545             :                        NameListToString(typmodoutName));
     546             :     if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
     547             :         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
     548             :                        NameListToString(analyzeName));
     549             : #endif
     550             : 
     551             :     /*
     552             :      * Print warnings if any of the type's I/O functions are marked volatile.
     553             :      * There is a general assumption that I/O functions are stable or
     554             :      * immutable; this allows us for example to mark record_in/record_out
     555             :      * stable rather than volatile.  Ideally we would throw errors not just
     556             :      * warnings here; but since this check is new as of 9.5, and since the
     557             :      * volatility marking might be just an error-of-omission and not a true
     558             :      * indication of how the function behaves, we'll let it pass as a warning
     559             :      * for now.
     560             :      */
     561           8 :     if (inputOid && func_volatile(inputOid) == PROVOLATILE_VOLATILE)
     562           0 :         ereport(WARNING,
     563             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     564             :                  errmsg("type input function %s should not be volatile",
     565             :                         NameListToString(inputName))));
     566           8 :     if (outputOid && func_volatile(outputOid) == PROVOLATILE_VOLATILE)
     567           0 :         ereport(WARNING,
     568             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     569             :                  errmsg("type output function %s should not be volatile",
     570             :                         NameListToString(outputName))));
     571           8 :     if (receiveOid && func_volatile(receiveOid) == PROVOLATILE_VOLATILE)
     572           0 :         ereport(WARNING,
     573             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     574             :                  errmsg("type receive function %s should not be volatile",
     575             :                         NameListToString(receiveName))));
     576           8 :     if (sendOid && func_volatile(sendOid) == PROVOLATILE_VOLATILE)
     577           0 :         ereport(WARNING,
     578             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     579             :                  errmsg("type send function %s should not be volatile",
     580             :                         NameListToString(sendName))));
     581           8 :     if (typmodinOid && func_volatile(typmodinOid) == PROVOLATILE_VOLATILE)
     582           0 :         ereport(WARNING,
     583             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     584             :                  errmsg("type modifier input function %s should not be volatile",
     585             :                         NameListToString(typmodinName))));
     586           8 :     if (typmodoutOid && func_volatile(typmodoutOid) == PROVOLATILE_VOLATILE)
     587           0 :         ereport(WARNING,
     588             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     589             :                  errmsg("type modifier output function %s should not be volatile",
     590             :                         NameListToString(typmodoutName))));
     591             : 
     592             :     /*
     593             :      * OK, we're done checking, time to make the type.  We must assign the
     594             :      * array type OID ahead of calling TypeCreate, since the base type and
     595             :      * array type each refer to the other.
     596             :      */
     597           8 :     array_oid = AssignTypeArrayOid();
     598             : 
     599             :     /*
     600             :      * now have TypeCreate do all the real work.
     601             :      *
     602             :      * Note: the pg_type.oid is stored in user tables as array elements (base
     603             :      * types) in ArrayType and in composite types in DatumTupleFields.  This
     604             :      * oid must be preserved by binary upgrades.
     605             :      */
     606           8 :     address =
     607           8 :         TypeCreate(InvalidOid,  /* no predetermined type OID */
     608             :                    typeName,    /* type name */
     609             :                    typeNamespace,   /* namespace */
     610             :                    InvalidOid,  /* relation oid (n/a here) */
     611             :                    0,           /* relation kind (ditto) */
     612             :                    GetUserId(), /* owner's ID */
     613             :                    internalLength,  /* internal size */
     614             :                    TYPTYPE_BASE,    /* type-type (base type) */
     615             :                    category,    /* type-category */
     616             :                    preferred,   /* is it a preferred type? */
     617             :                    delimiter,   /* array element delimiter */
     618             :                    inputOid,    /* input procedure */
     619             :                    outputOid,   /* output procedure */
     620             :                    receiveOid,  /* receive procedure */
     621             :                    sendOid,     /* send procedure */
     622             :                    typmodinOid, /* typmodin procedure */
     623             :                    typmodoutOid,    /* typmodout procedure */
     624             :                    analyzeOid,  /* analyze procedure */
     625             :                    elemType,    /* element type ID */
     626             :                    false,       /* this is not an array type */
     627             :                    array_oid,   /* array type we are about to create */
     628             :                    InvalidOid,  /* base type ID (only for domains) */
     629             :                    defaultValue,    /* default type value */
     630             :                    NULL,        /* no binary form available */
     631             :                    byValue,     /* passed by value */
     632             :                    alignment,   /* required alignment */
     633             :                    storage,     /* TOAST strategy */
     634             :                    -1,          /* typMod (Domains only) */
     635             :                    0,           /* Array Dimensions of typbasetype */
     636             :                    false,       /* Type NOT NULL */
     637             :                    collation);  /* type's collation */
     638           8 :     Assert(typoid == address.objectId);
     639             : 
     640             :     /*
     641             :      * Create the array type that goes with it.
     642             :      */
     643           8 :     array_type = makeArrayTypeName(typeName, typeNamespace);
     644             : 
     645             :     /* alignment must be 'i' or 'd' for arrays */
     646           8 :     alignment = (alignment == 'd') ? 'd' : 'i';
     647             : 
     648           8 :     TypeCreate(array_oid,       /* force assignment of this type OID */
     649             :                array_type,      /* type name */
     650             :                typeNamespace,   /* namespace */
     651             :                InvalidOid,      /* relation oid (n/a here) */
     652             :                0,               /* relation kind (ditto) */
     653             :                GetUserId(),     /* owner's ID */
     654             :                -1,              /* internal size (always varlena) */
     655             :                TYPTYPE_BASE,    /* type-type (base type) */
     656             :                TYPCATEGORY_ARRAY,   /* type-category (array) */
     657             :                false,           /* array types are never preferred */
     658             :                delimiter,       /* array element delimiter */
     659             :                F_ARRAY_IN,      /* input procedure */
     660             :                F_ARRAY_OUT,     /* output procedure */
     661             :                F_ARRAY_RECV,    /* receive procedure */
     662             :                F_ARRAY_SEND,    /* send procedure */
     663             :                typmodinOid,     /* typmodin procedure */
     664             :                typmodoutOid,    /* typmodout procedure */
     665             :                F_ARRAY_TYPANALYZE,  /* analyze procedure */
     666             :                typoid,          /* element type ID */
     667             :                true,            /* yes this is an array type */
     668             :                InvalidOid,      /* no further array type */
     669             :                InvalidOid,      /* base type ID */
     670             :                NULL,            /* never a default type value */
     671             :                NULL,            /* binary default isn't sent either */
     672             :                false,           /* never passed by value */
     673             :                alignment,       /* see above */
     674             :                'x',             /* ARRAY is always toastable */
     675             :                -1,              /* typMod (Domains only) */
     676             :                0,               /* Array dimensions of typbasetype */
     677             :                false,           /* Type NOT NULL */
     678             :                collation);      /* type's collation */
     679             : 
     680           8 :     pfree(array_type);
     681             : 
     682           8 :     return address;
     683             : }
     684             : 
     685             : /*
     686             :  * Guts of type deletion.
     687             :  */
     688             : void
     689        3782 : RemoveTypeById(Oid typeOid)
     690             : {
     691             :     Relation    relation;
     692             :     HeapTuple   tup;
     693             : 
     694        3782 :     relation = heap_open(TypeRelationId, RowExclusiveLock);
     695             : 
     696        3782 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
     697        3782 :     if (!HeapTupleIsValid(tup))
     698           0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
     699             : 
     700        3782 :     CatalogTupleDelete(relation, &tup->t_self);
     701             : 
     702             :     /*
     703             :      * If it is an enum, delete the pg_enum entries too; we don't bother with
     704             :      * making dependency entries for those, so it has to be done "by hand"
     705             :      * here.
     706             :      */
     707        3782 :     if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
     708           8 :         EnumValuesDelete(typeOid);
     709             : 
     710             :     /*
     711             :      * If it is a range type, delete the pg_range entry too; we don't bother
     712             :      * with making a dependency entry for that, so it has to be done "by hand"
     713             :      * here.
     714             :      */
     715        3782 :     if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
     716           6 :         RangeDelete(typeOid);
     717             : 
     718        3782 :     ReleaseSysCache(tup);
     719             : 
     720        3782 :     heap_close(relation, RowExclusiveLock);
     721        3782 : }
     722             : 
     723             : 
     724             : /*
     725             :  * DefineDomain
     726             :  *      Registers a new domain.
     727             :  */
     728             : ObjectAddress
     729          77 : DefineDomain(CreateDomainStmt *stmt)
     730             : {
     731             :     char       *domainName;
     732             :     Oid         domainNamespace;
     733             :     AclResult   aclresult;
     734             :     int16       internalLength;
     735             :     Oid         inputProcedure;
     736             :     Oid         outputProcedure;
     737             :     Oid         receiveProcedure;
     738             :     Oid         sendProcedure;
     739             :     Oid         analyzeProcedure;
     740             :     bool        byValue;
     741             :     char        category;
     742             :     char        delimiter;
     743             :     char        alignment;
     744             :     char        storage;
     745             :     char        typtype;
     746             :     Datum       datum;
     747             :     bool        isnull;
     748          77 :     char       *defaultValue = NULL;
     749          77 :     char       *defaultValueBin = NULL;
     750          77 :     bool        saw_default = false;
     751          77 :     bool        typNotNull = false;
     752          77 :     bool        nullDefined = false;
     753          77 :     int32       typNDims = list_length(stmt->typeName->arrayBounds);
     754             :     HeapTuple   typeTup;
     755          77 :     List       *schema = stmt->constraints;
     756             :     ListCell   *listptr;
     757             :     Oid         basetypeoid;
     758             :     Oid         old_type_oid;
     759             :     Oid         domaincoll;
     760             :     Form_pg_type baseType;
     761             :     int32       basetypeMod;
     762             :     Oid         baseColl;
     763             :     ObjectAddress address;
     764             : 
     765             :     /* Convert list of names to a name and namespace */
     766          77 :     domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
     767             :                                                         &domainName);
     768             : 
     769             :     /* Check we have creation rights in target namespace */
     770          77 :     aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
     771             :                                       ACL_CREATE);
     772          77 :     if (aclresult != ACLCHECK_OK)
     773           0 :         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
     774           0 :                        get_namespace_name(domainNamespace));
     775             : 
     776             :     /*
     777             :      * Check for collision with an existing type name.  If there is one and
     778             :      * it's an autogenerated array, we can rename it out of the way.
     779             :      */
     780          77 :     old_type_oid = GetSysCacheOid2(TYPENAMENSP,
     781             :                                    CStringGetDatum(domainName),
     782             :                                    ObjectIdGetDatum(domainNamespace));
     783          77 :     if (OidIsValid(old_type_oid))
     784             :     {
     785           0 :         if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
     786           0 :             ereport(ERROR,
     787             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
     788             :                      errmsg("type \"%s\" already exists", domainName)));
     789             :     }
     790             : 
     791             :     /*
     792             :      * Look up the base type.
     793             :      */
     794          77 :     typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
     795          77 :     baseType = (Form_pg_type) GETSTRUCT(typeTup);
     796          77 :     basetypeoid = HeapTupleGetOid(typeTup);
     797             : 
     798             :     /*
     799             :      * Base type must be a plain base type, another domain, an enum or a range
     800             :      * type. Domains over pseudotypes would create a security hole.  Domains
     801             :      * over composite types might be made to work in the future, but not
     802             :      * today.
     803             :      */
     804          77 :     typtype = baseType->typtype;
     805          77 :     if (typtype != TYPTYPE_BASE &&
     806           2 :         typtype != TYPTYPE_DOMAIN &&
     807           1 :         typtype != TYPTYPE_ENUM &&
     808             :         typtype != TYPTYPE_RANGE)
     809           0 :         ereport(ERROR,
     810             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
     811             :                  errmsg("\"%s\" is not a valid base type for a domain",
     812             :                         TypeNameToString(stmt->typeName))));
     813             : 
     814          77 :     aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
     815          77 :     if (aclresult != ACLCHECK_OK)
     816           1 :         aclcheck_error_type(aclresult, basetypeoid);
     817             : 
     818             :     /*
     819             :      * Identify the collation if any
     820             :      */
     821          76 :     baseColl = baseType->typcollation;
     822          76 :     if (stmt->collClause)
     823           2 :         domaincoll = get_collation_oid(stmt->collClause->collname, false);
     824             :     else
     825          74 :         domaincoll = baseColl;
     826             : 
     827             :     /* Complain if COLLATE is applied to an uncollatable type */
     828          76 :     if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
     829           1 :         ereport(ERROR,
     830             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
     831             :                  errmsg("collations are not supported by type %s",
     832             :                         format_type_be(basetypeoid))));
     833             : 
     834             :     /* passed by value */
     835          75 :     byValue = baseType->typbyval;
     836             : 
     837             :     /* Required Alignment */
     838          75 :     alignment = baseType->typalign;
     839             : 
     840             :     /* TOAST Strategy */
     841          75 :     storage = baseType->typstorage;
     842             : 
     843             :     /* Storage Length */
     844          75 :     internalLength = baseType->typlen;
     845             : 
     846             :     /* Type Category */
     847          75 :     category = baseType->typcategory;
     848             : 
     849             :     /* Array element Delimiter */
     850          75 :     delimiter = baseType->typdelim;
     851             : 
     852             :     /* I/O Functions */
     853          75 :     inputProcedure = F_DOMAIN_IN;
     854          75 :     outputProcedure = baseType->typoutput;
     855          75 :     receiveProcedure = F_DOMAIN_RECV;
     856          75 :     sendProcedure = baseType->typsend;
     857             : 
     858             :     /* Domains never accept typmods, so no typmodin/typmodout needed */
     859             : 
     860             :     /* Analysis function */
     861          75 :     analyzeProcedure = baseType->typanalyze;
     862             : 
     863             :     /* Inherited default value */
     864          75 :     datum = SysCacheGetAttr(TYPEOID, typeTup,
     865             :                             Anum_pg_type_typdefault, &isnull);
     866          75 :     if (!isnull)
     867           0 :         defaultValue = TextDatumGetCString(datum);
     868             : 
     869             :     /* Inherited default binary value */
     870          75 :     datum = SysCacheGetAttr(TYPEOID, typeTup,
     871             :                             Anum_pg_type_typdefaultbin, &isnull);
     872          75 :     if (!isnull)
     873           0 :         defaultValueBin = TextDatumGetCString(datum);
     874             : 
     875             :     /*
     876             :      * Run through constraints manually to avoid the additional processing
     877             :      * conducted by DefineRelation() and friends.
     878             :      */
     879         114 :     foreach(listptr, schema)
     880             :     {
     881          39 :         Constraint *constr = lfirst(listptr);
     882             : 
     883          39 :         if (!IsA(constr, Constraint))
     884           0 :             elog(ERROR, "unrecognized node type: %d",
     885             :                  (int) nodeTag(constr));
     886          39 :         switch (constr->contype)
     887             :         {
     888             :             case CONSTR_DEFAULT:
     889             : 
     890             :                 /*
     891             :                  * The inherited default value may be overridden by the user
     892             :                  * with the DEFAULT <expr> clause ... but only once.
     893             :                  */
     894           7 :                 if (saw_default)
     895           0 :                     ereport(ERROR,
     896             :                             (errcode(ERRCODE_SYNTAX_ERROR),
     897             :                              errmsg("multiple default expressions")));
     898           7 :                 saw_default = true;
     899             : 
     900           7 :                 if (constr->raw_expr)
     901             :                 {
     902             :                     ParseState *pstate;
     903             :                     Node       *defaultExpr;
     904             : 
     905             :                     /* Create a dummy ParseState for transformExpr */
     906           7 :                     pstate = make_parsestate(NULL);
     907             : 
     908             :                     /*
     909             :                      * Cook the constr->raw_expr into an expression. Note:
     910             :                      * name is strictly for error message
     911             :                      */
     912           7 :                     defaultExpr = cookDefault(pstate, constr->raw_expr,
     913             :                                               basetypeoid,
     914             :                                               basetypeMod,
     915             :                                               domainName);
     916             : 
     917             :                     /*
     918             :                      * If the expression is just a NULL constant, we treat it
     919             :                      * like not having a default.
     920             :                      *
     921             :                      * Note that if the basetype is another domain, we'll see
     922             :                      * a CoerceToDomain expr here and not discard the default.
     923             :                      * This is critical because the domain default needs to be
     924             :                      * retained to override any default that the base domain
     925             :                      * might have.
     926             :                      */
     927          14 :                     if (defaultExpr == NULL ||
     928          10 :                         (IsA(defaultExpr, Const) &&
     929           3 :                          ((Const *) defaultExpr)->constisnull))
     930             :                     {
     931           0 :                         defaultValue = NULL;
     932           0 :                         defaultValueBin = NULL;
     933             :                     }
     934             :                     else
     935             :                     {
     936             :                         /*
     937             :                          * Expression must be stored as a nodeToString result,
     938             :                          * but we also require a valid textual representation
     939             :                          * (mainly to make life easier for pg_dump).
     940             :                          */
     941           7 :                         defaultValue =
     942             :                             deparse_expression(defaultExpr,
     943             :                                                NIL, false, false);
     944           7 :                         defaultValueBin = nodeToString(defaultExpr);
     945             :                     }
     946             :                 }
     947             :                 else
     948             :                 {
     949             :                     /* No default (can this still happen?) */
     950           0 :                     defaultValue = NULL;
     951           0 :                     defaultValueBin = NULL;
     952             :                 }
     953           7 :                 break;
     954             : 
     955             :             case CONSTR_NOTNULL:
     956           8 :                 if (nullDefined && !typNotNull)
     957           0 :                     ereport(ERROR,
     958             :                             (errcode(ERRCODE_SYNTAX_ERROR),
     959             :                              errmsg("conflicting NULL/NOT NULL constraints")));
     960           8 :                 typNotNull = true;
     961           8 :                 nullDefined = true;
     962           8 :                 break;
     963             : 
     964             :             case CONSTR_NULL:
     965           0 :                 if (nullDefined && typNotNull)
     966           0 :                     ereport(ERROR,
     967             :                             (errcode(ERRCODE_SYNTAX_ERROR),
     968             :                              errmsg("conflicting NULL/NOT NULL constraints")));
     969           0 :                 typNotNull = false;
     970           0 :                 nullDefined = true;
     971           0 :                 break;
     972             : 
     973             :             case CONSTR_CHECK:
     974             : 
     975             :                 /*
     976             :                  * Check constraints are handled after domain creation, as
     977             :                  * they require the Oid of the domain; at this point we can
     978             :                  * only check that they're not marked NO INHERIT, because that
     979             :                  * would be bogus.
     980             :                  */
     981          24 :                 if (constr->is_no_inherit)
     982           0 :                     ereport(ERROR,
     983             :                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     984             :                              errmsg("check constraints for domains cannot be marked NO INHERIT")));
     985          24 :                 break;
     986             : 
     987             :                 /*
     988             :                  * All else are error cases
     989             :                  */
     990             :             case CONSTR_UNIQUE:
     991           0 :                 ereport(ERROR,
     992             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     993             :                          errmsg("unique constraints not possible for domains")));
     994             :                 break;
     995             : 
     996             :             case CONSTR_PRIMARY:
     997           0 :                 ereport(ERROR,
     998             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     999             :                          errmsg("primary key constraints not possible for domains")));
    1000             :                 break;
    1001             : 
    1002             :             case CONSTR_EXCLUSION:
    1003           0 :                 ereport(ERROR,
    1004             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1005             :                          errmsg("exclusion constraints not possible for domains")));
    1006             :                 break;
    1007             : 
    1008             :             case CONSTR_FOREIGN:
    1009           0 :                 ereport(ERROR,
    1010             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1011             :                          errmsg("foreign key constraints not possible for domains")));
    1012             :                 break;
    1013             : 
    1014             :             case CONSTR_ATTR_DEFERRABLE:
    1015             :             case CONSTR_ATTR_NOT_DEFERRABLE:
    1016             :             case CONSTR_ATTR_DEFERRED:
    1017             :             case CONSTR_ATTR_IMMEDIATE:
    1018           0 :                 ereport(ERROR,
    1019             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1020             :                          errmsg("specifying constraint deferrability not supported for domains")));
    1021             :                 break;
    1022             : 
    1023             :             default:
    1024           0 :                 elog(ERROR, "unrecognized constraint subtype: %d",
    1025             :                      (int) constr->contype);
    1026             :                 break;
    1027             :         }
    1028             :     }
    1029             : 
    1030             :     /*
    1031             :      * Have TypeCreate do all the real work.
    1032             :      */
    1033          75 :     address =
    1034          75 :         TypeCreate(InvalidOid,  /* no predetermined type OID */
    1035             :                    domainName,  /* type name */
    1036             :                    domainNamespace, /* namespace */
    1037             :                    InvalidOid,  /* relation oid (n/a here) */
    1038             :                    0,           /* relation kind (ditto) */
    1039             :                    GetUserId(), /* owner's ID */
    1040             :                    internalLength,  /* internal size */
    1041             :                    TYPTYPE_DOMAIN,  /* type-type (domain type) */
    1042             :                    category,    /* type-category */
    1043             :                    false,       /* domain types are never preferred */
    1044             :                    delimiter,   /* array element delimiter */
    1045             :                    inputProcedure,  /* input procedure */
    1046             :                    outputProcedure, /* output procedure */
    1047             :                    receiveProcedure,    /* receive procedure */
    1048             :                    sendProcedure,   /* send procedure */
    1049             :                    InvalidOid,  /* typmodin procedure - none */
    1050             :                    InvalidOid,  /* typmodout procedure - none */
    1051             :                    analyzeProcedure,    /* analyze procedure */
    1052             :                    InvalidOid,  /* no array element type */
    1053             :                    false,       /* this isn't an array */
    1054             :                    InvalidOid,  /* no arrays for domains (yet) */
    1055             :                    basetypeoid, /* base type ID */
    1056             :                    defaultValue,    /* default type value (text) */
    1057             :                    defaultValueBin, /* default type value (binary) */
    1058             :                    byValue,     /* passed by value */
    1059             :                    alignment,   /* required alignment */
    1060             :                    storage,     /* TOAST strategy */
    1061             :                    basetypeMod, /* typeMod value */
    1062             :                    typNDims,    /* Array dimensions for base type */
    1063             :                    typNotNull,  /* Type NOT NULL */
    1064             :                    domaincoll); /* type's collation */
    1065             : 
    1066             :     /*
    1067             :      * Process constraints which refer to the domain ID returned by TypeCreate
    1068             :      */
    1069         114 :     foreach(listptr, schema)
    1070             :     {
    1071          39 :         Constraint *constr = lfirst(listptr);
    1072             : 
    1073             :         /* it must be a Constraint, per check above */
    1074             : 
    1075          39 :         switch (constr->contype)
    1076             :         {
    1077             :             case CONSTR_CHECK:
    1078          24 :                 domainAddConstraint(address.objectId, domainNamespace,
    1079             :                                     basetypeoid, basetypeMod,
    1080             :                                     constr, domainName, NULL);
    1081          24 :                 break;
    1082             : 
    1083             :                 /* Other constraint types were fully processed above */
    1084             : 
    1085             :             default:
    1086          15 :                 break;
    1087             :         }
    1088             : 
    1089             :         /* CCI so we can detect duplicate constraint names */
    1090          39 :         CommandCounterIncrement();
    1091             :     }
    1092             : 
    1093             :     /*
    1094             :      * Now we can clean up.
    1095             :      */
    1096          75 :     ReleaseSysCache(typeTup);
    1097             : 
    1098          75 :     return address;
    1099             : }
    1100             : 
    1101             : 
    1102             : /*
    1103             :  * DefineEnum
    1104             :  *      Registers a new enum.
    1105             :  */
    1106             : ObjectAddress
    1107          15 : DefineEnum(CreateEnumStmt *stmt)
    1108             : {
    1109             :     char       *enumName;
    1110             :     char       *enumArrayName;
    1111             :     Oid         enumNamespace;
    1112             :     AclResult   aclresult;
    1113             :     Oid         old_type_oid;
    1114             :     Oid         enumArrayOid;
    1115             :     ObjectAddress enumTypeAddr;
    1116             : 
    1117             :     /* Convert list of names to a name and namespace */
    1118          15 :     enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
    1119             :                                                       &enumName);
    1120             : 
    1121             :     /* Check we have creation rights in target namespace */
    1122          15 :     aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
    1123          15 :     if (aclresult != ACLCHECK_OK)
    1124           0 :         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
    1125           0 :                        get_namespace_name(enumNamespace));
    1126             : 
    1127             :     /*
    1128             :      * Check for collision with an existing type name.  If there is one and
    1129             :      * it's an autogenerated array, we can rename it out of the way.
    1130             :      */
    1131          15 :     old_type_oid = GetSysCacheOid2(TYPENAMENSP,
    1132             :                                    CStringGetDatum(enumName),
    1133             :                                    ObjectIdGetDatum(enumNamespace));
    1134          15 :     if (OidIsValid(old_type_oid))
    1135             :     {
    1136           1 :         if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
    1137           0 :             ereport(ERROR,
    1138             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    1139             :                      errmsg("type \"%s\" already exists", enumName)));
    1140             :     }
    1141             : 
    1142          15 :     enumArrayOid = AssignTypeArrayOid();
    1143             : 
    1144             :     /* Create the pg_type entry */
    1145          15 :     enumTypeAddr =
    1146          15 :         TypeCreate(InvalidOid,  /* no predetermined type OID */
    1147             :                    enumName,    /* type name */
    1148             :                    enumNamespace,   /* namespace */
    1149             :                    InvalidOid,  /* relation oid (n/a here) */
    1150             :                    0,           /* relation kind (ditto) */
    1151             :                    GetUserId(), /* owner's ID */
    1152             :                    sizeof(Oid), /* internal size */
    1153             :                    TYPTYPE_ENUM,    /* type-type (enum type) */
    1154             :                    TYPCATEGORY_ENUM,    /* type-category (enum type) */
    1155             :                    false,       /* enum types are never preferred */
    1156             :                    DEFAULT_TYPDELIM,    /* array element delimiter */
    1157             :                    F_ENUM_IN,   /* input procedure */
    1158             :                    F_ENUM_OUT,  /* output procedure */
    1159             :                    F_ENUM_RECV, /* receive procedure */
    1160             :                    F_ENUM_SEND, /* send procedure */
    1161             :                    InvalidOid,  /* typmodin procedure - none */
    1162             :                    InvalidOid,  /* typmodout procedure - none */
    1163             :                    InvalidOid,  /* analyze procedure - default */
    1164             :                    InvalidOid,  /* element type ID */
    1165             :                    false,       /* this is not an array type */
    1166             :                    enumArrayOid,    /* array type we are about to create */
    1167             :                    InvalidOid,  /* base type ID (only for domains) */
    1168             :                    NULL,        /* never a default type value */
    1169             :                    NULL,        /* binary default isn't sent either */
    1170             :                    true,        /* always passed by value */
    1171             :                    'i',         /* int alignment */
    1172             :                    'p',         /* TOAST strategy always plain */
    1173             :                    -1,          /* typMod (Domains only) */
    1174             :                    0,           /* Array dimensions of typbasetype */
    1175             :                    false,       /* Type NOT NULL */
    1176             :                    InvalidOid); /* type's collation */
    1177             : 
    1178             :     /* Enter the enum's values into pg_enum */
    1179          15 :     EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
    1180             : 
    1181             :     /*
    1182             :      * Create the array type that goes with it.
    1183             :      */
    1184          15 :     enumArrayName = makeArrayTypeName(enumName, enumNamespace);
    1185             : 
    1186          15 :     TypeCreate(enumArrayOid,    /* force assignment of this type OID */
    1187             :                enumArrayName,   /* type name */
    1188             :                enumNamespace,   /* namespace */
    1189             :                InvalidOid,      /* relation oid (n/a here) */
    1190             :                0,               /* relation kind (ditto) */
    1191             :                GetUserId(),     /* owner's ID */
    1192             :                -1,              /* internal size (always varlena) */
    1193             :                TYPTYPE_BASE,    /* type-type (base type) */
    1194             :                TYPCATEGORY_ARRAY,   /* type-category (array) */
    1195             :                false,           /* array types are never preferred */
    1196             :                DEFAULT_TYPDELIM,    /* array element delimiter */
    1197             :                F_ARRAY_IN,      /* input procedure */
    1198             :                F_ARRAY_OUT,     /* output procedure */
    1199             :                F_ARRAY_RECV,    /* receive procedure */
    1200             :                F_ARRAY_SEND,    /* send procedure */
    1201             :                InvalidOid,      /* typmodin procedure - none */
    1202             :                InvalidOid,      /* typmodout procedure - none */
    1203             :                F_ARRAY_TYPANALYZE,  /* analyze procedure */
    1204             :                enumTypeAddr.objectId,   /* element type ID */
    1205             :                true,            /* yes this is an array type */
    1206             :                InvalidOid,      /* no further array type */
    1207             :                InvalidOid,      /* base type ID */
    1208             :                NULL,            /* never a default type value */
    1209             :                NULL,            /* binary default isn't sent either */
    1210             :                false,           /* never passed by value */
    1211             :                'i',             /* enums have align i, so do their arrays */
    1212             :                'x',             /* ARRAY is always toastable */
    1213             :                -1,              /* typMod (Domains only) */
    1214             :                0,               /* Array dimensions of typbasetype */
    1215             :                false,           /* Type NOT NULL */
    1216             :                InvalidOid);     /* type's collation */
    1217             : 
    1218          15 :     pfree(enumArrayName);
    1219             : 
    1220          15 :     return enumTypeAddr;
    1221             : }
    1222             : 
    1223             : /*
    1224             :  * AlterEnum
    1225             :  *      Adds a new label to an existing enum.
    1226             :  */
    1227             : ObjectAddress
    1228          47 : AlterEnum(AlterEnumStmt *stmt)
    1229             : {
    1230             :     Oid         enum_type_oid;
    1231             :     TypeName   *typename;
    1232             :     HeapTuple   tup;
    1233             :     ObjectAddress address;
    1234             : 
    1235             :     /* Make a TypeName so we can use standard type lookup machinery */
    1236          47 :     typename = makeTypeNameFromNameList(stmt->typeName);
    1237          47 :     enum_type_oid = typenameTypeId(NULL, typename);
    1238             : 
    1239          47 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
    1240          47 :     if (!HeapTupleIsValid(tup))
    1241           0 :         elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
    1242             : 
    1243             :     /* Check it's an enum and check user has permission to ALTER the enum */
    1244          47 :     checkEnumOwner(tup);
    1245             : 
    1246          47 :     ReleaseSysCache(tup);
    1247             : 
    1248          47 :     if (stmt->oldVal)
    1249             :     {
    1250             :         /* Rename an existing label */
    1251           3 :         RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
    1252             :     }
    1253             :     else
    1254             :     {
    1255             :         /* Add a new label */
    1256         132 :         AddEnumLabel(enum_type_oid, stmt->newVal,
    1257          88 :                      stmt->newValNeighbor, stmt->newValIsAfter,
    1258          44 :                      stmt->skipIfNewValExists);
    1259             :     }
    1260             : 
    1261          42 :     InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
    1262             : 
    1263          42 :     ObjectAddressSet(address, TypeRelationId, enum_type_oid);
    1264             : 
    1265          42 :     return address;
    1266             : }
    1267             : 
    1268             : 
    1269             : /*
    1270             :  * checkEnumOwner
    1271             :  *
    1272             :  * Check that the type is actually an enum and that the current user
    1273             :  * has permission to do ALTER TYPE on it.  Throw an error if not.
    1274             :  */
    1275             : static void
    1276          47 : checkEnumOwner(HeapTuple tup)
    1277             : {
    1278          47 :     Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
    1279             : 
    1280             :     /* Check that this is actually an enum */
    1281          47 :     if (typTup->typtype != TYPTYPE_ENUM)
    1282           0 :         ereport(ERROR,
    1283             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1284             :                  errmsg("%s is not an enum",
    1285             :                         format_type_be(HeapTupleGetOid(tup)))));
    1286             : 
    1287             :     /* Permission check: must own type */
    1288          47 :     if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
    1289           0 :         aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
    1290          47 : }
    1291             : 
    1292             : 
    1293             : /*
    1294             :  * DefineRange
    1295             :  *      Registers a new range type.
    1296             :  */
    1297             : ObjectAddress
    1298          10 : DefineRange(CreateRangeStmt *stmt)
    1299             : {
    1300             :     char       *typeName;
    1301             :     Oid         typeNamespace;
    1302             :     Oid         typoid;
    1303             :     char       *rangeArrayName;
    1304             :     Oid         rangeArrayOid;
    1305          10 :     Oid         rangeSubtype = InvalidOid;
    1306          10 :     List       *rangeSubOpclassName = NIL;
    1307          10 :     List       *rangeCollationName = NIL;
    1308          10 :     List       *rangeCanonicalName = NIL;
    1309          10 :     List       *rangeSubtypeDiffName = NIL;
    1310             :     Oid         rangeSubOpclass;
    1311             :     Oid         rangeCollation;
    1312             :     regproc     rangeCanonical;
    1313             :     regproc     rangeSubtypeDiff;
    1314             :     int16       subtyplen;
    1315             :     bool        subtypbyval;
    1316             :     char        subtypalign;
    1317             :     char        alignment;
    1318             :     AclResult   aclresult;
    1319             :     ListCell   *lc;
    1320             :     ObjectAddress address;
    1321             : 
    1322             :     /* Convert list of names to a name and namespace */
    1323          10 :     typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
    1324             :                                                       &typeName);
    1325             : 
    1326             :     /* Check we have creation rights in target namespace */
    1327          10 :     aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
    1328          10 :     if (aclresult != ACLCHECK_OK)
    1329           0 :         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
    1330           0 :                        get_namespace_name(typeNamespace));
    1331             : 
    1332             :     /*
    1333             :      * Look to see if type already exists.
    1334             :      */
    1335          10 :     typoid = GetSysCacheOid2(TYPENAMENSP,
    1336             :                              CStringGetDatum(typeName),
    1337             :                              ObjectIdGetDatum(typeNamespace));
    1338             : 
    1339             :     /*
    1340             :      * If it's not a shell, see if it's an autogenerated array type, and if so
    1341             :      * rename it out of the way.
    1342             :      */
    1343          10 :     if (OidIsValid(typoid) && get_typisdefined(typoid))
    1344             :     {
    1345           0 :         if (moveArrayTypeName(typoid, typeName, typeNamespace))
    1346           0 :             typoid = InvalidOid;
    1347             :         else
    1348           0 :             ereport(ERROR,
    1349             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    1350             :                      errmsg("type \"%s\" already exists", typeName)));
    1351             :     }
    1352             : 
    1353             :     /*
    1354             :      * If it doesn't exist, create it as a shell, so that the OID is known for
    1355             :      * use in the range function definitions.
    1356             :      */
    1357          10 :     if (!OidIsValid(typoid))
    1358             :     {
    1359          10 :         address = TypeShellMake(typeName, typeNamespace, GetUserId());
    1360          10 :         typoid = address.objectId;
    1361             :         /* Make new shell type visible for modification below */
    1362          10 :         CommandCounterIncrement();
    1363             :     }
    1364             : 
    1365             :     /* Extract the parameters from the parameter list */
    1366          25 :     foreach(lc, stmt->params)
    1367             :     {
    1368          15 :         DefElem    *defel = (DefElem *) lfirst(lc);
    1369             : 
    1370          15 :         if (pg_strcasecmp(defel->defname, "subtype") == 0)
    1371             :         {
    1372          10 :             if (OidIsValid(rangeSubtype))
    1373           0 :                 ereport(ERROR,
    1374             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1375             :                          errmsg("conflicting or redundant options")));
    1376             :             /* we can look up the subtype name immediately */
    1377          10 :             rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
    1378             :         }
    1379           5 :         else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
    1380             :         {
    1381           0 :             if (rangeSubOpclassName != NIL)
    1382           0 :                 ereport(ERROR,
    1383             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1384             :                          errmsg("conflicting or redundant options")));
    1385           0 :             rangeSubOpclassName = defGetQualifiedName(defel);
    1386             :         }
    1387           5 :         else if (pg_strcasecmp(defel->defname, "collation") == 0)
    1388             :         {
    1389           3 :             if (rangeCollationName != NIL)
    1390           0 :                 ereport(ERROR,
    1391             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1392             :                          errmsg("conflicting or redundant options")));
    1393           3 :             rangeCollationName = defGetQualifiedName(defel);
    1394             :         }
    1395           2 :         else if (pg_strcasecmp(defel->defname, "canonical") == 0)
    1396             :         {
    1397           0 :             if (rangeCanonicalName != NIL)
    1398           0 :                 ereport(ERROR,
    1399             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1400             :                          errmsg("conflicting or redundant options")));
    1401           0 :             rangeCanonicalName = defGetQualifiedName(defel);
    1402             :         }
    1403           2 :         else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
    1404             :         {
    1405           2 :             if (rangeSubtypeDiffName != NIL)
    1406           0 :                 ereport(ERROR,
    1407             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1408             :                          errmsg("conflicting or redundant options")));
    1409           2 :             rangeSubtypeDiffName = defGetQualifiedName(defel);
    1410             :         }
    1411             :         else
    1412           0 :             ereport(ERROR,
    1413             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    1414             :                      errmsg("type attribute \"%s\" not recognized",
    1415             :                             defel->defname)));
    1416             :     }
    1417             : 
    1418             :     /* Must have a subtype */
    1419          10 :     if (!OidIsValid(rangeSubtype))
    1420           0 :         ereport(ERROR,
    1421             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    1422             :                  errmsg("type attribute \"subtype\" is required")));
    1423             :     /* disallow ranges of pseudotypes */
    1424          10 :     if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
    1425           0 :         ereport(ERROR,
    1426             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    1427             :                  errmsg("range subtype cannot be %s",
    1428             :                         format_type_be(rangeSubtype))));
    1429             : 
    1430             :     /* Identify subopclass */
    1431          10 :     rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
    1432             : 
    1433             :     /* Identify collation to use, if any */
    1434          10 :     if (type_is_collatable(rangeSubtype))
    1435             :     {
    1436           3 :         if (rangeCollationName != NIL)
    1437           3 :             rangeCollation = get_collation_oid(rangeCollationName, false);
    1438             :         else
    1439           0 :             rangeCollation = get_typcollation(rangeSubtype);
    1440             :     }
    1441             :     else
    1442             :     {
    1443           7 :         if (rangeCollationName != NIL)
    1444           0 :             ereport(ERROR,
    1445             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1446             :                      errmsg("range collation specified but subtype does not support collation")));
    1447           7 :         rangeCollation = InvalidOid;
    1448             :     }
    1449             : 
    1450             :     /* Identify support functions, if provided */
    1451          10 :     if (rangeCanonicalName != NIL)
    1452           0 :         rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
    1453             :                                                     typoid);
    1454             :     else
    1455          10 :         rangeCanonical = InvalidOid;
    1456             : 
    1457          10 :     if (rangeSubtypeDiffName != NIL)
    1458           2 :         rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
    1459             :                                                         rangeSubtype);
    1460             :     else
    1461           8 :         rangeSubtypeDiff = InvalidOid;
    1462             : 
    1463           9 :     get_typlenbyvalalign(rangeSubtype,
    1464             :                          &subtyplen, &subtypbyval, &subtypalign);
    1465             : 
    1466             :     /* alignment must be 'i' or 'd' for ranges */
    1467           9 :     alignment = (subtypalign == 'd') ? 'd' : 'i';
    1468             : 
    1469             :     /* Allocate OID for array type */
    1470           9 :     rangeArrayOid = AssignTypeArrayOid();
    1471             : 
    1472             :     /* Create the pg_type entry */
    1473           9 :     address =
    1474           9 :         TypeCreate(InvalidOid,  /* no predetermined type OID */
    1475             :                    typeName,    /* type name */
    1476             :                    typeNamespace,   /* namespace */
    1477             :                    InvalidOid,  /* relation oid (n/a here) */
    1478             :                    0,           /* relation kind (ditto) */
    1479             :                    GetUserId(), /* owner's ID */
    1480             :                    -1,          /* internal size (always varlena) */
    1481             :                    TYPTYPE_RANGE,   /* type-type (range type) */
    1482             :                    TYPCATEGORY_RANGE,   /* type-category (range type) */
    1483             :                    false,       /* range types are never preferred */
    1484             :                    DEFAULT_TYPDELIM,    /* array element delimiter */
    1485             :                    F_RANGE_IN,  /* input procedure */
    1486             :                    F_RANGE_OUT, /* output procedure */
    1487             :                    F_RANGE_RECV,    /* receive procedure */
    1488             :                    F_RANGE_SEND,    /* send procedure */
    1489             :                    InvalidOid,  /* typmodin procedure - none */
    1490             :                    InvalidOid,  /* typmodout procedure - none */
    1491             :                    F_RANGE_TYPANALYZE,  /* analyze procedure */
    1492             :                    InvalidOid,  /* element type ID - none */
    1493             :                    false,       /* this is not an array type */
    1494             :                    rangeArrayOid,   /* array type we are about to create */
    1495             :                    InvalidOid,  /* base type ID (only for domains) */
    1496             :                    NULL,        /* never a default type value */
    1497             :                    NULL,        /* no binary form available either */
    1498             :                    false,       /* never passed by value */
    1499             :                    alignment,   /* alignment */
    1500             :                    'x',         /* TOAST strategy (always extended) */
    1501             :                    -1,          /* typMod (Domains only) */
    1502             :                    0,           /* Array dimensions of typbasetype */
    1503             :                    false,       /* Type NOT NULL */
    1504             :                    InvalidOid); /* type's collation (ranges never have one) */
    1505           9 :     Assert(typoid == address.objectId);
    1506             : 
    1507             :     /* Create the entry in pg_range */
    1508           9 :     RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
    1509             :                 rangeCanonical, rangeSubtypeDiff);
    1510             : 
    1511             :     /*
    1512             :      * Create the array type that goes with it.
    1513             :      */
    1514           9 :     rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
    1515             : 
    1516           9 :     TypeCreate(rangeArrayOid,   /* force assignment of this type OID */
    1517             :                rangeArrayName,  /* type name */
    1518             :                typeNamespace,   /* namespace */
    1519             :                InvalidOid,      /* relation oid (n/a here) */
    1520             :                0,               /* relation kind (ditto) */
    1521             :                GetUserId(),     /* owner's ID */
    1522             :                -1,              /* internal size (always varlena) */
    1523             :                TYPTYPE_BASE,    /* type-type (base type) */
    1524             :                TYPCATEGORY_ARRAY,   /* type-category (array) */
    1525             :                false,           /* array types are never preferred */
    1526             :                DEFAULT_TYPDELIM,    /* array element delimiter */
    1527             :                F_ARRAY_IN,      /* input procedure */
    1528             :                F_ARRAY_OUT,     /* output procedure */
    1529             :                F_ARRAY_RECV,    /* receive procedure */
    1530             :                F_ARRAY_SEND,    /* send procedure */
    1531             :                InvalidOid,      /* typmodin procedure - none */
    1532             :                InvalidOid,      /* typmodout procedure - none */
    1533             :                F_ARRAY_TYPANALYZE,  /* analyze procedure */
    1534             :                typoid,          /* element type ID */
    1535             :                true,            /* yes this is an array type */
    1536             :                InvalidOid,      /* no further array type */
    1537             :                InvalidOid,      /* base type ID */
    1538             :                NULL,            /* never a default type value */
    1539             :                NULL,            /* binary default isn't sent either */
    1540             :                false,           /* never passed by value */
    1541             :                alignment,       /* alignment - same as range's */
    1542             :                'x',             /* ARRAY is always toastable */
    1543             :                -1,              /* typMod (Domains only) */
    1544             :                0,               /* Array dimensions of typbasetype */
    1545             :                false,           /* Type NOT NULL */
    1546             :                InvalidOid);     /* typcollation */
    1547             : 
    1548           9 :     pfree(rangeArrayName);
    1549             : 
    1550             :     /* And create the constructor functions for this range type */
    1551           9 :     makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
    1552             : 
    1553           9 :     return address;
    1554             : }
    1555             : 
    1556             : /*
    1557             :  * Because there may exist several range types over the same subtype, the
    1558             :  * range type can't be uniquely determined from the subtype.  So it's
    1559             :  * impossible to define a polymorphic constructor; we have to generate new
    1560             :  * constructor functions explicitly for each range type.
    1561             :  *
    1562             :  * We actually define 4 functions, with 0 through 3 arguments.  This is just
    1563             :  * to offer more convenience for the user.
    1564             :  */
    1565             : static void
    1566           9 : makeRangeConstructors(const char *name, Oid namespace,
    1567             :                       Oid rangeOid, Oid subtype)
    1568             : {
    1569             :     static const char *const prosrc[2] = {"range_constructor2",
    1570             :     "range_constructor3"};
    1571             :     static const int pronargs[2] = {2, 3};
    1572             : 
    1573             :     Oid         constructorArgTypes[3];
    1574             :     ObjectAddress myself,
    1575             :                 referenced;
    1576             :     int         i;
    1577             : 
    1578           9 :     constructorArgTypes[0] = subtype;
    1579           9 :     constructorArgTypes[1] = subtype;
    1580           9 :     constructorArgTypes[2] = TEXTOID;
    1581             : 
    1582           9 :     referenced.classId = TypeRelationId;
    1583           9 :     referenced.objectId = rangeOid;
    1584           9 :     referenced.objectSubId = 0;
    1585             : 
    1586          27 :     for (i = 0; i < lengthof(prosrc); i++)
    1587             :     {
    1588             :         oidvector  *constructorArgTypesVector;
    1589             : 
    1590          18 :         constructorArgTypesVector = buildoidvector(constructorArgTypes,
    1591             :                                                    pronargs[i]);
    1592             : 
    1593          18 :         myself = ProcedureCreate(name,  /* name: same as range type */
    1594             :                                  namespace, /* namespace */
    1595             :                                  false, /* replace */
    1596             :                                  false, /* returns set */
    1597             :                                  rangeOid,  /* return type */
    1598             :                                  BOOTSTRAP_SUPERUSERID, /* proowner */
    1599             :                                  INTERNALlanguageId,    /* language */
    1600             :                                  F_FMGR_INTERNAL_VALIDATOR, /* language validator */
    1601             :                                  prosrc[i], /* prosrc */
    1602             :                                  NULL,  /* probin */
    1603             :                                  false, /* isAgg */
    1604             :                                  false, /* isWindowFunc */
    1605             :                                  false, /* security_definer */
    1606             :                                  false, /* leakproof */
    1607             :                                  false, /* isStrict */
    1608             :                                  PROVOLATILE_IMMUTABLE, /* volatility */
    1609             :                                  PROPARALLEL_SAFE,  /* parallel safety */
    1610             :                                  constructorArgTypesVector, /* parameterTypes */
    1611             :                                  PointerGetDatum(NULL), /* allParameterTypes */
    1612             :                                  PointerGetDatum(NULL), /* parameterModes */
    1613             :                                  PointerGetDatum(NULL), /* parameterNames */
    1614             :                                  NIL,   /* parameterDefaults */
    1615             :                                  PointerGetDatum(NULL), /* trftypes */
    1616             :                                  PointerGetDatum(NULL), /* proconfig */
    1617             :                                  1.0,   /* procost */
    1618             :                                  0.0);  /* prorows */
    1619             : 
    1620             :         /*
    1621             :          * Make the constructors internally-dependent on the range type so
    1622             :          * that they go away silently when the type is dropped.  Note that
    1623             :          * pg_dump depends on this choice to avoid dumping the constructors.
    1624             :          */
    1625          18 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
    1626             :     }
    1627           9 : }
    1628             : 
    1629             : 
    1630             : /*
    1631             :  * Find suitable I/O functions for a type.
    1632             :  *
    1633             :  * typeOid is the type's OID (which will already exist, if only as a shell
    1634             :  * type).
    1635             :  */
    1636             : 
    1637             : static Oid
    1638           9 : findTypeInputFunction(List *procname, Oid typeOid)
    1639             : {
    1640             :     Oid         argList[3];
    1641             :     Oid         procOid;
    1642             : 
    1643             :     /*
    1644             :      * Input functions can take a single argument of type CSTRING, or three
    1645             :      * arguments (string, typioparam OID, typmod).
    1646             :      *
    1647             :      * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
    1648             :      * see this, we issue a warning and fix up the pg_proc entry.
    1649             :      */
    1650           9 :     argList[0] = CSTRINGOID;
    1651             : 
    1652           9 :     procOid = LookupFuncName(procname, 1, argList, true);
    1653           9 :     if (OidIsValid(procOid))
    1654           8 :         return procOid;
    1655             : 
    1656           1 :     argList[1] = OIDOID;
    1657           1 :     argList[2] = INT4OID;
    1658             : 
    1659           1 :     procOid = LookupFuncName(procname, 3, argList, true);
    1660           1 :     if (OidIsValid(procOid))
    1661           1 :         return procOid;
    1662             : 
    1663             :     /* No luck, try it with OPAQUE */
    1664           0 :     argList[0] = OPAQUEOID;
    1665             : 
    1666           0 :     procOid = LookupFuncName(procname, 1, argList, true);
    1667             : 
    1668           0 :     if (!OidIsValid(procOid))
    1669             :     {
    1670           0 :         argList[1] = OIDOID;
    1671           0 :         argList[2] = INT4OID;
    1672             : 
    1673           0 :         procOid = LookupFuncName(procname, 3, argList, true);
    1674             :     }
    1675             : 
    1676           0 :     if (OidIsValid(procOid))
    1677             :     {
    1678             :         /* Found, but must complain and fix the pg_proc entry */
    1679           0 :         ereport(WARNING,
    1680             :                 (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
    1681             :                         NameListToString(procname))));
    1682           0 :         SetFunctionArgType(procOid, 0, CSTRINGOID);
    1683             : 
    1684             :         /*
    1685             :          * Need CommandCounterIncrement since DefineType will likely try to
    1686             :          * alter the pg_proc tuple again.
    1687             :          */
    1688           0 :         CommandCounterIncrement();
    1689             : 
    1690           0 :         return procOid;
    1691             :     }
    1692             : 
    1693             :     /* Use CSTRING (preferred) in the error message */
    1694           0 :     argList[0] = CSTRINGOID;
    1695             : 
    1696           0 :     ereport(ERROR,
    1697             :             (errcode(ERRCODE_UNDEFINED_FUNCTION),
    1698             :              errmsg("function %s does not exist",
    1699             :                     func_signature_string(procname, 1, NIL, argList))));
    1700             : 
    1701             :     return InvalidOid;          /* keep compiler quiet */
    1702             : }
    1703             : 
    1704             : static Oid
    1705           9 : findTypeOutputFunction(List *procname, Oid typeOid)
    1706             : {
    1707             :     Oid         argList[1];
    1708             :     Oid         procOid;
    1709             : 
    1710             :     /*
    1711             :      * Output functions can take a single argument of the type.
    1712             :      *
    1713             :      * For backwards compatibility we allow OPAQUE in place of the actual type
    1714             :      * name; if we see this, we issue a warning and fix up the pg_proc entry.
    1715             :      */
    1716           9 :     argList[0] = typeOid;
    1717             : 
    1718           9 :     procOid = LookupFuncName(procname, 1, argList, true);
    1719           9 :     if (OidIsValid(procOid))
    1720           7 :         return procOid;
    1721             : 
    1722             :     /* No luck, try it with OPAQUE */
    1723           2 :     argList[0] = OPAQUEOID;
    1724             : 
    1725           2 :     procOid = LookupFuncName(procname, 1, argList, true);
    1726             : 
    1727           2 :     if (OidIsValid(procOid))
    1728             :     {
    1729             :         /* Found, but must complain and fix the pg_proc entry */
    1730           1 :         ereport(WARNING,
    1731             :                 (errmsg("changing argument type of function %s from \"opaque\" to %s",
    1732             :                         NameListToString(procname), format_type_be(typeOid))));
    1733           1 :         SetFunctionArgType(procOid, 0, typeOid);
    1734             : 
    1735             :         /*
    1736             :          * Need CommandCounterIncrement since DefineType will likely try to
    1737             :          * alter the pg_proc tuple again.
    1738             :          */
    1739           1 :         CommandCounterIncrement();
    1740             : 
    1741           1 :         return procOid;
    1742             :     }
    1743             : 
    1744             :     /* Use type name, not OPAQUE, in the failure message. */
    1745           1 :     argList[0] = typeOid;
    1746             : 
    1747           1 :     ereport(ERROR,
    1748             :             (errcode(ERRCODE_UNDEFINED_FUNCTION),
    1749             :              errmsg("function %s does not exist",
    1750             :                     func_signature_string(procname, 1, NIL, argList))));
    1751             : 
    1752             :     return InvalidOid;          /* keep compiler quiet */
    1753             : }
    1754             : 
    1755             : static Oid
    1756           0 : findTypeReceiveFunction(List *procname, Oid typeOid)
    1757             : {
    1758             :     Oid         argList[3];
    1759             :     Oid         procOid;
    1760             : 
    1761             :     /*
    1762             :      * Receive functions can take a single argument of type INTERNAL, or three
    1763             :      * arguments (internal, typioparam OID, typmod).
    1764             :      */
    1765           0 :     argList[0] = INTERNALOID;
    1766             : 
    1767           0 :     procOid = LookupFuncName(procname, 1, argList, true);
    1768           0 :     if (OidIsValid(procOid))
    1769           0 :         return procOid;
    1770             : 
    1771           0 :     argList[1] = OIDOID;
    1772           0 :     argList[2] = INT4OID;
    1773             : 
    1774           0 :     procOid = LookupFuncName(procname, 3, argList, true);
    1775           0 :     if (OidIsValid(procOid))
    1776           0 :         return procOid;
    1777             : 
    1778           0 :     ereport(ERROR,
    1779             :             (errcode(ERRCODE_UNDEFINED_FUNCTION),
    1780             :              errmsg("function %s does not exist",
    1781             :                     func_signature_string(procname, 1, NIL, argList))));
    1782             : 
    1783             :     return InvalidOid;          /* keep compiler quiet */
    1784             : }
    1785             : 
    1786             : static Oid
    1787           0 : findTypeSendFunction(List *procname, Oid typeOid)
    1788             : {
    1789             :     Oid         argList[1];
    1790             :     Oid         procOid;
    1791             : 
    1792             :     /*
    1793             :      * Send functions can take a single argument of the type.
    1794             :      */
    1795           0 :     argList[0] = typeOid;
    1796             : 
    1797           0 :     procOid = LookupFuncName(procname, 1, argList, true);
    1798           0 :     if (OidIsValid(procOid))
    1799           0 :         return procOid;
    1800             : 
    1801           0 :     ereport(ERROR,
    1802             :             (errcode(ERRCODE_UNDEFINED_FUNCTION),
    1803             :              errmsg("function %s does not exist",
    1804             :                     func_signature_string(procname, 1, NIL, argList))));
    1805             : 
    1806             :     return InvalidOid;          /* keep compiler quiet */
    1807             : }
    1808             : 
    1809             : static Oid
    1810           1 : findTypeTypmodinFunction(List *procname)
    1811             : {
    1812             :     Oid         argList[1];
    1813             :     Oid         procOid;
    1814             : 
    1815             :     /*
    1816             :      * typmodin functions always take one cstring[] argument and return int4.
    1817             :      */
    1818           1 :     argList[0] = CSTRINGARRAYOID;
    1819             : 
    1820           1 :     procOid = LookupFuncName(procname, 1, argList, true);
    1821           1 :     if (!OidIsValid(procOid))
    1822           0 :         ereport(ERROR,
    1823             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    1824             :                  errmsg("function %s does not exist",
    1825             :                         func_signature_string(procname, 1, NIL, argList))));
    1826             : 
    1827           1 :     if (get_func_rettype(procOid) != INT4OID)
    1828           0 :         ereport(ERROR,
    1829             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1830             :                  errmsg("typmod_in function %s must return type %s",
    1831             :                         NameListToString(procname), "integer")));
    1832             : 
    1833           1 :     return procOid;
    1834             : }
    1835             : 
    1836             : static Oid
    1837           1 : findTypeTypmodoutFunction(List *procname)
    1838             : {
    1839             :     Oid         argList[1];
    1840             :     Oid         procOid;
    1841             : 
    1842             :     /*
    1843             :      * typmodout functions always take one int4 argument and return cstring.
    1844             :      */
    1845           1 :     argList[0] = INT4OID;
    1846             : 
    1847           1 :     procOid = LookupFuncName(procname, 1, argList, true);
    1848           1 :     if (!OidIsValid(procOid))
    1849           0 :         ereport(ERROR,
    1850             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    1851             :                  errmsg("function %s does not exist",
    1852             :                         func_signature_string(procname, 1, NIL, argList))));
    1853             : 
    1854           1 :     if (get_func_rettype(procOid) != CSTRINGOID)
    1855           0 :         ereport(ERROR,
    1856             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1857             :                  errmsg("typmod_out function %s must return type %s",
    1858             :                         NameListToString(procname), "cstring")));
    1859             : 
    1860           1 :     return procOid;
    1861             : }
    1862             : 
    1863             : static Oid
    1864           0 : findTypeAnalyzeFunction(List *procname, Oid typeOid)
    1865             : {
    1866             :     Oid         argList[1];
    1867             :     Oid         procOid;
    1868             : 
    1869             :     /*
    1870             :      * Analyze functions always take one INTERNAL argument and return bool.
    1871             :      */
    1872           0 :     argList[0] = INTERNALOID;
    1873             : 
    1874           0 :     procOid = LookupFuncName(procname, 1, argList, true);
    1875           0 :     if (!OidIsValid(procOid))
    1876           0 :         ereport(ERROR,
    1877             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    1878             :                  errmsg("function %s does not exist",
    1879             :                         func_signature_string(procname, 1, NIL, argList))));
    1880             : 
    1881           0 :     if (get_func_rettype(procOid) != BOOLOID)
    1882           0 :         ereport(ERROR,
    1883             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1884             :                  errmsg("type analyze function %s must return type %s",
    1885             :                         NameListToString(procname), "boolean")));
    1886             : 
    1887           0 :     return procOid;
    1888             : }
    1889             : 
    1890             : /*
    1891             :  * Find suitable support functions and opclasses for a range type.
    1892             :  */
    1893             : 
    1894             : /*
    1895             :  * Find named btree opclass for subtype, or default btree opclass if
    1896             :  * opcname is NIL.
    1897             :  */
    1898             : static Oid
    1899          10 : findRangeSubOpclass(List *opcname, Oid subtype)
    1900             : {
    1901             :     Oid         opcid;
    1902             :     Oid         opInputType;
    1903             : 
    1904          10 :     if (opcname != NIL)
    1905             :     {
    1906           0 :         opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
    1907             : 
    1908             :         /*
    1909             :          * Verify that the operator class accepts this datatype. Note we will
    1910             :          * accept binary compatibility.
    1911             :          */
    1912           0 :         opInputType = get_opclass_input_type(opcid);
    1913           0 :         if (!IsBinaryCoercible(subtype, opInputType))
    1914           0 :             ereport(ERROR,
    1915             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    1916             :                      errmsg("operator class \"%s\" does not accept data type %s",
    1917             :                             NameListToString(opcname),
    1918             :                             format_type_be(subtype))));
    1919             :     }
    1920             :     else
    1921             :     {
    1922          10 :         opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
    1923          10 :         if (!OidIsValid(opcid))
    1924             :         {
    1925             :             /* We spell the error message identically to GetIndexOpClass */
    1926           0 :             ereport(ERROR,
    1927             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    1928             :                      errmsg("data type %s has no default operator class for access method \"%s\"",
    1929             :                             format_type_be(subtype), "btree"),
    1930             :                      errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
    1931             :         }
    1932             :     }
    1933             : 
    1934          10 :     return opcid;
    1935             : }
    1936             : 
    1937             : static Oid
    1938           0 : findRangeCanonicalFunction(List *procname, Oid typeOid)
    1939             : {
    1940             :     Oid         argList[1];
    1941             :     Oid         procOid;
    1942             :     AclResult   aclresult;
    1943             : 
    1944             :     /*
    1945             :      * Range canonical functions must take and return the range type, and must
    1946             :      * be immutable.
    1947             :      */
    1948           0 :     argList[0] = typeOid;
    1949             : 
    1950           0 :     procOid = LookupFuncName(procname, 1, argList, true);
    1951             : 
    1952           0 :     if (!OidIsValid(procOid))
    1953           0 :         ereport(ERROR,
    1954             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    1955             :                  errmsg("function %s does not exist",
    1956             :                         func_signature_string(procname, 1, NIL, argList))));
    1957             : 
    1958           0 :     if (get_func_rettype(procOid) != typeOid)
    1959           0 :         ereport(ERROR,
    1960             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1961             :                  errmsg("range canonical function %s must return range type",
    1962             :                         func_signature_string(procname, 1, NIL, argList))));
    1963             : 
    1964           0 :     if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
    1965           0 :         ereport(ERROR,
    1966             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1967             :                  errmsg("range canonical function %s must be immutable",
    1968             :                         func_signature_string(procname, 1, NIL, argList))));
    1969             : 
    1970             :     /* Also, range type's creator must have permission to call function */
    1971           0 :     aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
    1972           0 :     if (aclresult != ACLCHECK_OK)
    1973           0 :         aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
    1974             : 
    1975           0 :     return procOid;
    1976             : }
    1977             : 
    1978             : static Oid
    1979           2 : findRangeSubtypeDiffFunction(List *procname, Oid subtype)
    1980             : {
    1981             :     Oid         argList[2];
    1982             :     Oid         procOid;
    1983             :     AclResult   aclresult;
    1984             : 
    1985             :     /*
    1986             :      * Range subtype diff functions must take two arguments of the subtype,
    1987             :      * must return float8, and must be immutable.
    1988             :      */
    1989           2 :     argList[0] = subtype;
    1990           2 :     argList[1] = subtype;
    1991             : 
    1992           2 :     procOid = LookupFuncName(procname, 2, argList, true);
    1993             : 
    1994           2 :     if (!OidIsValid(procOid))
    1995           1 :         ereport(ERROR,
    1996             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    1997             :                  errmsg("function %s does not exist",
    1998             :                         func_signature_string(procname, 2, NIL, argList))));
    1999             : 
    2000           1 :     if (get_func_rettype(procOid) != FLOAT8OID)
    2001           0 :         ereport(ERROR,
    2002             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2003             :                  errmsg("range subtype diff function %s must return type %s",
    2004             :                         func_signature_string(procname, 2, NIL, argList),
    2005             :                         "double precision")));
    2006             : 
    2007           1 :     if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
    2008           0 :         ereport(ERROR,
    2009             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2010             :                  errmsg("range subtype diff function %s must be immutable",
    2011             :                         func_signature_string(procname, 2, NIL, argList))));
    2012             : 
    2013             :     /* Also, range type's creator must have permission to call function */
    2014           1 :     aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
    2015           1 :     if (aclresult != ACLCHECK_OK)
    2016           0 :         aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(procOid));
    2017             : 
    2018           1 :     return procOid;
    2019             : }
    2020             : 
    2021             : /*
    2022             :  *  AssignTypeArrayOid
    2023             :  *
    2024             :  *  Pre-assign the type's array OID for use in pg_type.typarray
    2025             :  */
    2026             : Oid
    2027        2014 : AssignTypeArrayOid(void)
    2028             : {
    2029             :     Oid         type_array_oid;
    2030             : 
    2031             :     /* Use binary-upgrade override for pg_type.typarray? */
    2032        2014 :     if (IsBinaryUpgrade)
    2033             :     {
    2034           0 :         if (!OidIsValid(binary_upgrade_next_array_pg_type_oid))
    2035           0 :             ereport(ERROR,
    2036             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2037             :                      errmsg("pg_type array OID value not set when in binary upgrade mode")));
    2038             : 
    2039           0 :         type_array_oid = binary_upgrade_next_array_pg_type_oid;
    2040           0 :         binary_upgrade_next_array_pg_type_oid = InvalidOid;
    2041             :     }
    2042             :     else
    2043             :     {
    2044        2014 :         Relation    pg_type = heap_open(TypeRelationId, AccessShareLock);
    2045             : 
    2046        2014 :         type_array_oid = GetNewOid(pg_type);
    2047        2014 :         heap_close(pg_type, AccessShareLock);
    2048             :     }
    2049             : 
    2050        2014 :     return type_array_oid;
    2051             : }
    2052             : 
    2053             : 
    2054             : /*-------------------------------------------------------------------
    2055             :  * DefineCompositeType
    2056             :  *
    2057             :  * Create a Composite Type relation.
    2058             :  * `DefineRelation' does all the work, we just provide the correct
    2059             :  * arguments!
    2060             :  *
    2061             :  * If the relation already exists, then 'DefineRelation' will abort
    2062             :  * the xact...
    2063             :  *
    2064             :  * Return type is the new type's object address.
    2065             :  *-------------------------------------------------------------------
    2066             :  */
    2067             : ObjectAddress
    2068          51 : DefineCompositeType(RangeVar *typevar, List *coldeflist)
    2069             : {
    2070          51 :     CreateStmt *createStmt = makeNode(CreateStmt);
    2071             :     Oid         old_type_oid;
    2072             :     Oid         typeNamespace;
    2073             :     ObjectAddress address;
    2074             : 
    2075             :     /*
    2076             :      * now set the parameters for keys/inheritance etc. All of these are
    2077             :      * uninteresting for composite types...
    2078             :      */
    2079          51 :     createStmt->relation = typevar;
    2080          51 :     createStmt->tableElts = coldeflist;
    2081          51 :     createStmt->inhRelations = NIL;
    2082          51 :     createStmt->constraints = NIL;
    2083          51 :     createStmt->options = NIL;
    2084          51 :     createStmt->oncommit = ONCOMMIT_NOOP;
    2085          51 :     createStmt->tablespacename = NULL;
    2086          51 :     createStmt->if_not_exists = false;
    2087             : 
    2088             :     /*
    2089             :      * Check for collision with an existing type name. If there is one and
    2090             :      * it's an autogenerated array, we can rename it out of the way.  This
    2091             :      * check is here mainly to get a better error message about a "type"
    2092             :      * instead of below about a "relation".
    2093             :      */
    2094          51 :     typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
    2095             :                                                          NoLock, NULL);
    2096          51 :     RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
    2097          51 :     old_type_oid =
    2098          51 :         GetSysCacheOid2(TYPENAMENSP,
    2099             :                         CStringGetDatum(createStmt->relation->relname),
    2100             :                         ObjectIdGetDatum(typeNamespace));
    2101          51 :     if (OidIsValid(old_type_oid))
    2102             :     {
    2103           0 :         if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
    2104           0 :             ereport(ERROR,
    2105             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    2106             :                      errmsg("type \"%s\" already exists", createStmt->relation->relname)));
    2107             :     }
    2108             : 
    2109             :     /*
    2110             :      * Finally create the relation.  This also creates the type.
    2111             :      */
    2112          51 :     DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
    2113             :                    NULL);
    2114             : 
    2115          49 :     return address;
    2116             : }
    2117             : 
    2118             : /*
    2119             :  * AlterDomainDefault
    2120             :  *
    2121             :  * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
    2122             :  *
    2123             :  * Returns ObjectAddress of the modified domain.
    2124             :  */
    2125             : ObjectAddress
    2126           2 : AlterDomainDefault(List *names, Node *defaultRaw)
    2127             : {
    2128             :     TypeName   *typename;
    2129             :     Oid         domainoid;
    2130             :     HeapTuple   tup;
    2131             :     ParseState *pstate;
    2132             :     Relation    rel;
    2133             :     char       *defaultValue;
    2134           2 :     Node       *defaultExpr = NULL; /* NULL if no default specified */
    2135             :     Datum       new_record[Natts_pg_type];
    2136             :     bool        new_record_nulls[Natts_pg_type];
    2137             :     bool        new_record_repl[Natts_pg_type];
    2138             :     HeapTuple   newtuple;
    2139             :     Form_pg_type typTup;
    2140             :     ObjectAddress address;
    2141             : 
    2142             :     /* Make a TypeName so we can use standard type lookup machinery */
    2143           2 :     typename = makeTypeNameFromNameList(names);
    2144           2 :     domainoid = typenameTypeId(NULL, typename);
    2145             : 
    2146             :     /* Look up the domain in the type table */
    2147           2 :     rel = heap_open(TypeRelationId, RowExclusiveLock);
    2148             : 
    2149           2 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
    2150           2 :     if (!HeapTupleIsValid(tup))
    2151           0 :         elog(ERROR, "cache lookup failed for type %u", domainoid);
    2152           2 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    2153             : 
    2154             :     /* Check it's a domain and check user has permission for ALTER DOMAIN */
    2155           2 :     checkDomainOwner(tup);
    2156             : 
    2157             :     /* Setup new tuple */
    2158           2 :     MemSet(new_record, (Datum) 0, sizeof(new_record));
    2159           2 :     MemSet(new_record_nulls, false, sizeof(new_record_nulls));
    2160           2 :     MemSet(new_record_repl, false, sizeof(new_record_repl));
    2161             : 
    2162             :     /* Store the new default into the tuple */
    2163           2 :     if (defaultRaw)
    2164             :     {
    2165             :         /* Create a dummy ParseState for transformExpr */
    2166           1 :         pstate = make_parsestate(NULL);
    2167             : 
    2168             :         /*
    2169             :          * Cook the colDef->raw_expr into an expression. Note: Name is
    2170             :          * strictly for error message
    2171             :          */
    2172           1 :         defaultExpr = cookDefault(pstate, defaultRaw,
    2173             :                                   typTup->typbasetype,
    2174             :                                   typTup->typtypmod,
    2175           1 :                                   NameStr(typTup->typname));
    2176             : 
    2177             :         /*
    2178             :          * If the expression is just a NULL constant, we treat the command
    2179             :          * like ALTER ... DROP DEFAULT.  (But see note for same test in
    2180             :          * DefineDomain.)
    2181             :          */
    2182           2 :         if (defaultExpr == NULL ||
    2183           2 :             (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
    2184             :         {
    2185             :             /* Default is NULL, drop it */
    2186           0 :             new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
    2187           0 :             new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
    2188           0 :             new_record_nulls[Anum_pg_type_typdefault - 1] = true;
    2189           0 :             new_record_repl[Anum_pg_type_typdefault - 1] = true;
    2190             :         }
    2191             :         else
    2192             :         {
    2193             :             /*
    2194             :              * Expression must be stored as a nodeToString result, but we also
    2195             :              * require a valid textual representation (mainly to make life
    2196             :              * easier for pg_dump).
    2197             :              */
    2198           1 :             defaultValue = deparse_expression(defaultExpr,
    2199             :                                               NIL, false, false);
    2200             : 
    2201             :             /*
    2202             :              * Form an updated tuple with the new default and write it back.
    2203             :              */
    2204           1 :             new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
    2205             : 
    2206           1 :             new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
    2207           1 :             new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
    2208           1 :             new_record_repl[Anum_pg_type_typdefault - 1] = true;
    2209             :         }
    2210             :     }
    2211             :     else
    2212             :     {
    2213             :         /* ALTER ... DROP DEFAULT */
    2214           1 :         new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
    2215           1 :         new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
    2216           1 :         new_record_nulls[Anum_pg_type_typdefault - 1] = true;
    2217           1 :         new_record_repl[Anum_pg_type_typdefault - 1] = true;
    2218             :     }
    2219             : 
    2220           2 :     newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
    2221             :                                  new_record, new_record_nulls,
    2222             :                                  new_record_repl);
    2223             : 
    2224           2 :     CatalogTupleUpdate(rel, &tup->t_self, newtuple);
    2225             : 
    2226             :     /* Rebuild dependencies */
    2227           2 :     GenerateTypeDependencies(typTup->typnamespace,
    2228             :                              domainoid,
    2229             :                              InvalidOid,    /* typrelid is n/a */
    2230             :                              0, /* relation kind is n/a */
    2231             :                              typTup->typowner,
    2232             :                              typTup->typinput,
    2233             :                              typTup->typoutput,
    2234             :                              typTup->typreceive,
    2235             :                              typTup->typsend,
    2236             :                              typTup->typmodin,
    2237             :                              typTup->typmodout,
    2238             :                              typTup->typanalyze,
    2239             :                              InvalidOid,
    2240             :                              false, /* a domain isn't an implicit array */
    2241             :                              typTup->typbasetype,
    2242             :                              typTup->typcollation,
    2243             :                              defaultExpr,
    2244             :                              true); /* Rebuild is true */
    2245             : 
    2246           2 :     InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
    2247             : 
    2248           2 :     ObjectAddressSet(address, TypeRelationId, domainoid);
    2249             : 
    2250             :     /* Clean up */
    2251           2 :     heap_close(rel, NoLock);
    2252           2 :     heap_freetuple(newtuple);
    2253             : 
    2254           2 :     return address;
    2255             : }
    2256             : 
    2257             : /*
    2258             :  * AlterDomainNotNull
    2259             :  *
    2260             :  * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
    2261             :  *
    2262             :  * Returns ObjectAddress of the modified domain.
    2263             :  */
    2264             : ObjectAddress
    2265           6 : AlterDomainNotNull(List *names, bool notNull)
    2266             : {
    2267             :     TypeName   *typename;
    2268             :     Oid         domainoid;
    2269             :     Relation    typrel;
    2270             :     HeapTuple   tup;
    2271             :     Form_pg_type typTup;
    2272           6 :     ObjectAddress address = InvalidObjectAddress;
    2273             : 
    2274             :     /* Make a TypeName so we can use standard type lookup machinery */
    2275           6 :     typename = makeTypeNameFromNameList(names);
    2276           6 :     domainoid = typenameTypeId(NULL, typename);
    2277             : 
    2278             :     /* Look up the domain in the type table */
    2279           6 :     typrel = heap_open(TypeRelationId, RowExclusiveLock);
    2280             : 
    2281           6 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
    2282           6 :     if (!HeapTupleIsValid(tup))
    2283           0 :         elog(ERROR, "cache lookup failed for type %u", domainoid);
    2284           6 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    2285             : 
    2286             :     /* Check it's a domain and check user has permission for ALTER DOMAIN */
    2287           6 :     checkDomainOwner(tup);
    2288             : 
    2289             :     /* Is the domain already set to the desired constraint? */
    2290           6 :     if (typTup->typnotnull == notNull)
    2291             :     {
    2292           0 :         heap_close(typrel, RowExclusiveLock);
    2293           0 :         return address;
    2294             :     }
    2295             : 
    2296             :     /* Adding a NOT NULL constraint requires checking existing columns */
    2297           6 :     if (notNull)
    2298             :     {
    2299             :         List       *rels;
    2300             :         ListCell   *rt;
    2301             : 
    2302             :         /* Fetch relation list with attributes based on this domain */
    2303             :         /* ShareLock is sufficient to prevent concurrent data changes */
    2304             : 
    2305           4 :         rels = get_rels_with_domain(domainoid, ShareLock);
    2306             : 
    2307           5 :         foreach(rt, rels)
    2308             :         {
    2309           3 :             RelToCheck *rtc = (RelToCheck *) lfirst(rt);
    2310           3 :             Relation    testrel = rtc->rel;
    2311           3 :             TupleDesc   tupdesc = RelationGetDescr(testrel);
    2312             :             HeapScanDesc scan;
    2313             :             HeapTuple   tuple;
    2314             :             Snapshot    snapshot;
    2315             : 
    2316             :             /* Scan all tuples in this relation */
    2317           3 :             snapshot = RegisterSnapshot(GetLatestSnapshot());
    2318           3 :             scan = heap_beginscan(testrel, snapshot, 0, NULL);
    2319           7 :             while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
    2320             :             {
    2321             :                 int         i;
    2322             : 
    2323             :                 /* Test attributes that are of the domain */
    2324           6 :                 for (i = 0; i < rtc->natts; i++)
    2325             :                 {
    2326           5 :                     int         attnum = rtc->atts[i];
    2327           5 :                     Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
    2328             : 
    2329           5 :                     if (heap_attisnull(tuple, attnum))
    2330             :                     {
    2331             :                         /*
    2332             :                          * In principle the auxiliary information for this
    2333             :                          * error should be errdatatype(), but errtablecol()
    2334             :                          * seems considerably more useful in practice.  Since
    2335             :                          * this code only executes in an ALTER DOMAIN command,
    2336             :                          * the client should already know which domain is in
    2337             :                          * question.
    2338             :                          */
    2339           2 :                         ereport(ERROR,
    2340             :                                 (errcode(ERRCODE_NOT_NULL_VIOLATION),
    2341             :                                  errmsg("column \"%s\" of table \"%s\" contains null values",
    2342             :                                         NameStr(attr->attname),
    2343             :                                         RelationGetRelationName(testrel)),
    2344             :                                  errtablecol(testrel, attnum)));
    2345             :                     }
    2346             :                 }
    2347             :             }
    2348           1 :             heap_endscan(scan);
    2349           1 :             UnregisterSnapshot(snapshot);
    2350             : 
    2351             :             /* Close each rel after processing, but keep lock */
    2352           1 :             heap_close(testrel, NoLock);
    2353             :         }
    2354             :     }
    2355             : 
    2356             :     /*
    2357             :      * Okay to update pg_type row.  We can scribble on typTup because it's a
    2358             :      * copy.
    2359             :      */
    2360           4 :     typTup->typnotnull = notNull;
    2361             : 
    2362           4 :     CatalogTupleUpdate(typrel, &tup->t_self, tup);
    2363             : 
    2364           4 :     InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
    2365             : 
    2366           4 :     ObjectAddressSet(address, TypeRelationId, domainoid);
    2367             : 
    2368             :     /* Clean up */
    2369           4 :     heap_freetuple(tup);
    2370           4 :     heap_close(typrel, RowExclusiveLock);
    2371             : 
    2372           4 :     return address;
    2373             : }
    2374             : 
    2375             : /*
    2376             :  * AlterDomainDropConstraint
    2377             :  *
    2378             :  * Implements the ALTER DOMAIN DROP CONSTRAINT statement
    2379             :  */
    2380             : ObjectAddress
    2381           6 : AlterDomainDropConstraint(List *names, const char *constrName,
    2382             :                           DropBehavior behavior, bool missing_ok)
    2383             : {
    2384             :     TypeName   *typename;
    2385             :     Oid         domainoid;
    2386             :     HeapTuple   tup;
    2387             :     Relation    rel;
    2388             :     Relation    conrel;
    2389             :     SysScanDesc conscan;
    2390             :     ScanKeyData key[1];
    2391             :     HeapTuple   contup;
    2392           6 :     bool        found = false;
    2393           6 :     ObjectAddress address = InvalidObjectAddress;
    2394             : 
    2395             :     /* Make a TypeName so we can use standard type lookup machinery */
    2396           6 :     typename = makeTypeNameFromNameList(names);
    2397           6 :     domainoid = typenameTypeId(NULL, typename);
    2398             : 
    2399             :     /* Look up the domain in the type table */
    2400           6 :     rel = heap_open(TypeRelationId, RowExclusiveLock);
    2401             : 
    2402           6 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
    2403           6 :     if (!HeapTupleIsValid(tup))
    2404           0 :         elog(ERROR, "cache lookup failed for type %u", domainoid);
    2405             : 
    2406             :     /* Check it's a domain and check user has permission for ALTER DOMAIN */
    2407           6 :     checkDomainOwner(tup);
    2408             : 
    2409             :     /* Grab an appropriate lock on the pg_constraint relation */
    2410           6 :     conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
    2411             : 
    2412             :     /* Use the index to scan only constraints of the target relation */
    2413          12 :     ScanKeyInit(&key[0],
    2414             :                 Anum_pg_constraint_contypid,
    2415             :                 BTEqualStrategyNumber, F_OIDEQ,
    2416          12 :                 ObjectIdGetDatum(HeapTupleGetOid(tup)));
    2417             : 
    2418           6 :     conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
    2419             :                                  NULL, 1, key);
    2420             : 
    2421             :     /*
    2422             :      * Scan over the result set, removing any matching entries.
    2423             :      */
    2424          19 :     while ((contup = systable_getnext(conscan)) != NULL)
    2425             :     {
    2426           7 :         Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);
    2427             : 
    2428           7 :         if (strcmp(NameStr(con->conname), constrName) == 0)
    2429             :         {
    2430             :             ObjectAddress conobj;
    2431             : 
    2432           4 :             conobj.classId = ConstraintRelationId;
    2433           4 :             conobj.objectId = HeapTupleGetOid(contup);
    2434           4 :             conobj.objectSubId = 0;
    2435             : 
    2436           4 :             performDeletion(&conobj, behavior, 0);
    2437           4 :             found = true;
    2438             :         }
    2439             :     }
    2440             : 
    2441           6 :     ObjectAddressSet(address, TypeRelationId, domainoid);
    2442             : 
    2443             :     /* Clean up after the scan */
    2444           6 :     systable_endscan(conscan);
    2445           6 :     heap_close(conrel, RowExclusiveLock);
    2446             : 
    2447           6 :     heap_close(rel, NoLock);
    2448             : 
    2449           6 :     if (!found)
    2450             :     {
    2451           2 :         if (!missing_ok)
    2452           1 :             ereport(ERROR,
    2453             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    2454             :                      errmsg("constraint \"%s\" of domain \"%s\" does not exist",
    2455             :                             constrName, TypeNameToString(typename))));
    2456             :         else
    2457           1 :             ereport(NOTICE,
    2458             :                     (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
    2459             :                             constrName, TypeNameToString(typename))));
    2460             :     }
    2461             : 
    2462           5 :     return address;
    2463             : }
    2464             : 
    2465             : /*
    2466             :  * AlterDomainAddConstraint
    2467             :  *
    2468             :  * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
    2469             :  */
    2470             : ObjectAddress
    2471          16 : AlterDomainAddConstraint(List *names, Node *newConstraint,
    2472             :                          ObjectAddress *constrAddr)
    2473             : {
    2474             :     TypeName   *typename;
    2475             :     Oid         domainoid;
    2476             :     Relation    typrel;
    2477             :     HeapTuple   tup;
    2478             :     Form_pg_type typTup;
    2479             :     Constraint *constr;
    2480             :     char       *ccbin;
    2481             :     ObjectAddress address;
    2482             : 
    2483             :     /* Make a TypeName so we can use standard type lookup machinery */
    2484          16 :     typename = makeTypeNameFromNameList(names);
    2485          16 :     domainoid = typenameTypeId(NULL, typename);
    2486             : 
    2487             :     /* Look up the domain in the type table */
    2488          16 :     typrel = heap_open(TypeRelationId, RowExclusiveLock);
    2489             : 
    2490          16 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
    2491          16 :     if (!HeapTupleIsValid(tup))
    2492           0 :         elog(ERROR, "cache lookup failed for type %u", domainoid);
    2493          16 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    2494             : 
    2495             :     /* Check it's a domain and check user has permission for ALTER DOMAIN */
    2496          16 :     checkDomainOwner(tup);
    2497             : 
    2498          16 :     if (!IsA(newConstraint, Constraint))
    2499           0 :         elog(ERROR, "unrecognized node type: %d",
    2500             :              (int) nodeTag(newConstraint));
    2501             : 
    2502          16 :     constr = (Constraint *) newConstraint;
    2503             : 
    2504          16 :     switch (constr->contype)
    2505             :     {
    2506             :         case CONSTR_CHECK:
    2507             :             /* processed below */
    2508          16 :             break;
    2509             : 
    2510             :         case CONSTR_UNIQUE:
    2511           0 :             ereport(ERROR,
    2512             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    2513             :                      errmsg("unique constraints not possible for domains")));
    2514             :             break;
    2515             : 
    2516             :         case CONSTR_PRIMARY:
    2517           0 :             ereport(ERROR,
    2518             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    2519             :                      errmsg("primary key constraints not possible for domains")));
    2520             :             break;
    2521             : 
    2522             :         case CONSTR_EXCLUSION:
    2523           0 :             ereport(ERROR,
    2524             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    2525             :                      errmsg("exclusion constraints not possible for domains")));
    2526             :             break;
    2527             : 
    2528             :         case CONSTR_FOREIGN:
    2529           0 :             ereport(ERROR,
    2530             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    2531             :                      errmsg("foreign key constraints not possible for domains")));
    2532             :             break;
    2533             : 
    2534             :         case CONSTR_ATTR_DEFERRABLE:
    2535             :         case CONSTR_ATTR_NOT_DEFERRABLE:
    2536             :         case CONSTR_ATTR_DEFERRED:
    2537             :         case CONSTR_ATTR_IMMEDIATE:
    2538           0 :             ereport(ERROR,
    2539             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2540             :                      errmsg("specifying constraint deferrability not supported for domains")));
    2541             :             break;
    2542             : 
    2543             :         default:
    2544           0 :             elog(ERROR, "unrecognized constraint subtype: %d",
    2545             :                  (int) constr->contype);
    2546             :             break;
    2547             :     }
    2548             : 
    2549             :     /*
    2550             :      * Since all other constraint types throw errors, this must be a check
    2551             :      * constraint.  First, process the constraint expression and add an entry
    2552             :      * to pg_constraint.
    2553             :      */
    2554             : 
    2555          16 :     ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
    2556             :                                 typTup->typbasetype, typTup->typtypmod,
    2557          16 :                                 constr, NameStr(typTup->typname), constrAddr);
    2558             : 
    2559             :     /*
    2560             :      * If requested to validate the constraint, test all values stored in the
    2561             :      * attributes based on the domain the constraint is being added to.
    2562             :      */
    2563          16 :     if (!constr->skip_validation)
    2564          15 :         validateDomainConstraint(domainoid, ccbin);
    2565             : 
    2566           8 :     ObjectAddressSet(address, TypeRelationId, domainoid);
    2567             : 
    2568             :     /* Clean up */
    2569           8 :     heap_close(typrel, RowExclusiveLock);
    2570             : 
    2571           8 :     return address;
    2572             : }
    2573             : 
    2574             : /*
    2575             :  * AlterDomainValidateConstraint
    2576             :  *
    2577             :  * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
    2578             :  */
    2579             : ObjectAddress
    2580           2 : AlterDomainValidateConstraint(List *names, char *constrName)
    2581             : {
    2582             :     TypeName   *typename;
    2583             :     Oid         domainoid;
    2584             :     Relation    typrel;
    2585             :     Relation    conrel;
    2586             :     HeapTuple   tup;
    2587           2 :     Form_pg_constraint con = NULL;
    2588             :     Form_pg_constraint copy_con;
    2589             :     char       *conbin;
    2590             :     SysScanDesc scan;
    2591             :     Datum       val;
    2592           2 :     bool        found = false;
    2593             :     bool        isnull;
    2594             :     HeapTuple   tuple;
    2595             :     HeapTuple   copyTuple;
    2596             :     ScanKeyData key;
    2597             :     ObjectAddress address;
    2598             : 
    2599             :     /* Make a TypeName so we can use standard type lookup machinery */
    2600           2 :     typename = makeTypeNameFromNameList(names);
    2601           2 :     domainoid = typenameTypeId(NULL, typename);
    2602             : 
    2603             :     /* Look up the domain in the type table */
    2604           2 :     typrel = heap_open(TypeRelationId, AccessShareLock);
    2605             : 
    2606           2 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
    2607           2 :     if (!HeapTupleIsValid(tup))
    2608           0 :         elog(ERROR, "cache lookup failed for type %u", domainoid);
    2609             : 
    2610             :     /* Check it's a domain and check user has permission for ALTER DOMAIN */
    2611           2 :     checkDomainOwner(tup);
    2612             : 
    2613             :     /*
    2614             :      * Find and check the target constraint
    2615             :      */
    2616           2 :     conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
    2617           2 :     ScanKeyInit(&key,
    2618             :                 Anum_pg_constraint_contypid,
    2619             :                 BTEqualStrategyNumber, F_OIDEQ,
    2620             :                 ObjectIdGetDatum(domainoid));
    2621           2 :     scan = systable_beginscan(conrel, ConstraintTypidIndexId,
    2622             :                               true, NULL, 1, &key);
    2623             : 
    2624           2 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
    2625             :     {
    2626           2 :         con = (Form_pg_constraint) GETSTRUCT(tuple);
    2627           2 :         if (strcmp(NameStr(con->conname), constrName) == 0)
    2628             :         {
    2629           2 :             found = true;
    2630           2 :             break;
    2631             :         }
    2632             :     }
    2633             : 
    2634           2 :     if (!found)
    2635           0 :         ereport(ERROR,
    2636             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2637             :                  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
    2638             :                         constrName, TypeNameToString(typename))));
    2639             : 
    2640           2 :     if (con->contype != CONSTRAINT_CHECK)
    2641           0 :         ereport(ERROR,
    2642             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2643             :                  errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
    2644             :                         constrName, TypeNameToString(typename))));
    2645             : 
    2646           2 :     val = SysCacheGetAttr(CONSTROID, tuple,
    2647             :                           Anum_pg_constraint_conbin,
    2648             :                           &isnull);
    2649           2 :     if (isnull)
    2650           0 :         elog(ERROR, "null conbin for constraint %u",
    2651             :              HeapTupleGetOid(tuple));
    2652           2 :     conbin = TextDatumGetCString(val);
    2653             : 
    2654           2 :     validateDomainConstraint(domainoid, conbin);
    2655             : 
    2656             :     /*
    2657             :      * Now update the catalog, while we have the door open.
    2658             :      */
    2659           1 :     copyTuple = heap_copytuple(tuple);
    2660           1 :     copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
    2661           1 :     copy_con->convalidated = true;
    2662           1 :     CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
    2663             : 
    2664           1 :     InvokeObjectPostAlterHook(ConstraintRelationId,
    2665             :                               HeapTupleGetOid(copyTuple), 0);
    2666             : 
    2667           1 :     ObjectAddressSet(address, TypeRelationId, domainoid);
    2668             : 
    2669           1 :     heap_freetuple(copyTuple);
    2670             : 
    2671           1 :     systable_endscan(scan);
    2672             : 
    2673           1 :     heap_close(typrel, AccessShareLock);
    2674           1 :     heap_close(conrel, RowExclusiveLock);
    2675             : 
    2676           1 :     ReleaseSysCache(tup);
    2677             : 
    2678           1 :     return address;
    2679             : }
    2680             : 
    2681             : static void
    2682          17 : validateDomainConstraint(Oid domainoid, char *ccbin)
    2683             : {
    2684          17 :     Expr       *expr = (Expr *) stringToNode(ccbin);
    2685             :     List       *rels;
    2686             :     ListCell   *rt;
    2687             :     EState     *estate;
    2688             :     ExprContext *econtext;
    2689             :     ExprState  *exprstate;
    2690             : 
    2691             :     /* Need an EState to run ExecEvalExpr */
    2692          17 :     estate = CreateExecutorState();
    2693          17 :     econtext = GetPerTupleExprContext(estate);
    2694             : 
    2695             :     /* build execution state for expr */
    2696          17 :     exprstate = ExecPrepareExpr(expr, estate);
    2697             : 
    2698             :     /* Fetch relation list with attributes based on this domain */
    2699             :     /* ShareLock is sufficient to prevent concurrent data changes */
    2700             : 
    2701          17 :     rels = get_rels_with_domain(domainoid, ShareLock);
    2702             : 
    2703          18 :     foreach(rt, rels)
    2704             :     {
    2705          10 :         RelToCheck *rtc = (RelToCheck *) lfirst(rt);
    2706          10 :         Relation    testrel = rtc->rel;
    2707          10 :         TupleDesc   tupdesc = RelationGetDescr(testrel);
    2708             :         HeapScanDesc scan;
    2709             :         HeapTuple   tuple;
    2710             :         Snapshot    snapshot;
    2711             : 
    2712             :         /* Scan all tuples in this relation */
    2713          10 :         snapshot = RegisterSnapshot(GetLatestSnapshot());
    2714          10 :         scan = heap_beginscan(testrel, snapshot, 0, NULL);
    2715          32 :         while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
    2716             :         {
    2717             :             int         i;
    2718             : 
    2719             :             /* Test attributes that are of the domain */
    2720          29 :             for (i = 0; i < rtc->natts; i++)
    2721             :             {
    2722          17 :                 int         attnum = rtc->atts[i];
    2723             :                 Datum       d;
    2724             :                 bool        isNull;
    2725             :                 Datum       conResult;
    2726          17 :                 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
    2727             : 
    2728          17 :                 d = heap_getattr(tuple, attnum, tupdesc, &isNull);
    2729             : 
    2730          17 :                 econtext->domainValue_datum = d;
    2731          17 :                 econtext->domainValue_isNull = isNull;
    2732             : 
    2733          17 :                 conResult = ExecEvalExprSwitchContext(exprstate,
    2734             :                                                       econtext,
    2735             :                                                       &isNull);
    2736             : 
    2737          17 :                 if (!isNull && !DatumGetBool(conResult))
    2738             :                 {
    2739             :                     /*
    2740             :                      * In principle the auxiliary information for this error
    2741             :                      * should be errdomainconstraint(), but errtablecol()
    2742             :                      * seems considerably more useful in practice.  Since this
    2743             :                      * code only executes in an ALTER DOMAIN command, the
    2744             :                      * client should already know which domain is in question,
    2745             :                      * and which constraint too.
    2746             :                      */
    2747           5 :                     ereport(ERROR,
    2748             :                             (errcode(ERRCODE_CHECK_VIOLATION),
    2749             :                              errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
    2750             :                                     NameStr(attr->attname),
    2751             :                                     RelationGetRelationName(testrel)),
    2752             :                              errtablecol(testrel, attnum)));
    2753             :                 }
    2754             :             }
    2755             : 
    2756          12 :             ResetExprContext(econtext);
    2757             :         }
    2758           5 :         heap_endscan(scan);
    2759           5 :         UnregisterSnapshot(snapshot);
    2760             : 
    2761             :         /* Hold relation lock till commit (XXX bad for concurrency) */
    2762           5 :         heap_close(testrel, NoLock);
    2763             :     }
    2764             : 
    2765           8 :     FreeExecutorState(estate);
    2766           8 : }
    2767             : 
    2768             : /*
    2769             :  * get_rels_with_domain
    2770             :  *
    2771             :  * Fetch all relations / attributes which are using the domain
    2772             :  *
    2773             :  * The result is a list of RelToCheck structs, one for each distinct
    2774             :  * relation, each containing one or more attribute numbers that are of
    2775             :  * the domain type.  We have opened each rel and acquired the specified lock
    2776             :  * type on it.
    2777             :  *
    2778             :  * We support nested domains by including attributes that are of derived
    2779             :  * domain types.  Current callers do not need to distinguish between attributes
    2780             :  * that are of exactly the given domain and those that are of derived domains.
    2781             :  *
    2782             :  * XXX this is completely broken because there is no way to lock the domain
    2783             :  * to prevent columns from being added or dropped while our command runs.
    2784             :  * We can partially protect against column drops by locking relations as we
    2785             :  * come across them, but there is still a race condition (the window between
    2786             :  * seeing a pg_depend entry and acquiring lock on the relation it references).
    2787             :  * Also, holding locks on all these relations simultaneously creates a non-
    2788             :  * trivial risk of deadlock.  We can minimize but not eliminate the deadlock
    2789             :  * risk by using the weakest suitable lock (ShareLock for most callers).
    2790             :  *
    2791             :  * XXX the API for this is not sufficient to support checking domain values
    2792             :  * that are inside container types, such as composite types, arrays, or
    2793             :  * ranges.  Currently we just error out if a container type containing the
    2794             :  * target domain is stored anywhere.
    2795             :  *
    2796             :  * Generally used for retrieving a list of tests when adding
    2797             :  * new constraints to a domain.
    2798             :  */
    2799             : static List *
    2800          23 : get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
    2801             : {
    2802          23 :     List       *result = NIL;
    2803          23 :     char       *domainTypeName = format_type_be(domainOid);
    2804             :     Relation    depRel;
    2805             :     ScanKeyData key[2];
    2806             :     SysScanDesc depScan;
    2807             :     HeapTuple   depTup;
    2808             : 
    2809          23 :     Assert(lockmode != NoLock);
    2810             : 
    2811             :     /* since this function recurses, it could be driven to stack overflow */
    2812          23 :     check_stack_depth();
    2813             : 
    2814             :     /*
    2815             :      * We scan pg_depend to find those things that depend on the domain. (We
    2816             :      * assume we can ignore refobjsubid for a domain.)
    2817             :      */
    2818          23 :     depRel = heap_open(DependRelationId, AccessShareLock);
    2819             : 
    2820          23 :     ScanKeyInit(&key[0],
    2821             :                 Anum_pg_depend_refclassid,
    2822             :                 BTEqualStrategyNumber, F_OIDEQ,
    2823             :                 ObjectIdGetDatum(TypeRelationId));
    2824          23 :     ScanKeyInit(&key[1],
    2825             :                 Anum_pg_depend_refobjid,
    2826             :                 BTEqualStrategyNumber, F_OIDEQ,
    2827             :                 ObjectIdGetDatum(domainOid));
    2828             : 
    2829          23 :     depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
    2830             :                                  NULL, 2, key);
    2831             : 
    2832          84 :     while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
    2833             :     {
    2834          42 :         Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
    2835          42 :         RelToCheck *rtc = NULL;
    2836             :         ListCell   *rellist;
    2837             :         Form_pg_attribute pg_att;
    2838             :         int         ptr;
    2839             : 
    2840             :         /* Check for directly dependent types */
    2841          42 :         if (pg_depend->classid == TypeRelationId)
    2842             :         {
    2843           3 :             if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
    2844             :             {
    2845             :                 /*
    2846             :                  * This is a sub-domain, so recursively add dependent columns
    2847             :                  * to the output list.  This is a bit inefficient since we may
    2848             :                  * fail to combine RelToCheck entries when attributes of the
    2849             :                  * same rel have different derived domain types, but it's
    2850             :                  * probably not worth improving.
    2851             :                  */
    2852           2 :                 result = list_concat(result,
    2853             :                                      get_rels_with_domain(pg_depend->objid,
    2854             :                                                           lockmode));
    2855             :             }
    2856             :             else
    2857             :             {
    2858             :                 /*
    2859             :                  * Otherwise, it is some container type using the domain, so
    2860             :                  * fail if there are any columns of this type.
    2861             :                  */
    2862           1 :                 find_composite_type_dependencies(pg_depend->objid,
    2863             :                                                  NULL,
    2864             :                                                  domainTypeName);
    2865             :             }
    2866           2 :             continue;
    2867             :         }
    2868             : 
    2869             :         /* Else, ignore dependees that aren't user columns of relations */
    2870             :         /* (we assume system columns are never of domain types) */
    2871          63 :         if (pg_depend->classid != RelationRelationId ||
    2872          24 :             pg_depend->objsubid <= 0)
    2873          15 :             continue;
    2874             : 
    2875             :         /* See if we already have an entry for this relation */
    2876          26 :         foreach(rellist, result)
    2877             :         {
    2878           5 :             RelToCheck *rt = (RelToCheck *) lfirst(rellist);
    2879             : 
    2880           5 :             if (RelationGetRelid(rt->rel) == pg_depend->objid)
    2881             :             {
    2882           3 :                 rtc = rt;
    2883           3 :                 break;
    2884             :             }
    2885             :         }
    2886             : 
    2887          24 :         if (rtc == NULL)
    2888             :         {
    2889             :             /* First attribute found for this relation */
    2890             :             Relation    rel;
    2891             : 
    2892             :             /* Acquire requested lock on relation */
    2893          21 :             rel = relation_open(pg_depend->objid, lockmode);
    2894             : 
    2895             :             /*
    2896             :              * Check to see if rowtype is stored anyplace as a composite-type
    2897             :              * column; if so we have to fail, for now anyway.
    2898             :              */
    2899          21 :             if (OidIsValid(rel->rd_rel->reltype))
    2900          21 :                 find_composite_type_dependencies(rel->rd_rel->reltype,
    2901             :                                                  NULL,
    2902             :                                                  domainTypeName);
    2903             : 
    2904             :             /*
    2905             :              * Otherwise, we can ignore relations except those with both
    2906             :              * storage and user-chosen column types.
    2907             :              *
    2908             :              * XXX If an index-only scan could satisfy "col::some_domain" from
    2909             :              * a suitable expression index, this should also check expression
    2910             :              * index columns.
    2911             :              */
    2912          23 :             if (rel->rd_rel->relkind != RELKIND_RELATION &&
    2913           5 :                 rel->rd_rel->relkind != RELKIND_MATVIEW)
    2914             :             {
    2915           5 :                 relation_close(rel, lockmode);
    2916           5 :                 continue;
    2917             :             }
    2918             : 
    2919             :             /* Build the RelToCheck entry with enough space for all atts */
    2920          13 :             rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
    2921          13 :             rtc->rel = rel;
    2922          13 :             rtc->natts = 0;
    2923          13 :             rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
    2924          13 :             result = lcons(rtc, result);
    2925             :         }
    2926             : 
    2927             :         /*
    2928             :          * Confirm column has not been dropped, and is of the expected type.
    2929             :          * This defends against an ALTER DROP COLUMN occurring just before we
    2930             :          * acquired lock ... but if the whole table were dropped, we'd still
    2931             :          * have a problem.
    2932             :          */
    2933          16 :         if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
    2934           0 :             continue;
    2935          16 :         pg_att = TupleDescAttr(rtc->rel->rd_att, pg_depend->objsubid - 1);
    2936          16 :         if (pg_att->attisdropped || pg_att->atttypid != domainOid)
    2937           0 :             continue;
    2938             : 
    2939             :         /*
    2940             :          * Okay, add column to result.  We store the columns in column-number
    2941             :          * order; this is just a hack to improve predictability of regression
    2942             :          * test output ...
    2943             :          */
    2944          16 :         Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
    2945             : 
    2946          16 :         ptr = rtc->natts++;
    2947          35 :         while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
    2948             :         {
    2949           3 :             rtc->atts[ptr] = rtc->atts[ptr - 1];
    2950           3 :             ptr--;
    2951             :         }
    2952          16 :         rtc->atts[ptr] = pg_depend->objsubid;
    2953             :     }
    2954             : 
    2955          19 :     systable_endscan(depScan);
    2956             : 
    2957          19 :     relation_close(depRel, AccessShareLock);
    2958             : 
    2959          19 :     return result;
    2960             : }
    2961             : 
    2962             : /*
    2963             :  * checkDomainOwner
    2964             :  *
    2965             :  * Check that the type is actually a domain and that the current user
    2966             :  * has permission to do ALTER DOMAIN on it.  Throw an error if not.
    2967             :  */
    2968             : void
    2969          33 : checkDomainOwner(HeapTuple tup)
    2970             : {
    2971          33 :     Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
    2972             : 
    2973             :     /* Check that this is actually a domain */
    2974          33 :     if (typTup->typtype != TYPTYPE_DOMAIN)
    2975           0 :         ereport(ERROR,
    2976             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2977             :                  errmsg("%s is not a domain",
    2978             :                         format_type_be(HeapTupleGetOid(tup)))));
    2979             : 
    2980             :     /* Permission check: must own type */
    2981          33 :     if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
    2982           0 :         aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
    2983          33 : }
    2984             : 
    2985             : /*
    2986             :  * domainAddConstraint - code shared between CREATE and ALTER DOMAIN
    2987             :  */
    2988             : static char *
    2989          40 : domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
    2990             :                     int typMod, Constraint *constr,
    2991             :                     char *domainName, ObjectAddress *constrAddr)
    2992             : {
    2993             :     Node       *expr;
    2994             :     char       *ccsrc;
    2995             :     char       *ccbin;
    2996             :     ParseState *pstate;
    2997             :     CoerceToDomainValue *domVal;
    2998             :     Oid         ccoid;
    2999             : 
    3000             :     /*
    3001             :      * Assign or validate constraint name
    3002             :      */
    3003          40 :     if (constr->conname)
    3004             :     {
    3005          21 :         if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
    3006             :                                  domainOid,
    3007             :                                  domainNamespace,
    3008          21 :                                  constr->conname))
    3009           0 :             ereport(ERROR,
    3010             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    3011             :                      errmsg("constraint \"%s\" for domain \"%s\" already exists",
    3012             :                             constr->conname, domainName)));
    3013             :     }
    3014             :     else
    3015          19 :         constr->conname = ChooseConstraintName(domainName,
    3016             :                                                NULL,
    3017             :                                                "check",
    3018             :                                                domainNamespace,
    3019             :                                                NIL);
    3020             : 
    3021             :     /*
    3022             :      * Convert the A_EXPR in raw_expr into an EXPR
    3023             :      */
    3024          40 :     pstate = make_parsestate(NULL);
    3025             : 
    3026             :     /*
    3027             :      * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
    3028             :      * the expression.  Note that it will appear to have the type of the base
    3029             :      * type, not the domain.  This seems correct since within the check
    3030             :      * expression, we should not assume the input value can be considered a
    3031             :      * member of the domain.
    3032             :      */
    3033          40 :     domVal = makeNode(CoerceToDomainValue);
    3034          40 :     domVal->typeId = baseTypeOid;
    3035          40 :     domVal->typeMod = typMod;
    3036          40 :     domVal->collation = get_typcollation(baseTypeOid);
    3037          40 :     domVal->location = -1;       /* will be set when/if used */
    3038             : 
    3039          40 :     pstate->p_pre_columnref_hook = replace_domain_constraint_value;
    3040          40 :     pstate->p_ref_hook_state = (void *) domVal;
    3041             : 
    3042          40 :     expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
    3043             : 
    3044             :     /*
    3045             :      * Make sure it yields a boolean result.
    3046             :      */
    3047          40 :     expr = coerce_to_boolean(pstate, expr, "CHECK");
    3048             : 
    3049             :     /*
    3050             :      * Fix up collation information.
    3051             :      */
    3052          40 :     assign_expr_collations(pstate, expr);
    3053             : 
    3054             :     /*
    3055             :      * Domains don't allow variables (this is probably dead code now that
    3056             :      * add_missing_from is history, but let's be sure).
    3057             :      */
    3058          80 :     if (list_length(pstate->p_rtable) != 0 ||
    3059          40 :         contain_var_clause(expr))
    3060           0 :         ereport(ERROR,
    3061             :                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
    3062             :                  errmsg("cannot use table references in domain check constraint")));
    3063             : 
    3064             :     /*
    3065             :      * Convert to string form for storage.
    3066             :      */
    3067          40 :     ccbin = nodeToString(expr);
    3068             : 
    3069             :     /*
    3070             :      * Deparse it to produce text for consrc.
    3071             :      */
    3072          40 :     ccsrc = deparse_expression(expr,
    3073             :                                NIL, false, false);
    3074             : 
    3075             :     /*
    3076             :      * Store the constraint in pg_constraint
    3077             :      */
    3078          40 :     ccoid =
    3079          40 :         CreateConstraintEntry(constr->conname,   /* Constraint Name */
    3080             :                               domainNamespace,  /* namespace */
    3081             :                               CONSTRAINT_CHECK, /* Constraint Type */
    3082             :                               false,    /* Is Deferrable */
    3083             :                               false,    /* Is Deferred */
    3084          40 :                               !constr->skip_validation, /* Is Validated */
    3085             :                               InvalidOid,   /* not a relation constraint */
    3086             :                               NULL,
    3087             :                               0,
    3088             :                               domainOid,    /* domain constraint */
    3089             :                               InvalidOid,   /* no associated index */
    3090             :                               InvalidOid,   /* Foreign key fields */
    3091             :                               NULL,
    3092             :                               NULL,
    3093             :                               NULL,
    3094             :                               NULL,
    3095             :                               0,
    3096             :                               ' ',
    3097             :                               ' ',
    3098             :                               ' ',
    3099             :                               NULL, /* not an exclusion constraint */
    3100             :                               expr, /* Tree form of check constraint */
    3101             :                               ccbin,    /* Binary form of check constraint */
    3102             :                               ccsrc,    /* Source form of check constraint */
    3103             :                               true, /* is local */
    3104             :                               0,    /* inhcount */
    3105             :                               false,    /* connoinherit */
    3106             :                               false);   /* is_internal */
    3107          40 :     if (constrAddr)
    3108          16 :         ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
    3109             : 
    3110             :     /*
    3111             :      * Return the compiled constraint expression so the calling routine can
    3112             :      * perform any additional required tests.
    3113             :      */
    3114          40 :     return ccbin;
    3115             : }
    3116             : 
    3117             : /* Parser pre_columnref_hook for domain CHECK constraint parsing */
    3118             : static Node *
    3119          46 : replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
    3120             : {
    3121             :     /*
    3122             :      * Check for a reference to "value", and if that's what it is, replace
    3123             :      * with a CoerceToDomainValue as prepared for us by domainAddConstraint.
    3124             :      * (We handle VALUE as a name, not a keyword, to avoid breaking a lot of
    3125             :      * applications that have used VALUE as a column name in the past.)
    3126             :      */
    3127          46 :     if (list_length(cref->fields) == 1)
    3128             :     {
    3129          46 :         Node       *field1 = (Node *) linitial(cref->fields);
    3130             :         char       *colname;
    3131             : 
    3132          46 :         Assert(IsA(field1, String));
    3133          46 :         colname = strVal(field1);
    3134          46 :         if (strcmp(colname, "value") == 0)
    3135             :         {
    3136          46 :             CoerceToDomainValue *domVal = copyObject(pstate->p_ref_hook_state);
    3137             : 
    3138             :             /* Propagate location knowledge, if any */
    3139          46 :             domVal->location = cref->location;
    3140          46 :             return (Node *) domVal;
    3141             :         }
    3142             :     }
    3143           0 :     return NULL;
    3144             : }
    3145             : 
    3146             : 
    3147             : /*
    3148             :  * Execute ALTER TYPE RENAME
    3149             :  */
    3150             : ObjectAddress
    3151           3 : RenameType(RenameStmt *stmt)
    3152             : {
    3153           3 :     List       *names = castNode(List, stmt->object);
    3154           3 :     const char *newTypeName = stmt->newname;
    3155             :     TypeName   *typename;
    3156             :     Oid         typeOid;
    3157             :     Relation    rel;
    3158             :     HeapTuple   tup;
    3159             :     Form_pg_type typTup;
    3160             :     ObjectAddress address;
    3161             : 
    3162             :     /* Make a TypeName so we can use standard type lookup machinery */
    3163           3 :     typename = makeTypeNameFromNameList(names);
    3164           3 :     typeOid = typenameTypeId(NULL, typename);
    3165             : 
    3166             :     /* Look up the type in the type table */
    3167           3 :     rel = heap_open(TypeRelationId, RowExclusiveLock);
    3168             : 
    3169           3 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
    3170           3 :     if (!HeapTupleIsValid(tup))
    3171           0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
    3172           3 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    3173             : 
    3174             :     /* check permissions on type */
    3175           3 :     if (!pg_type_ownercheck(typeOid, GetUserId()))
    3176           0 :         aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
    3177             : 
    3178             :     /* ALTER DOMAIN used on a non-domain? */
    3179           3 :     if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
    3180           0 :         ereport(ERROR,
    3181             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3182             :                  errmsg("%s is not a domain",
    3183             :                         format_type_be(typeOid))));
    3184             : 
    3185             :     /*
    3186             :      * If it's a composite type, we need to check that it really is a
    3187             :      * free-standing composite type, and not a table's rowtype. We want people
    3188             :      * to use ALTER TABLE not ALTER TYPE for that case.
    3189             :      */
    3190           3 :     if (typTup->typtype == TYPTYPE_COMPOSITE &&
    3191           0 :         get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
    3192           0 :         ereport(ERROR,
    3193             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3194             :                  errmsg("%s is a table's row type",
    3195             :                         format_type_be(typeOid)),
    3196             :                  errhint("Use ALTER TABLE instead.")));
    3197             : 
    3198             :     /* don't allow direct alteration of array types, either */
    3199           3 :     if (OidIsValid(typTup->typelem) &&
    3200           0 :         get_array_type(typTup->typelem) == typeOid)
    3201           0 :         ereport(ERROR,
    3202             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3203             :                  errmsg("cannot alter array type %s",
    3204             :                         format_type_be(typeOid)),
    3205             :                  errhint("You can alter type %s, which will alter the array type as well.",
    3206             :                          format_type_be(typTup->typelem))));
    3207             : 
    3208             :     /*
    3209             :      * If type is composite we need to rename associated pg_class entry too.
    3210             :      * RenameRelationInternal will call RenameTypeInternal automatically.
    3211             :      */
    3212           3 :     if (typTup->typtype == TYPTYPE_COMPOSITE)
    3213           0 :         RenameRelationInternal(typTup->typrelid, newTypeName, false);
    3214             :     else
    3215           3 :         RenameTypeInternal(typeOid, newTypeName,
    3216             :                            typTup->typnamespace);
    3217             : 
    3218           3 :     ObjectAddressSet(address, TypeRelationId, typeOid);
    3219             :     /* Clean up */
    3220           3 :     heap_close(rel, RowExclusiveLock);
    3221             : 
    3222           3 :     return address;
    3223             : }
    3224             : 
    3225             : /*
    3226             :  * Change the owner of a type.
    3227             :  */
    3228             : ObjectAddress
    3229           0 : AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
    3230             : {
    3231             :     TypeName   *typename;
    3232             :     Oid         typeOid;
    3233             :     Relation    rel;
    3234             :     HeapTuple   tup;
    3235             :     HeapTuple   newtup;
    3236             :     Form_pg_type typTup;
    3237             :     AclResult   aclresult;
    3238             :     ObjectAddress address;
    3239             : 
    3240           0 :     rel = heap_open(TypeRelationId, RowExclusiveLock);
    3241             : 
    3242             :     /* Make a TypeName so we can use standard type lookup machinery */
    3243           0 :     typename = makeTypeNameFromNameList(names);
    3244             : 
    3245             :     /* Use LookupTypeName here so that shell types can be processed */
    3246           0 :     tup = LookupTypeName(NULL, typename, NULL, false);
    3247           0 :     if (tup == NULL)
    3248           0 :         ereport(ERROR,
    3249             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3250             :                  errmsg("type \"%s\" does not exist",
    3251             :                         TypeNameToString(typename))));
    3252           0 :     typeOid = typeTypeId(tup);
    3253             : 
    3254             :     /* Copy the syscache entry so we can scribble on it below */
    3255           0 :     newtup = heap_copytuple(tup);
    3256           0 :     ReleaseSysCache(tup);
    3257           0 :     tup = newtup;
    3258           0 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    3259             : 
    3260             :     /* Don't allow ALTER DOMAIN on a type */
    3261           0 :     if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
    3262           0 :         ereport(ERROR,
    3263             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3264             :                  errmsg("%s is not a domain",
    3265             :                         format_type_be(typeOid))));
    3266             : 
    3267             :     /*
    3268             :      * If it's a composite type, we need to check that it really is a
    3269             :      * free-standing composite type, and not a table's rowtype. We want people
    3270             :      * to use ALTER TABLE not ALTER TYPE for that case.
    3271             :      */
    3272           0 :     if (typTup->typtype == TYPTYPE_COMPOSITE &&
    3273           0 :         get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
    3274           0 :         ereport(ERROR,
    3275             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3276             :                  errmsg("%s is a table's row type",
    3277             :                         format_type_be(typeOid)),
    3278             :                  errhint("Use ALTER TABLE instead.")));
    3279             : 
    3280             :     /* don't allow direct alteration of array types, either */
    3281           0 :     if (OidIsValid(typTup->typelem) &&
    3282           0 :         get_array_type(typTup->typelem) == typeOid)
    3283           0 :         ereport(ERROR,
    3284             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3285             :                  errmsg("cannot alter array type %s",
    3286             :                         format_type_be(typeOid)),
    3287             :                  errhint("You can alter type %s, which will alter the array type as well.",
    3288             :                          format_type_be(typTup->typelem))));
    3289             : 
    3290             :     /*
    3291             :      * If the new owner is the same as the existing owner, consider the
    3292             :      * command to have succeeded.  This is for dump restoration purposes.
    3293             :      */
    3294           0 :     if (typTup->typowner != newOwnerId)
    3295             :     {
    3296             :         /* Superusers can always do it */
    3297           0 :         if (!superuser())
    3298             :         {
    3299             :             /* Otherwise, must be owner of the existing object */
    3300           0 :             if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
    3301           0 :                 aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup));
    3302             : 
    3303             :             /* Must be able to become new owner */
    3304           0 :             check_is_member_of_role(GetUserId(), newOwnerId);
    3305             : 
    3306             :             /* New owner must have CREATE privilege on namespace */
    3307           0 :             aclresult = pg_namespace_aclcheck(typTup->typnamespace,
    3308             :                                               newOwnerId,
    3309             :                                               ACL_CREATE);
    3310           0 :             if (aclresult != ACLCHECK_OK)
    3311           0 :                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
    3312           0 :                                get_namespace_name(typTup->typnamespace));
    3313             :         }
    3314             : 
    3315           0 :         AlterTypeOwner_oid(typeOid, newOwnerId, true);
    3316             :     }
    3317             : 
    3318           0 :     ObjectAddressSet(address, TypeRelationId, typeOid);
    3319             : 
    3320             :     /* Clean up */
    3321           0 :     heap_close(rel, RowExclusiveLock);
    3322             : 
    3323           0 :     return address;
    3324             : }
    3325             : 
    3326             : /*
    3327             :  * AlterTypeOwner_oid - change type owner unconditionally
    3328             :  *
    3329             :  * This function recurses to handle a pg_class entry, if necessary.  It
    3330             :  * invokes any necessary access object hooks.  If hasDependEntry is TRUE, this
    3331             :  * function modifies the pg_shdepend entry appropriately (this should be
    3332             :  * passed as FALSE only for table rowtypes and array types).
    3333             :  *
    3334             :  * This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
    3335             :  * OWNED BY.  It assumes the caller has done all needed check.
    3336             :  */
    3337             : void
    3338           3 : AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
    3339             : {
    3340             :     Relation    rel;
    3341             :     HeapTuple   tup;
    3342             :     Form_pg_type typTup;
    3343             : 
    3344           3 :     rel = heap_open(TypeRelationId, RowExclusiveLock);
    3345             : 
    3346           3 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
    3347           3 :     if (!HeapTupleIsValid(tup))
    3348           0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
    3349           3 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    3350             : 
    3351             :     /*
    3352             :      * If it's a composite type, invoke ATExecChangeOwner so that we fix up
    3353             :      * the pg_class entry properly.  That will call back to
    3354             :      * AlterTypeOwnerInternal to take care of the pg_type entry(s).
    3355             :      */
    3356           3 :     if (typTup->typtype == TYPTYPE_COMPOSITE)
    3357           1 :         ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
    3358             :     else
    3359           2 :         AlterTypeOwnerInternal(typeOid, newOwnerId);
    3360             : 
    3361             :     /* Update owner dependency reference */
    3362           3 :     if (hasDependEntry)
    3363           3 :         changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
    3364             : 
    3365           3 :     InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
    3366             : 
    3367           3 :     ReleaseSysCache(tup);
    3368           3 :     heap_close(rel, RowExclusiveLock);
    3369           3 : }
    3370             : 
    3371             : /*
    3372             :  * AlterTypeOwnerInternal - bare-bones type owner change.
    3373             :  *
    3374             :  * This routine simply modifies the owner of a pg_type entry, and recurses
    3375             :  * to handle a possible array type.
    3376             :  */
    3377             : void
    3378          46 : AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
    3379             : {
    3380             :     Relation    rel;
    3381             :     HeapTuple   tup;
    3382             :     Form_pg_type typTup;
    3383             :     Datum       repl_val[Natts_pg_type];
    3384             :     bool        repl_null[Natts_pg_type];
    3385             :     bool        repl_repl[Natts_pg_type];
    3386             :     Acl        *newAcl;
    3387             :     Datum       aclDatum;
    3388             :     bool        isNull;
    3389             : 
    3390          46 :     rel = heap_open(TypeRelationId, RowExclusiveLock);
    3391             : 
    3392          46 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
    3393          46 :     if (!HeapTupleIsValid(tup))
    3394           0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
    3395          46 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    3396             : 
    3397          46 :     memset(repl_null, false, sizeof(repl_null));
    3398          46 :     memset(repl_repl, false, sizeof(repl_repl));
    3399             : 
    3400          46 :     repl_repl[Anum_pg_type_typowner - 1] = true;
    3401          46 :     repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
    3402             : 
    3403          46 :     aclDatum = heap_getattr(tup,
    3404             :                             Anum_pg_type_typacl,
    3405             :                             RelationGetDescr(rel),
    3406             :                             &isNull);
    3407             :     /* Null ACLs do not require changes */
    3408          46 :     if (!isNull)
    3409             :     {
    3410           0 :         newAcl = aclnewowner(DatumGetAclP(aclDatum),
    3411             :                              typTup->typowner, newOwnerId);
    3412           0 :         repl_repl[Anum_pg_type_typacl - 1] = true;
    3413           0 :         repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
    3414             :     }
    3415             : 
    3416          46 :     tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
    3417             :                             repl_repl);
    3418             : 
    3419          46 :     CatalogTupleUpdate(rel, &tup->t_self, tup);
    3420             : 
    3421             :     /* If it has an array type, update that too */
    3422          46 :     if (OidIsValid(typTup->typarray))
    3423          19 :         AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
    3424             : 
    3425             :     /* Clean up */
    3426          46 :     heap_close(rel, RowExclusiveLock);
    3427          46 : }
    3428             : 
    3429             : /*
    3430             :  * Execute ALTER TYPE SET SCHEMA
    3431             :  */
    3432             : ObjectAddress
    3433           3 : AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype,
    3434             :                    Oid *oldschema)
    3435             : {
    3436             :     TypeName   *typename;
    3437             :     Oid         typeOid;
    3438             :     Oid         nspOid;
    3439             :     Oid         oldNspOid;
    3440             :     ObjectAddresses *objsMoved;
    3441             :     ObjectAddress myself;
    3442             : 
    3443             :     /* Make a TypeName so we can use standard type lookup machinery */
    3444           3 :     typename = makeTypeNameFromNameList(names);
    3445           3 :     typeOid = typenameTypeId(NULL, typename);
    3446             : 
    3447             :     /* Don't allow ALTER DOMAIN on a type */
    3448           3 :     if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
    3449           0 :         ereport(ERROR,
    3450             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3451             :                  errmsg("%s is not a domain",
    3452             :                         format_type_be(typeOid))));
    3453             : 
    3454             :     /* get schema OID and check its permissions */
    3455           3 :     nspOid = LookupCreationNamespace(newschema);
    3456             : 
    3457           3 :     objsMoved = new_object_addresses();
    3458           3 :     oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
    3459           3 :     free_object_addresses(objsMoved);
    3460             : 
    3461           3 :     if (oldschema)
    3462           3 :         *oldschema = oldNspOid;
    3463             : 
    3464           3 :     ObjectAddressSet(myself, TypeRelationId, typeOid);
    3465             : 
    3466           3 :     return myself;
    3467             : }
    3468             : 
    3469             : Oid
    3470           3 : AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
    3471             : {
    3472             :     Oid         elemOid;
    3473             : 
    3474             :     /* check permissions on type */
    3475           3 :     if (!pg_type_ownercheck(typeOid, GetUserId()))
    3476           0 :         aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
    3477             : 
    3478             :     /* don't allow direct alteration of array types */
    3479           3 :     elemOid = get_element_type(typeOid);
    3480           3 :     if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
    3481           0 :         ereport(ERROR,
    3482             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3483             :                  errmsg("cannot alter array type %s",
    3484             :                         format_type_be(typeOid)),
    3485             :                  errhint("You can alter type %s, which will alter the array type as well.",
    3486             :                          format_type_be(elemOid))));
    3487             : 
    3488             :     /* and do the work */
    3489           3 :     return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
    3490             : }
    3491             : 
    3492             : /*
    3493             :  * Move specified type to new namespace.
    3494             :  *
    3495             :  * Caller must have already checked privileges.
    3496             :  *
    3497             :  * The function automatically recurses to process the type's array type,
    3498             :  * if any.  isImplicitArray should be TRUE only when doing this internal
    3499             :  * recursion (outside callers must never try to move an array type directly).
    3500             :  *
    3501             :  * If errorOnTableType is TRUE, the function errors out if the type is
    3502             :  * a table type.  ALTER TABLE has to be used to move a table to a new
    3503             :  * namespace.
    3504             :  *
    3505             :  * Returns the type's old namespace OID.
    3506             :  */
    3507             : Oid
    3508          29 : AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
    3509             :                            bool isImplicitArray,
    3510             :                            bool errorOnTableType,
    3511             :                            ObjectAddresses *objsMoved)
    3512             : {
    3513             :     Relation    rel;
    3514             :     HeapTuple   tup;
    3515             :     Form_pg_type typform;
    3516             :     Oid         oldNspOid;
    3517             :     Oid         arrayOid;
    3518             :     bool        isCompositeType;
    3519             :     ObjectAddress thisobj;
    3520             : 
    3521             :     /*
    3522             :      * Make sure we haven't moved this object previously.
    3523             :      */
    3524          29 :     thisobj.classId = TypeRelationId;
    3525          29 :     thisobj.objectId = typeOid;
    3526          29 :     thisobj.objectSubId = 0;
    3527             : 
    3528          29 :     if (object_address_present(&thisobj, objsMoved))
    3529           0 :         return InvalidOid;
    3530             : 
    3531          29 :     rel = heap_open(TypeRelationId, RowExclusiveLock);
    3532             : 
    3533          29 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
    3534          29 :     if (!HeapTupleIsValid(tup))
    3535           0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
    3536          29 :     typform = (Form_pg_type) GETSTRUCT(tup);
    3537             : 
    3538          29 :     oldNspOid = typform->typnamespace;
    3539          29 :     arrayOid = typform->typarray;
    3540             : 
    3541             :     /* If the type is already there, we scan skip these next few checks. */
    3542          29 :     if (oldNspOid != nspOid)
    3543             :     {
    3544             :         /* common checks on switching namespaces */
    3545          21 :         CheckSetNamespace(oldNspOid, nspOid);
    3546             : 
    3547             :         /* check for duplicate name (more friendly than unique-index failure) */
    3548          21 :         if (SearchSysCacheExists2(TYPENAMENSP,
    3549             :                                   NameGetDatum(&typform->typname),
    3550             :                                   ObjectIdGetDatum(nspOid)))
    3551           0 :             ereport(ERROR,
    3552             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    3553             :                      errmsg("type \"%s\" already exists in schema \"%s\"",
    3554             :                             NameStr(typform->typname),
    3555             :                             get_namespace_name(nspOid))));
    3556             :     }
    3557             : 
    3558             :     /* Detect whether type is a composite type (but not a table rowtype) */
    3559          29 :     isCompositeType =
    3560          45 :         (typform->typtype == TYPTYPE_COMPOSITE &&
    3561          16 :          get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
    3562             : 
    3563             :     /* Enforce not-table-type if requested */
    3564          29 :     if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
    3565             :         errorOnTableType)
    3566           0 :         ereport(ERROR,
    3567             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3568             :                  errmsg("%s is a table's row type",
    3569             :                         format_type_be(typeOid)),
    3570             :                  errhint("Use ALTER TABLE instead.")));
    3571             : 
    3572          29 :     if (oldNspOid != nspOid)
    3573             :     {
    3574             :         /* OK, modify the pg_type row */
    3575             : 
    3576             :         /* tup is a copy, so we can scribble directly on it */
    3577          21 :         typform->typnamespace = nspOid;
    3578             : 
    3579          21 :         CatalogTupleUpdate(rel, &tup->t_self, tup);
    3580             :     }
    3581             : 
    3582             :     /*
    3583             :      * Composite types have pg_class entries.
    3584             :      *
    3585             :      * We need to modify the pg_class tuple as well to reflect the change of
    3586             :      * schema.
    3587             :      */
    3588          29 :     if (isCompositeType)
    3589             :     {
    3590             :         Relation    classRel;
    3591             : 
    3592           2 :         classRel = heap_open(RelationRelationId, RowExclusiveLock);
    3593             : 
    3594           2 :         AlterRelationNamespaceInternal(classRel, typform->typrelid,
    3595             :                                        oldNspOid, nspOid,
    3596             :                                        false, objsMoved);
    3597             : 
    3598           2 :         heap_close(classRel, RowExclusiveLock);
    3599             : 
    3600             :         /*
    3601             :          * Check for constraints associated with the composite type (we don't
    3602             :          * currently support this, but probably will someday).
    3603             :          */
    3604           2 :         AlterConstraintNamespaces(typform->typrelid, oldNspOid,
    3605             :                                   nspOid, false, objsMoved);
    3606             :     }
    3607             :     else
    3608             :     {
    3609             :         /* If it's a domain, it might have constraints */
    3610          27 :         if (typform->typtype == TYPTYPE_DOMAIN)
    3611           1 :             AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
    3612             :                                       objsMoved);
    3613             :     }
    3614             : 
    3615             :     /*
    3616             :      * Update dependency on schema, if any --- a table rowtype has not got
    3617             :      * one, and neither does an implicit array.
    3618             :      */
    3619          29 :     if (oldNspOid != nspOid &&
    3620          20 :         (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
    3621             :         !isImplicitArray)
    3622           2 :         if (changeDependencyFor(TypeRelationId, typeOid,
    3623             :                                 NamespaceRelationId, oldNspOid, nspOid) != 1)
    3624           0 :             elog(ERROR, "failed to change schema dependency for type %s",
    3625             :                  format_type_be(typeOid));
    3626             : 
    3627          29 :     InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
    3628             : 
    3629          29 :     heap_freetuple(tup);
    3630             : 
    3631          29 :     heap_close(rel, RowExclusiveLock);
    3632             : 
    3633          29 :     add_exact_object_address(&thisobj, objsMoved);
    3634             : 
    3635             :     /* Recursively alter the associated array type, if any */
    3636          29 :     if (OidIsValid(arrayOid))
    3637          12 :         AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
    3638             : 
    3639          29 :     return oldNspOid;
    3640             : }

Generated by: LCOV version 1.11