LCOV - code coverage report
Current view: top level - src/backend/commands - typecmds.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 85.5 % 1374 1175
Test Date: 2026-05-23 14:16:35 Functions: 97.8 % 45 44
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-2026, 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 "FooCreate" routines (in src/backend/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/genam.h"
      35              : #include "access/htup_details.h"
      36              : #include "access/relation.h"
      37              : #include "access/table.h"
      38              : #include "access/tableam.h"
      39              : #include "access/xact.h"
      40              : #include "catalog/binary_upgrade.h"
      41              : #include "catalog/catalog.h"
      42              : #include "catalog/heap.h"
      43              : #include "catalog/objectaccess.h"
      44              : #include "catalog/pg_am.h"
      45              : #include "catalog/pg_authid.h"
      46              : #include "catalog/pg_cast.h"
      47              : #include "catalog/pg_collation.h"
      48              : #include "catalog/pg_constraint.h"
      49              : #include "catalog/pg_depend.h"
      50              : #include "catalog/pg_enum.h"
      51              : #include "catalog/pg_language.h"
      52              : #include "catalog/pg_namespace.h"
      53              : #include "catalog/pg_proc.h"
      54              : #include "catalog/pg_range.h"
      55              : #include "catalog/pg_type.h"
      56              : #include "commands/defrem.h"
      57              : #include "commands/tablecmds.h"
      58              : #include "commands/typecmds.h"
      59              : #include "executor/executor.h"
      60              : #include "miscadmin.h"
      61              : #include "nodes/makefuncs.h"
      62              : #include "optimizer/optimizer.h"
      63              : #include "parser/parse_coerce.h"
      64              : #include "parser/parse_collate.h"
      65              : #include "parser/parse_expr.h"
      66              : #include "parser/parse_func.h"
      67              : #include "parser/parse_type.h"
      68              : #include "utils/builtins.h"
      69              : #include "utils/fmgroids.h"
      70              : #include "utils/inval.h"
      71              : #include "utils/lsyscache.h"
      72              : #include "utils/rel.h"
      73              : #include "utils/ruleutils.h"
      74              : #include "utils/snapmgr.h"
      75              : #include "utils/syscache.h"
      76              : 
      77              : 
      78              : /* result structure for get_rels_with_domain() */
      79              : typedef struct
      80              : {
      81              :     Relation    rel;            /* opened and locked relation */
      82              :     int         natts;          /* number of attributes of interest */
      83              :     int        *atts;           /* attribute numbers */
      84              :     /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
      85              : } RelToCheck;
      86              : 
      87              : /* parameter structure for AlterTypeRecurse() */
      88              : typedef struct
      89              : {
      90              :     /* Flags indicating which type attributes to update */
      91              :     bool        updateStorage;
      92              :     bool        updateReceive;
      93              :     bool        updateSend;
      94              :     bool        updateTypmodin;
      95              :     bool        updateTypmodout;
      96              :     bool        updateAnalyze;
      97              :     bool        updateSubscript;
      98              :     /* New values for relevant attributes */
      99              :     char        storage;
     100              :     Oid         receiveOid;
     101              :     Oid         sendOid;
     102              :     Oid         typmodinOid;
     103              :     Oid         typmodoutOid;
     104              :     Oid         analyzeOid;
     105              :     Oid         subscriptOid;
     106              : } AlterTypeRecurseParams;
     107              : 
     108              : /* Potentially set by pg_upgrade_support functions */
     109              : Oid         binary_upgrade_next_array_pg_type_oid = InvalidOid;
     110              : Oid         binary_upgrade_next_mrng_pg_type_oid = InvalidOid;
     111              : Oid         binary_upgrade_next_mrng_array_pg_type_oid = InvalidOid;
     112              : 
     113              : static void makeRangeConstructors(const char *name, Oid namespace,
     114              :                                   Oid rangeOid, Oid subtype,
     115              :                                   Oid *rangeConstruct2_p, Oid *rangeConstruct3_p);
     116              : static void makeMultirangeConstructors(const char *name, Oid namespace,
     117              :                                        Oid multirangeOid, Oid rangeOid,
     118              :                                        Oid rangeArrayOid,
     119              :                                        Oid *mltrngConstruct0_p, Oid *mltrngConstruct1_p, Oid *mltrngConstruct2_p);
     120              : static Oid  findTypeInputFunction(List *procname, Oid typeOid);
     121              : static Oid  findTypeOutputFunction(List *procname, Oid typeOid);
     122              : static Oid  findTypeReceiveFunction(List *procname, Oid typeOid);
     123              : static Oid  findTypeSendFunction(List *procname, Oid typeOid);
     124              : static Oid  findTypeTypmodinFunction(List *procname);
     125              : static Oid  findTypeTypmodoutFunction(List *procname);
     126              : static Oid  findTypeAnalyzeFunction(List *procname, Oid typeOid);
     127              : static Oid  findTypeSubscriptingFunction(List *procname, Oid typeOid);
     128              : static Oid  findRangeSubOpclass(List *opcname, Oid subtype);
     129              : static Oid  findRangeCanonicalFunction(List *procname, Oid typeOid);
     130              : static Oid  findRangeSubtypeDiffFunction(List *procname, Oid subtype);
     131              : static void validateDomainCheckConstraint(Oid domainoid, const char *ccbin, LOCKMODE lockmode);
     132              : static void validateDomainNotNullConstraint(Oid domainoid);
     133              : static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
     134              : static void checkEnumOwner(HeapTuple tup);
     135              : static char *domainAddCheckConstraint(Oid domainOid, Oid domainNamespace,
     136              :                                       Oid baseTypeOid,
     137              :                                       int typMod, Constraint *constr,
     138              :                                       const char *domainName, ObjectAddress *constrAddr);
     139              : static Node *replace_domain_constraint_value(ParseState *pstate,
     140              :                                              ColumnRef *cref);
     141              : static void domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
     142              :                                        int typMod, Constraint *constr,
     143              :                                        const char *domainName, ObjectAddress *constrAddr);
     144              : static void AlterTypeRecurse(Oid typeOid, bool isImplicitArray,
     145              :                              HeapTuple tup, Relation catalog,
     146              :                              AlterTypeRecurseParams *atparams);
     147              : 
     148              : 
     149              : /*
     150              :  * DefineType
     151              :  *      Registers a new base type.
     152              :  */
     153              : ObjectAddress
     154          239 : DefineType(ParseState *pstate, List *names, List *parameters)
     155              : {
     156              :     char       *typeName;
     157              :     Oid         typeNamespace;
     158          239 :     int16       internalLength = -1;    /* default: variable-length */
     159          239 :     List       *inputName = NIL;
     160          239 :     List       *outputName = NIL;
     161          239 :     List       *receiveName = NIL;
     162          239 :     List       *sendName = NIL;
     163          239 :     List       *typmodinName = NIL;
     164          239 :     List       *typmodoutName = NIL;
     165          239 :     List       *analyzeName = NIL;
     166          239 :     List       *subscriptName = NIL;
     167          239 :     char        category = TYPCATEGORY_USER;
     168          239 :     bool        preferred = false;
     169          239 :     char        delimiter = DEFAULT_TYPDELIM;
     170          239 :     Oid         elemType = InvalidOid;
     171          239 :     char       *defaultValue = NULL;
     172          239 :     bool        byValue = false;
     173          239 :     char        alignment = TYPALIGN_INT;   /* default alignment */
     174          239 :     char        storage = TYPSTORAGE_PLAIN; /* default TOAST storage method */
     175          239 :     Oid         collation = InvalidOid;
     176          239 :     DefElem    *likeTypeEl = NULL;
     177          239 :     DefElem    *internalLengthEl = NULL;
     178          239 :     DefElem    *inputNameEl = NULL;
     179          239 :     DefElem    *outputNameEl = NULL;
     180          239 :     DefElem    *receiveNameEl = NULL;
     181          239 :     DefElem    *sendNameEl = NULL;
     182          239 :     DefElem    *typmodinNameEl = NULL;
     183          239 :     DefElem    *typmodoutNameEl = NULL;
     184          239 :     DefElem    *analyzeNameEl = NULL;
     185          239 :     DefElem    *subscriptNameEl = NULL;
     186          239 :     DefElem    *categoryEl = NULL;
     187          239 :     DefElem    *preferredEl = NULL;
     188          239 :     DefElem    *delimiterEl = NULL;
     189          239 :     DefElem    *elemTypeEl = NULL;
     190          239 :     DefElem    *defaultValueEl = NULL;
     191          239 :     DefElem    *byValueEl = NULL;
     192          239 :     DefElem    *alignmentEl = NULL;
     193          239 :     DefElem    *storageEl = NULL;
     194          239 :     DefElem    *collatableEl = NULL;
     195              :     Oid         inputOid;
     196              :     Oid         outputOid;
     197          239 :     Oid         receiveOid = InvalidOid;
     198          239 :     Oid         sendOid = InvalidOid;
     199          239 :     Oid         typmodinOid = InvalidOid;
     200          239 :     Oid         typmodoutOid = InvalidOid;
     201          239 :     Oid         analyzeOid = InvalidOid;
     202          239 :     Oid         subscriptOid = InvalidOid;
     203              :     char       *array_type;
     204              :     Oid         array_oid;
     205              :     Oid         typoid;
     206              :     ListCell   *pl;
     207              :     ObjectAddress address;
     208              : 
     209              :     /*
     210              :      * As of Postgres 8.4, we require superuser privilege to create a base
     211              :      * type.  This is simple paranoia: there are too many ways to mess up the
     212              :      * system with an incorrect type definition (for instance, representation
     213              :      * parameters that don't match what the C code expects).  In practice it
     214              :      * takes superuser privilege to create the I/O functions, and so the
     215              :      * former requirement that you own the I/O functions pretty much forced
     216              :      * superuserness anyway.  We're just making doubly sure here.
     217              :      *
     218              :      * XXX re-enable NOT_USED code sections below if you remove this test.
     219              :      */
     220          239 :     if (!superuser())
     221            0 :         ereport(ERROR,
     222              :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     223              :                  errmsg("must be superuser to create a base type")));
     224              : 
     225              :     /* Convert list of names to a name and namespace */
     226          239 :     typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
     227              : 
     228              : #ifdef NOT_USED
     229              :     /* XXX this is unnecessary given the superuser check above */
     230              :     /* Check we have creation rights in target namespace */
     231              :     aclresult = object_aclcheck(NamespaceRelationId, typeNamespace, GetUserId(), ACL_CREATE);
     232              :     if (aclresult != ACLCHECK_OK)
     233              :         aclcheck_error(aclresult, OBJECT_SCHEMA,
     234              :                        get_namespace_name(typeNamespace));
     235              : #endif
     236              : 
     237              :     /*
     238              :      * Look to see if type already exists.
     239              :      */
     240          239 :     typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
     241              :                              CStringGetDatum(typeName),
     242              :                              ObjectIdGetDatum(typeNamespace));
     243              : 
     244              :     /*
     245              :      * If it's not a shell, see if it's an autogenerated array type, and if so
     246              :      * rename it out of the way.
     247              :      */
     248          239 :     if (OidIsValid(typoid) && get_typisdefined(typoid))
     249              :     {
     250            4 :         if (moveArrayTypeName(typoid, typeName, typeNamespace))
     251            0 :             typoid = InvalidOid;
     252              :         else
     253            4 :             ereport(ERROR,
     254              :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
     255              :                      errmsg("type \"%s\" already exists", typeName)));
     256              :     }
     257              : 
     258              :     /*
     259              :      * If this command is a parameterless CREATE TYPE, then we're just here to
     260              :      * make a shell type, so do that (or fail if there already is a shell).
     261              :      */
     262          235 :     if (parameters == NIL)
     263              :     {
     264           94 :         if (OidIsValid(typoid))
     265            4 :             ereport(ERROR,
     266              :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
     267              :                      errmsg("type \"%s\" already exists", typeName)));
     268              : 
     269           90 :         address = TypeShellMake(typeName, typeNamespace, GetUserId());
     270           90 :         return address;
     271              :     }
     272              : 
     273              :     /*
     274              :      * Otherwise, we must already have a shell type, since there is no other
     275              :      * way that the I/O functions could have been created.
     276              :      */
     277          141 :     if (!OidIsValid(typoid))
     278            4 :         ereport(ERROR,
     279              :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
     280              :                  errmsg("type \"%s\" does not exist", typeName),
     281              :                  errhint("Create the type as a shell type, then create its I/O functions, then do a full CREATE TYPE.")));
     282              : 
     283              :     /* Extract the parameters from the parameter list */
     284          687 :     foreach(pl, parameters)
     285              :     {
     286          550 :         DefElem    *defel = (DefElem *) lfirst(pl);
     287              :         DefElem   **defelp;
     288              : 
     289          550 :         if (strcmp(defel->defname, "like") == 0)
     290           39 :             defelp = &likeTypeEl;
     291          511 :         else if (strcmp(defel->defname, "internallength") == 0)
     292           84 :             defelp = &internalLengthEl;
     293          427 :         else if (strcmp(defel->defname, "input") == 0)
     294          133 :             defelp = &inputNameEl;
     295          294 :         else if (strcmp(defel->defname, "output") == 0)
     296          133 :             defelp = &outputNameEl;
     297          161 :         else if (strcmp(defel->defname, "receive") == 0)
     298            9 :             defelp = &receiveNameEl;
     299          152 :         else if (strcmp(defel->defname, "send") == 0)
     300            9 :             defelp = &sendNameEl;
     301          143 :         else if (strcmp(defel->defname, "typmod_in") == 0)
     302            5 :             defelp = &typmodinNameEl;
     303          138 :         else if (strcmp(defel->defname, "typmod_out") == 0)
     304            5 :             defelp = &typmodoutNameEl;
     305          133 :         else if (strcmp(defel->defname, "analyze") == 0 ||
     306          133 :                  strcmp(defel->defname, "analyse") == 0)
     307            0 :             defelp = &analyzeNameEl;
     308          133 :         else if (strcmp(defel->defname, "subscript") == 0)
     309            1 :             defelp = &subscriptNameEl;
     310          132 :         else if (strcmp(defel->defname, "category") == 0)
     311            7 :             defelp = &categoryEl;
     312          125 :         else if (strcmp(defel->defname, "preferred") == 0)
     313            7 :             defelp = &preferredEl;
     314          118 :         else if (strcmp(defel->defname, "delimiter") == 0)
     315            0 :             defelp = &delimiterEl;
     316          118 :         else if (strcmp(defel->defname, "element") == 0)
     317            9 :             defelp = &elemTypeEl;
     318          109 :         else if (strcmp(defel->defname, "default") == 0)
     319           11 :             defelp = &defaultValueEl;
     320           98 :         else if (strcmp(defel->defname, "passedbyvalue") == 0)
     321            8 :             defelp = &byValueEl;
     322           90 :         else if (strcmp(defel->defname, "alignment") == 0)
     323           33 :             defelp = &alignmentEl;
     324           57 :         else if (strcmp(defel->defname, "storage") == 0)
     325           31 :             defelp = &storageEl;
     326           26 :         else if (strcmp(defel->defname, "collatable") == 0)
     327            2 :             defelp = &collatableEl;
     328              :         else
     329              :         {
     330              :             /* WARNING, not ERROR, for historical backwards-compatibility */
     331           24 :             ereport(WARNING,
     332              :                     (errcode(ERRCODE_SYNTAX_ERROR),
     333              :                      errmsg("type attribute \"%s\" not recognized",
     334              :                             defel->defname),
     335              :                      parser_errposition(pstate, defel->location)));
     336           24 :             continue;
     337              :         }
     338          526 :         if (*defelp != NULL)
     339            0 :             errorConflictingDefElem(defel, pstate);
     340          526 :         *defelp = defel;
     341              :     }
     342              : 
     343              :     /*
     344              :      * Now interpret the options; we do this separately so that LIKE can be
     345              :      * overridden by other options regardless of the ordering in the parameter
     346              :      * list.
     347              :      */
     348          137 :     if (likeTypeEl)
     349              :     {
     350              :         Type        likeType;
     351              :         Form_pg_type likeForm;
     352              : 
     353           39 :         likeType = typenameType(pstate, defGetTypeName(likeTypeEl), NULL);
     354           35 :         likeForm = (Form_pg_type) GETSTRUCT(likeType);
     355           35 :         internalLength = likeForm->typlen;
     356           35 :         byValue = likeForm->typbyval;
     357           35 :         alignment = likeForm->typalign;
     358           35 :         storage = likeForm->typstorage;
     359           35 :         ReleaseSysCache(likeType);
     360              :     }
     361          133 :     if (internalLengthEl)
     362           84 :         internalLength = defGetTypeLength(internalLengthEl);
     363          133 :     if (inputNameEl)
     364          129 :         inputName = defGetQualifiedName(inputNameEl);
     365          133 :     if (outputNameEl)
     366          129 :         outputName = defGetQualifiedName(outputNameEl);
     367          133 :     if (receiveNameEl)
     368            9 :         receiveName = defGetQualifiedName(receiveNameEl);
     369          133 :     if (sendNameEl)
     370            9 :         sendName = defGetQualifiedName(sendNameEl);
     371          133 :     if (typmodinNameEl)
     372            5 :         typmodinName = defGetQualifiedName(typmodinNameEl);
     373          133 :     if (typmodoutNameEl)
     374            5 :         typmodoutName = defGetQualifiedName(typmodoutNameEl);
     375          133 :     if (analyzeNameEl)
     376            0 :         analyzeName = defGetQualifiedName(analyzeNameEl);
     377          133 :     if (subscriptNameEl)
     378            1 :         subscriptName = defGetQualifiedName(subscriptNameEl);
     379          133 :     if (categoryEl)
     380              :     {
     381            7 :         char       *p = defGetString(categoryEl);
     382              : 
     383            7 :         category = p[0];
     384              :         /* restrict to non-control ASCII */
     385            7 :         if (category < 32 || category > 126)
     386            0 :             ereport(ERROR,
     387              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     388              :                      errmsg("invalid type category \"%s\": must be simple ASCII",
     389              :                             p)));
     390              :     }
     391          133 :     if (preferredEl)
     392            7 :         preferred = defGetBoolean(preferredEl);
     393          133 :     if (delimiterEl)
     394              :     {
     395            0 :         char       *p = defGetString(delimiterEl);
     396              : 
     397            0 :         delimiter = p[0];
     398              :         /* XXX shouldn't we restrict the delimiter? */
     399              :     }
     400          133 :     if (elemTypeEl)
     401              :     {
     402            9 :         elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
     403              :         /* disallow arrays of pseudotypes */
     404            9 :         if (get_typtype(elemType) == TYPTYPE_PSEUDO)
     405            0 :             ereport(ERROR,
     406              :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
     407              :                      errmsg("array element type cannot be %s",
     408              :                             format_type_be(elemType))));
     409              :     }
     410          133 :     if (defaultValueEl)
     411           11 :         defaultValue = defGetString(defaultValueEl);
     412          133 :     if (byValueEl)
     413            8 :         byValue = defGetBoolean(byValueEl);
     414          133 :     if (alignmentEl)
     415              :     {
     416           33 :         char       *a = defGetString(alignmentEl);
     417              : 
     418              :         /*
     419              :          * Note: if argument was an unquoted identifier, parser will have
     420              :          * applied translations to it, so be prepared to recognize translated
     421              :          * type names as well as the nominal form.
     422              :          */
     423           56 :         if (pg_strcasecmp(a, "double") == 0 ||
     424           46 :             pg_strcasecmp(a, "float8") == 0 ||
     425           23 :             pg_strcasecmp(a, "pg_catalog.float8") == 0)
     426           10 :             alignment = TYPALIGN_DOUBLE;
     427           27 :         else if (pg_strcasecmp(a, "int4") == 0 ||
     428            4 :                  pg_strcasecmp(a, "pg_catalog.int4") == 0)
     429           23 :             alignment = TYPALIGN_INT;
     430            0 :         else if (pg_strcasecmp(a, "int2") == 0 ||
     431            0 :                  pg_strcasecmp(a, "pg_catalog.int2") == 0)
     432            0 :             alignment = TYPALIGN_SHORT;
     433            0 :         else if (pg_strcasecmp(a, "char") == 0 ||
     434            0 :                  pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
     435            0 :             alignment = TYPALIGN_CHAR;
     436              :         else
     437            0 :             ereport(ERROR,
     438              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     439              :                      errmsg("alignment \"%s\" not recognized", a)));
     440              :     }
     441          133 :     if (storageEl)
     442              :     {
     443           31 :         char       *a = defGetString(storageEl);
     444              : 
     445           31 :         if (pg_strcasecmp(a, "plain") == 0)
     446            9 :             storage = TYPSTORAGE_PLAIN;
     447           22 :         else if (pg_strcasecmp(a, "external") == 0)
     448            0 :             storage = TYPSTORAGE_EXTERNAL;
     449           22 :         else if (pg_strcasecmp(a, "extended") == 0)
     450           18 :             storage = TYPSTORAGE_EXTENDED;
     451            4 :         else if (pg_strcasecmp(a, "main") == 0)
     452            4 :             storage = TYPSTORAGE_MAIN;
     453              :         else
     454            0 :             ereport(ERROR,
     455              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     456              :                      errmsg("storage \"%s\" not recognized", a)));
     457              :     }
     458          133 :     if (collatableEl)
     459            2 :         collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
     460              : 
     461              :     /*
     462              :      * make sure we have our required definitions
     463              :      */
     464          133 :     if (inputName == NIL)
     465            4 :         ereport(ERROR,
     466              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     467              :                  errmsg("type input function must be specified")));
     468          129 :     if (outputName == NIL)
     469            0 :         ereport(ERROR,
     470              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     471              :                  errmsg("type output function must be specified")));
     472              : 
     473          129 :     if (typmodinName == NIL && typmodoutName != NIL)
     474            0 :         ereport(ERROR,
     475              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     476              :                  errmsg("type modifier output function is useless without a type modifier input function")));
     477              : 
     478              :     /*
     479              :      * Convert I/O proc names to OIDs
     480              :      */
     481          129 :     inputOid = findTypeInputFunction(inputName, typoid);
     482          125 :     outputOid = findTypeOutputFunction(outputName, typoid);
     483          125 :     if (receiveName)
     484            9 :         receiveOid = findTypeReceiveFunction(receiveName, typoid);
     485          125 :     if (sendName)
     486            9 :         sendOid = findTypeSendFunction(sendName, typoid);
     487              : 
     488              :     /*
     489              :      * Convert typmodin/out function proc names to OIDs.
     490              :      */
     491          125 :     if (typmodinName)
     492            5 :         typmodinOid = findTypeTypmodinFunction(typmodinName);
     493          125 :     if (typmodoutName)
     494            5 :         typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
     495              : 
     496              :     /*
     497              :      * Convert analysis function proc name to an OID. If no analysis function
     498              :      * is specified, we'll use zero to select the built-in default algorithm.
     499              :      */
     500          125 :     if (analyzeName)
     501            0 :         analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
     502              : 
     503              :     /*
     504              :      * Likewise look up the subscripting function if any.  If it is not
     505              :      * specified, but a typelem is specified, allow that if
     506              :      * raw_array_subscript_handler can be used.  (This is for backwards
     507              :      * compatibility; maybe someday we should throw an error instead.)
     508              :      */
     509          125 :     if (subscriptName)
     510            1 :         subscriptOid = findTypeSubscriptingFunction(subscriptName, typoid);
     511          124 :     else if (OidIsValid(elemType))
     512              :     {
     513            4 :         if (internalLength > 0 && !byValue && get_typlen(elemType) > 0)
     514            4 :             subscriptOid = F_RAW_ARRAY_SUBSCRIPT_HANDLER;
     515              :         else
     516            0 :             ereport(ERROR,
     517              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     518              :                      errmsg("element type cannot be specified without a subscripting function")));
     519              :     }
     520              : 
     521              :     /*
     522              :      * Check permissions on functions.  We choose to require the creator/owner
     523              :      * of a type to also own the underlying functions.  Since creating a type
     524              :      * is tantamount to granting public execute access on the functions, the
     525              :      * minimum sane check would be for execute-with-grant-option.  But we
     526              :      * don't have a way to make the type go away if the grant option is
     527              :      * revoked, so ownership seems better.
     528              :      *
     529              :      * XXX For now, this is all unnecessary given the superuser check above.
     530              :      * If we ever relax that, these calls likely should be moved into
     531              :      * findTypeInputFunction et al, where they could be shared by AlterType.
     532              :      */
     533              : #ifdef NOT_USED
     534              :     if (inputOid && !object_ownercheck(ProcedureRelationId, inputOid, GetUserId()))
     535              :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     536              :                        NameListToString(inputName));
     537              :     if (outputOid && !object_ownercheck(ProcedureRelationId, outputOid, GetUserId()))
     538              :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     539              :                        NameListToString(outputName));
     540              :     if (receiveOid && !object_ownercheck(ProcedureRelationId, receiveOid, GetUserId()))
     541              :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     542              :                        NameListToString(receiveName));
     543              :     if (sendOid && !object_ownercheck(ProcedureRelationId, sendOid, GetUserId()))
     544              :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     545              :                        NameListToString(sendName));
     546              :     if (typmodinOid && !object_ownercheck(ProcedureRelationId, typmodinOid, GetUserId()))
     547              :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     548              :                        NameListToString(typmodinName));
     549              :     if (typmodoutOid && !object_ownercheck(ProcedureRelationId, typmodoutOid, GetUserId()))
     550              :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     551              :                        NameListToString(typmodoutName));
     552              :     if (analyzeOid && !object_ownercheck(ProcedureRelationId, analyzeOid, GetUserId()))
     553              :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     554              :                        NameListToString(analyzeName));
     555              :     if (subscriptOid && !object_ownercheck(ProcedureRelationId, subscriptOid, GetUserId()))
     556              :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     557              :                        NameListToString(subscriptName));
     558              : #endif
     559              : 
     560              :     /*
     561              :      * OK, we're done checking, time to make the type.  We must assign the
     562              :      * array type OID ahead of calling TypeCreate, since the base type and
     563              :      * array type each refer to the other.
     564              :      */
     565          125 :     array_oid = AssignTypeArrayOid();
     566              : 
     567              :     /*
     568              :      * now have TypeCreate do all the real work.
     569              :      *
     570              :      * Note: the pg_type.oid is stored in user tables as array elements (base
     571              :      * types) in ArrayType and in composite types in DatumTupleFields.  This
     572              :      * oid must be preserved by binary upgrades.
     573              :      */
     574              :     address =
     575          125 :         TypeCreate(InvalidOid,  /* no predetermined type OID */
     576              :                    typeName,    /* type name */
     577              :                    typeNamespace,   /* namespace */
     578              :                    InvalidOid,  /* relation oid (n/a here) */
     579              :                    0,           /* relation kind (ditto) */
     580              :                    GetUserId(), /* owner's ID */
     581              :                    internalLength,  /* internal size */
     582              :                    TYPTYPE_BASE,    /* type-type (base type) */
     583              :                    category,    /* type-category */
     584              :                    preferred,   /* is it a preferred type? */
     585              :                    delimiter,   /* array element delimiter */
     586              :                    inputOid,    /* input procedure */
     587              :                    outputOid,   /* output procedure */
     588              :                    receiveOid,  /* receive procedure */
     589              :                    sendOid,     /* send procedure */
     590              :                    typmodinOid, /* typmodin procedure */
     591              :                    typmodoutOid,    /* typmodout procedure */
     592              :                    analyzeOid,  /* analyze procedure */
     593              :                    subscriptOid,    /* subscript procedure */
     594              :                    elemType,    /* element type ID */
     595              :                    false,       /* this is not an implicit array type */
     596              :                    array_oid,   /* array type we are about to create */
     597              :                    InvalidOid,  /* base type ID (only for domains) */
     598              :                    defaultValue,    /* default type value */
     599              :                    NULL,        /* no binary form available */
     600              :                    byValue,     /* passed by value */
     601              :                    alignment,   /* required alignment */
     602              :                    storage,     /* TOAST strategy */
     603              :                    -1,          /* typMod (Domains only) */
     604              :                    0,           /* Array Dimensions of typbasetype */
     605              :                    false,       /* Type NOT NULL */
     606              :                    collation);  /* type's collation */
     607              :     Assert(typoid == address.objectId);
     608              : 
     609              :     /*
     610              :      * Create the array type that goes with it.
     611              :      */
     612          125 :     array_type = makeArrayTypeName(typeName, typeNamespace);
     613              : 
     614              :     /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for arrays */
     615          125 :     alignment = (alignment == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
     616              : 
     617          125 :     TypeCreate(array_oid,       /* force assignment of this type OID */
     618              :                array_type,      /* type name */
     619              :                typeNamespace,   /* namespace */
     620              :                InvalidOid,      /* relation oid (n/a here) */
     621              :                0,               /* relation kind (ditto) */
     622              :                GetUserId(),     /* owner's ID */
     623              :                -1,              /* internal size (always varlena) */
     624              :                TYPTYPE_BASE,    /* type-type (base type) */
     625              :                TYPCATEGORY_ARRAY,   /* type-category (array) */
     626              :                false,           /* array types are never preferred */
     627              :                delimiter,       /* array element delimiter */
     628              :                F_ARRAY_IN,      /* input procedure */
     629              :                F_ARRAY_OUT,     /* output procedure */
     630              :                F_ARRAY_RECV,    /* receive procedure */
     631              :                F_ARRAY_SEND,    /* send procedure */
     632              :                typmodinOid,     /* typmodin procedure */
     633              :                typmodoutOid,    /* typmodout procedure */
     634              :                F_ARRAY_TYPANALYZE,  /* analyze procedure */
     635              :                F_ARRAY_SUBSCRIPT_HANDLER,   /* array subscript procedure */
     636              :                typoid,          /* element type ID */
     637              :                true,            /* yes this is an array type */
     638              :                InvalidOid,      /* no further array type */
     639              :                InvalidOid,      /* base type ID */
     640              :                NULL,            /* never a default type value */
     641              :                NULL,            /* binary default isn't sent either */
     642              :                false,           /* never passed by value */
     643              :                alignment,       /* see above */
     644              :                TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
     645              :                -1,              /* typMod (Domains only) */
     646              :                0,               /* Array dimensions of typbasetype */
     647              :                false,           /* Type NOT NULL */
     648              :                collation);      /* type's collation */
     649              : 
     650          125 :     pfree(array_type);
     651              : 
     652          125 :     return address;
     653              : }
     654              : 
     655              : /*
     656              :  * Guts of type deletion.
     657              :  */
     658              : void
     659        53620 : RemoveTypeById(Oid typeOid)
     660              : {
     661              :     Relation    relation;
     662              :     HeapTuple   tup;
     663              : 
     664        53620 :     relation = table_open(TypeRelationId, RowExclusiveLock);
     665              : 
     666        53620 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
     667        53620 :     if (!HeapTupleIsValid(tup))
     668            0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
     669              : 
     670        53620 :     CatalogTupleDelete(relation, &tup->t_self);
     671              : 
     672              :     /*
     673              :      * If it is an enum, delete the pg_enum entries too; we don't bother with
     674              :      * making dependency entries for those, so it has to be done "by hand"
     675              :      * here.
     676              :      */
     677        53620 :     if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
     678          179 :         EnumValuesDelete(typeOid);
     679              : 
     680              :     /*
     681              :      * If it is a range type, delete the pg_range entry too; we don't bother
     682              :      * with making a dependency entry for that, so it has to be done "by hand"
     683              :      * here.
     684              :      */
     685        53620 :     if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
     686           91 :         RangeDelete(typeOid);
     687              : 
     688        53620 :     ReleaseSysCache(tup);
     689              : 
     690        53620 :     table_close(relation, RowExclusiveLock);
     691        53620 : }
     692              : 
     693              : 
     694              : /*
     695              :  * DefineDomain
     696              :  *      Registers a new domain.
     697              :  */
     698              : ObjectAddress
     699          993 : DefineDomain(ParseState *pstate, CreateDomainStmt *stmt)
     700              : {
     701              :     char       *domainName;
     702              :     char       *domainArrayName;
     703              :     Oid         domainNamespace;
     704              :     AclResult   aclresult;
     705              :     int16       internalLength;
     706              :     Oid         inputProcedure;
     707              :     Oid         outputProcedure;
     708              :     Oid         receiveProcedure;
     709              :     Oid         sendProcedure;
     710              :     Oid         analyzeProcedure;
     711              :     bool        byValue;
     712              :     char        category;
     713              :     char        delimiter;
     714              :     char        alignment;
     715              :     char        storage;
     716              :     char        typtype;
     717              :     Datum       datum;
     718              :     bool        isnull;
     719          993 :     char       *defaultValue = NULL;
     720          993 :     char       *defaultValueBin = NULL;
     721          993 :     bool        saw_default = false;
     722          993 :     bool        typNotNull = false;
     723          993 :     bool        nullDefined = false;
     724          993 :     int32       typNDims = list_length(stmt->typeName->arrayBounds);
     725              :     HeapTuple   typeTup;
     726          993 :     List       *schema = stmt->constraints;
     727              :     ListCell   *listptr;
     728              :     Oid         basetypeoid;
     729              :     Oid         old_type_oid;
     730              :     Oid         domaincoll;
     731              :     Oid         domainArrayOid;
     732              :     Form_pg_type baseType;
     733              :     int32       basetypeMod;
     734              :     Oid         baseColl;
     735              :     ObjectAddress address;
     736              : 
     737              :     /* Convert list of names to a name and namespace */
     738          993 :     domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
     739              :                                                         &domainName);
     740              : 
     741              :     /* Check we have creation rights in target namespace */
     742          993 :     aclresult = object_aclcheck(NamespaceRelationId, domainNamespace, GetUserId(),
     743              :                                 ACL_CREATE);
     744          993 :     if (aclresult != ACLCHECK_OK)
     745            0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
     746            0 :                        get_namespace_name(domainNamespace));
     747              : 
     748              :     /*
     749              :      * Check for collision with an existing type name.  If there is one and
     750              :      * it's an autogenerated array, we can rename it out of the way.
     751              :      */
     752          993 :     old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
     753              :                                    CStringGetDatum(domainName),
     754              :                                    ObjectIdGetDatum(domainNamespace));
     755          993 :     if (OidIsValid(old_type_oid))
     756              :     {
     757            0 :         if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
     758            0 :             ereport(ERROR,
     759              :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
     760              :                      errmsg("type \"%s\" already exists", domainName)));
     761              :     }
     762              : 
     763              :     /*
     764              :      * Look up the base type.
     765              :      */
     766          993 :     typeTup = typenameType(pstate, stmt->typeName, &basetypeMod);
     767          989 :     baseType = (Form_pg_type) GETSTRUCT(typeTup);
     768          989 :     basetypeoid = baseType->oid;
     769              : 
     770              :     /*
     771              :      * Base type must be a plain base type, a composite type, another domain,
     772              :      * an enum or a range type.  Domains over pseudotypes would create a
     773              :      * security hole.  (It would be shorter to code this to just check for
     774              :      * pseudotypes; but it seems safer to call out the specific typtypes that
     775              :      * are supported, rather than assume that all future typtypes would be
     776              :      * automatically supported.)
     777              :      */
     778          989 :     typtype = baseType->typtype;
     779          989 :     if (typtype != TYPTYPE_BASE &&
     780           69 :         typtype != TYPTYPE_COMPOSITE &&
     781           36 :         typtype != TYPTYPE_DOMAIN &&
     782           27 :         typtype != TYPTYPE_ENUM &&
     783           13 :         typtype != TYPTYPE_RANGE &&
     784              :         typtype != TYPTYPE_MULTIRANGE)
     785            4 :         ereport(ERROR,
     786              :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
     787              :                  errmsg("\"%s\" is not a valid base type for a domain",
     788              :                         TypeNameToString(stmt->typeName)),
     789              :                  parser_errposition(pstate, stmt->typeName->location)));
     790              : 
     791          985 :     aclresult = object_aclcheck(TypeRelationId, basetypeoid, GetUserId(), ACL_USAGE);
     792          985 :     if (aclresult != ACLCHECK_OK)
     793            4 :         aclcheck_error_type(aclresult, basetypeoid);
     794              : 
     795              :     /*
     796              :      * Collect the properties of the new domain.  Some are inherited from the
     797              :      * base type, some are not.  If you change any of this inheritance
     798              :      * behavior, be sure to update AlterTypeRecurse() to match!
     799              :      */
     800              : 
     801              :     /*
     802              :      * Identify the collation if any
     803              :      */
     804          981 :     baseColl = baseType->typcollation;
     805          981 :     if (stmt->collClause)
     806          143 :         domaincoll = get_collation_oid(stmt->collClause->collname, false);
     807              :     else
     808          838 :         domaincoll = baseColl;
     809              : 
     810              :     /* Complain if COLLATE is applied to an uncollatable type */
     811          981 :     if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
     812           12 :         ereport(ERROR,
     813              :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
     814              :                  errmsg("collations are not supported by type %s",
     815              :                         format_type_be(basetypeoid)),
     816              :                  parser_errposition(pstate, stmt->typeName->location)));
     817              : 
     818              :     /* passed by value */
     819          969 :     byValue = baseType->typbyval;
     820              : 
     821              :     /* Required Alignment */
     822          969 :     alignment = baseType->typalign;
     823              : 
     824              :     /* TOAST Strategy */
     825          969 :     storage = baseType->typstorage;
     826              : 
     827              :     /* Storage Length */
     828          969 :     internalLength = baseType->typlen;
     829              : 
     830              :     /* Type Category */
     831          969 :     category = baseType->typcategory;
     832              : 
     833              :     /* Array element Delimiter */
     834          969 :     delimiter = baseType->typdelim;
     835              : 
     836              :     /* I/O Functions */
     837          969 :     inputProcedure = F_DOMAIN_IN;
     838          969 :     outputProcedure = baseType->typoutput;
     839          969 :     receiveProcedure = F_DOMAIN_RECV;
     840          969 :     sendProcedure = baseType->typsend;
     841              : 
     842              :     /* Domains never accept typmods, so no typmodin/typmodout needed */
     843              : 
     844              :     /* Analysis function */
     845          969 :     analyzeProcedure = baseType->typanalyze;
     846              : 
     847              :     /*
     848              :      * Domains don't need a subscript function, since they are not
     849              :      * subscriptable on their own.  If the base type is subscriptable, the
     850              :      * parser will reduce the type to the base type before subscripting.
     851              :      */
     852              : 
     853              :     /* Inherited default value */
     854          969 :     datum = SysCacheGetAttr(TYPEOID, typeTup,
     855              :                             Anum_pg_type_typdefault, &isnull);
     856          969 :     if (!isnull)
     857            0 :         defaultValue = TextDatumGetCString(datum);
     858              : 
     859              :     /* Inherited default binary value */
     860          969 :     datum = SysCacheGetAttr(TYPEOID, typeTup,
     861              :                             Anum_pg_type_typdefaultbin, &isnull);
     862          969 :     if (!isnull)
     863            0 :         defaultValueBin = TextDatumGetCString(datum);
     864              : 
     865              :     /*
     866              :      * Run through constraints manually to avoid the additional processing
     867              :      * conducted by DefineRelation() and friends.
     868              :      */
     869         1570 :     foreach(listptr, schema)
     870              :     {
     871          653 :         Constraint *constr = lfirst(listptr);
     872              : 
     873          653 :         if (!IsA(constr, Constraint))
     874            0 :             elog(ERROR, "unrecognized node type: %d",
     875              :                  (int) nodeTag(constr));
     876          653 :         switch (constr->contype)
     877              :         {
     878          118 :             case CONSTR_DEFAULT:
     879              : 
     880              :                 /*
     881              :                  * The inherited default value may be overridden by the user
     882              :                  * with the DEFAULT <expr> clause ... but only once.
     883              :                  */
     884          118 :                 if (saw_default)
     885            4 :                     ereport(ERROR,
     886              :                             errcode(ERRCODE_SYNTAX_ERROR),
     887              :                             errmsg("multiple default expressions"),
     888              :                             parser_errposition(pstate, constr->location));
     889          114 :                 saw_default = true;
     890              : 
     891          114 :                 if (constr->raw_expr)
     892              :                 {
     893              :                     Node       *defaultExpr;
     894              : 
     895              :                     /*
     896              :                      * Cook the constr->raw_expr into an expression. Note:
     897              :                      * name is strictly for error message
     898              :                      */
     899          114 :                     defaultExpr = cookDefault(pstate, constr->raw_expr,
     900              :                                               basetypeoid,
     901              :                                               basetypeMod,
     902              :                                               domainName,
     903              :                                               0);
     904              : 
     905              :                     /*
     906              :                      * If the expression is just a NULL constant, we treat it
     907              :                      * like not having a default.
     908              :                      *
     909              :                      * Note that if the basetype is another domain, we'll see
     910              :                      * a CoerceToDomain expr here and not discard the default.
     911              :                      * This is critical because the domain default needs to be
     912              :                      * retained to override any default that the base domain
     913              :                      * might have.
     914              :                      */
     915          110 :                     if (defaultExpr == NULL ||
     916          110 :                         (IsA(defaultExpr, Const) &&
     917           27 :                          ((Const *) defaultExpr)->constisnull))
     918              :                     {
     919            0 :                         defaultValue = NULL;
     920            0 :                         defaultValueBin = NULL;
     921              :                     }
     922              :                     else
     923              :                     {
     924              :                         /*
     925              :                          * Expression must be stored as a nodeToString result,
     926              :                          * but we also require a valid textual representation
     927              :                          * (mainly to make life easier for pg_dump).
     928              :                          */
     929              :                         defaultValue =
     930          110 :                             deparse_expression(defaultExpr,
     931              :                                                NIL, false, false);
     932          110 :                         defaultValueBin = nodeToString(defaultExpr);
     933              :                     }
     934              :                 }
     935              :                 else
     936              :                 {
     937              :                     /* No default (can this still happen?) */
     938            0 :                     defaultValue = NULL;
     939            0 :                     defaultValueBin = NULL;
     940              :                 }
     941          110 :                 break;
     942              : 
     943           80 :             case CONSTR_NOTNULL:
     944           80 :                 if (nullDefined)
     945              :                 {
     946            4 :                     if (!typNotNull)
     947            0 :                         ereport(ERROR,
     948              :                                 errcode(ERRCODE_SYNTAX_ERROR),
     949              :                                 errmsg("conflicting NULL/NOT NULL constraints"),
     950              :                                 parser_errposition(pstate, constr->location));
     951              : 
     952            4 :                     ereport(ERROR,
     953              :                             errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     954              :                             errmsg("redundant NOT NULL constraint definition"),
     955              :                             parser_errposition(pstate, constr->location));
     956              :                 }
     957           76 :                 if (constr->is_no_inherit)
     958            4 :                     ereport(ERROR,
     959              :                             errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     960              :                             errmsg("not-null constraints for domains cannot be marked NO INHERIT"),
     961              :                             parser_errposition(pstate, constr->location));
     962           72 :                 typNotNull = true;
     963           72 :                 nullDefined = true;
     964           72 :                 break;
     965              : 
     966            4 :             case CONSTR_NULL:
     967            4 :                 if (nullDefined && typNotNull)
     968            4 :                     ereport(ERROR,
     969              :                             errcode(ERRCODE_SYNTAX_ERROR),
     970              :                             errmsg("conflicting NULL/NOT NULL constraints"),
     971              :                             parser_errposition(pstate, constr->location));
     972            0 :                 typNotNull = false;
     973            0 :                 nullDefined = true;
     974            0 :                 break;
     975              : 
     976          423 :             case CONSTR_CHECK:
     977              : 
     978              :                 /*
     979              :                  * Check constraints are handled after domain creation, as
     980              :                  * they require the Oid of the domain; at this point we can
     981              :                  * only check that they're not marked NO INHERIT, because that
     982              :                  * would be bogus.
     983              :                  */
     984          423 :                 if (constr->is_no_inherit)
     985            4 :                     ereport(ERROR,
     986              :                             errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     987              :                             errmsg("check constraints for domains cannot be marked NO INHERIT"),
     988              :                             parser_errposition(pstate, constr->location));
     989              : 
     990          419 :                 break;
     991              : 
     992              :                 /*
     993              :                  * All else are error cases
     994              :                  */
     995            4 :             case CONSTR_UNIQUE:
     996            4 :                 ereport(ERROR,
     997              :                         errcode(ERRCODE_SYNTAX_ERROR),
     998              :                         errmsg("unique constraints not possible for domains"),
     999              :                         parser_errposition(pstate, constr->location));
    1000              :                 break;
    1001              : 
    1002            4 :             case CONSTR_PRIMARY:
    1003            4 :                 ereport(ERROR,
    1004              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1005              :                          errmsg("primary key constraints not possible for domains"),
    1006              :                          parser_errposition(pstate, constr->location)));
    1007              :                 break;
    1008              : 
    1009            0 :             case CONSTR_EXCLUSION:
    1010            0 :                 ereport(ERROR,
    1011              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1012              :                          errmsg("exclusion constraints not possible for domains"),
    1013              :                          parser_errposition(pstate, constr->location)));
    1014              :                 break;
    1015              : 
    1016            4 :             case CONSTR_FOREIGN:
    1017            4 :                 ereport(ERROR,
    1018              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1019              :                          errmsg("foreign key constraints not possible for domains"),
    1020              :                          parser_errposition(pstate, constr->location)));
    1021              :                 break;
    1022              : 
    1023            4 :             case CONSTR_ATTR_DEFERRABLE:
    1024              :             case CONSTR_ATTR_NOT_DEFERRABLE:
    1025              :             case CONSTR_ATTR_DEFERRED:
    1026              :             case CONSTR_ATTR_IMMEDIATE:
    1027            4 :                 ereport(ERROR,
    1028              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1029              :                          errmsg("specifying constraint deferrability not supported for domains"),
    1030              :                          parser_errposition(pstate, constr->location)));
    1031              :                 break;
    1032              : 
    1033            4 :             case CONSTR_GENERATED:
    1034              :             case CONSTR_IDENTITY:
    1035            4 :                 ereport(ERROR,
    1036              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1037              :                          errmsg("specifying GENERATED not supported for domains"),
    1038              :                          parser_errposition(pstate, constr->location)));
    1039              :                 break;
    1040              : 
    1041            8 :             case CONSTR_ATTR_ENFORCED:
    1042              :             case CONSTR_ATTR_NOT_ENFORCED:
    1043            8 :                 ereport(ERROR,
    1044              :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1045              :                          errmsg("specifying constraint enforceability not supported for domains"),
    1046              :                          parser_errposition(pstate, constr->location)));
    1047              :                 break;
    1048              : 
    1049              :                 /* no default, to let compiler warn about missing case */
    1050              :         }
    1051              :     }
    1052              : 
    1053              :     /* Allocate OID for array type */
    1054          917 :     domainArrayOid = AssignTypeArrayOid();
    1055              : 
    1056              :     /*
    1057              :      * Have TypeCreate do all the real work.
    1058              :      */
    1059              :     address =
    1060          917 :         TypeCreate(InvalidOid,  /* no predetermined type OID */
    1061              :                    domainName,  /* type name */
    1062              :                    domainNamespace, /* namespace */
    1063              :                    InvalidOid,  /* relation oid (n/a here) */
    1064              :                    0,           /* relation kind (ditto) */
    1065              :                    GetUserId(), /* owner's ID */
    1066              :                    internalLength,  /* internal size */
    1067              :                    TYPTYPE_DOMAIN,  /* type-type (domain type) */
    1068              :                    category,    /* type-category */
    1069              :                    false,       /* domain types are never preferred */
    1070              :                    delimiter,   /* array element delimiter */
    1071              :                    inputProcedure,  /* input procedure */
    1072              :                    outputProcedure, /* output procedure */
    1073              :                    receiveProcedure,    /* receive procedure */
    1074              :                    sendProcedure,   /* send procedure */
    1075              :                    InvalidOid,  /* typmodin procedure - none */
    1076              :                    InvalidOid,  /* typmodout procedure - none */
    1077              :                    analyzeProcedure,    /* analyze procedure */
    1078              :                    InvalidOid,  /* subscript procedure - none */
    1079              :                    InvalidOid,  /* no array element type */
    1080              :                    false,       /* this isn't an array */
    1081              :                    domainArrayOid,  /* array type we are about to create */
    1082              :                    basetypeoid, /* base type ID */
    1083              :                    defaultValue,    /* default type value (text) */
    1084              :                    defaultValueBin, /* default type value (binary) */
    1085              :                    byValue,     /* passed by value */
    1086              :                    alignment,   /* required alignment */
    1087              :                    storage,     /* TOAST strategy */
    1088              :                    basetypeMod, /* typeMod value */
    1089              :                    typNDims,    /* Array dimensions for base type */
    1090              :                    typNotNull,  /* Type NOT NULL */
    1091              :                    domaincoll); /* type's collation */
    1092              : 
    1093              :     /*
    1094              :      * Create the array type that goes with it.
    1095              :      */
    1096          917 :     domainArrayName = makeArrayTypeName(domainName, domainNamespace);
    1097              : 
    1098              :     /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for arrays */
    1099          917 :     alignment = (alignment == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
    1100              : 
    1101          917 :     TypeCreate(domainArrayOid,  /* force assignment of this type OID */
    1102              :                domainArrayName, /* type name */
    1103              :                domainNamespace, /* namespace */
    1104              :                InvalidOid,      /* relation oid (n/a here) */
    1105              :                0,               /* relation kind (ditto) */
    1106              :                GetUserId(),     /* owner's ID */
    1107              :                -1,              /* internal size (always varlena) */
    1108              :                TYPTYPE_BASE,    /* type-type (base type) */
    1109              :                TYPCATEGORY_ARRAY,   /* type-category (array) */
    1110              :                false,           /* array types are never preferred */
    1111              :                delimiter,       /* array element delimiter */
    1112              :                F_ARRAY_IN,      /* input procedure */
    1113              :                F_ARRAY_OUT,     /* output procedure */
    1114              :                F_ARRAY_RECV,    /* receive procedure */
    1115              :                F_ARRAY_SEND,    /* send procedure */
    1116              :                InvalidOid,      /* typmodin procedure - none */
    1117              :                InvalidOid,      /* typmodout procedure - none */
    1118              :                F_ARRAY_TYPANALYZE,  /* analyze procedure */
    1119              :                F_ARRAY_SUBSCRIPT_HANDLER,   /* array subscript procedure */
    1120              :                address.objectId,    /* element type ID */
    1121              :                true,            /* yes this is an array type */
    1122              :                InvalidOid,      /* no further array type */
    1123              :                InvalidOid,      /* base type ID */
    1124              :                NULL,            /* never a default type value */
    1125              :                NULL,            /* binary default isn't sent either */
    1126              :                false,           /* never passed by value */
    1127              :                alignment,       /* see above */
    1128              :                TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
    1129              :                -1,              /* typMod (Domains only) */
    1130              :                0,               /* Array dimensions of typbasetype */
    1131              :                false,           /* Type NOT NULL */
    1132              :                domaincoll);     /* type's collation */
    1133              : 
    1134          917 :     pfree(domainArrayName);
    1135              : 
    1136              :     /*
    1137              :      * Process constraints which refer to the domain ID returned by TypeCreate
    1138              :      */
    1139         1490 :     foreach(listptr, schema)
    1140              :     {
    1141          573 :         Constraint *constr = lfirst(listptr);
    1142              : 
    1143              :         /* it must be a Constraint, per check above */
    1144              : 
    1145          573 :         switch (constr->contype)
    1146              :         {
    1147          407 :             case CONSTR_CHECK:
    1148          407 :                 domainAddCheckConstraint(address.objectId, domainNamespace,
    1149              :                                          basetypeoid, basetypeMod,
    1150              :                                          constr, domainName, NULL);
    1151          407 :                 break;
    1152              : 
    1153           60 :             case CONSTR_NOTNULL:
    1154           60 :                 domainAddNotNullConstraint(address.objectId, domainNamespace,
    1155              :                                            basetypeoid, basetypeMod,
    1156              :                                            constr, domainName, NULL);
    1157           60 :                 break;
    1158              : 
    1159              :                 /* Other constraint types were fully processed above */
    1160              : 
    1161          106 :             default:
    1162          106 :                 break;
    1163              :         }
    1164              : 
    1165              :         /* CCI so we can detect duplicate constraint names */
    1166          573 :         CommandCounterIncrement();
    1167              :     }
    1168              : 
    1169              :     /*
    1170              :      * Now we can clean up.
    1171              :      */
    1172          917 :     ReleaseSysCache(typeTup);
    1173              : 
    1174          917 :     return address;
    1175              : }
    1176              : 
    1177              : 
    1178              : /*
    1179              :  * DefineEnum
    1180              :  *      Registers a new enum.
    1181              :  */
    1182              : ObjectAddress
    1183          251 : DefineEnum(CreateEnumStmt *stmt)
    1184              : {
    1185              :     char       *enumName;
    1186              :     char       *enumArrayName;
    1187              :     Oid         enumNamespace;
    1188              :     AclResult   aclresult;
    1189              :     Oid         old_type_oid;
    1190              :     Oid         enumArrayOid;
    1191              :     ObjectAddress enumTypeAddr;
    1192              : 
    1193              :     /* Convert list of names to a name and namespace */
    1194          251 :     enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
    1195              :                                                       &enumName);
    1196              : 
    1197              :     /* Check we have creation rights in target namespace */
    1198          251 :     aclresult = object_aclcheck(NamespaceRelationId, enumNamespace, GetUserId(), ACL_CREATE);
    1199          251 :     if (aclresult != ACLCHECK_OK)
    1200            0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
    1201            0 :                        get_namespace_name(enumNamespace));
    1202              : 
    1203              :     /*
    1204              :      * Check for collision with an existing type name.  If there is one and
    1205              :      * it's an autogenerated array, we can rename it out of the way.
    1206              :      */
    1207          251 :     old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
    1208              :                                    CStringGetDatum(enumName),
    1209              :                                    ObjectIdGetDatum(enumNamespace));
    1210          251 :     if (OidIsValid(old_type_oid))
    1211              :     {
    1212            5 :         if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
    1213            0 :             ereport(ERROR,
    1214              :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    1215              :                      errmsg("type \"%s\" already exists", enumName)));
    1216              :     }
    1217              : 
    1218              :     /* Allocate OID for array type */
    1219          251 :     enumArrayOid = AssignTypeArrayOid();
    1220              : 
    1221              :     /* Create the pg_type entry */
    1222              :     enumTypeAddr =
    1223          251 :         TypeCreate(InvalidOid,  /* no predetermined type OID */
    1224              :                    enumName,    /* type name */
    1225              :                    enumNamespace,   /* namespace */
    1226              :                    InvalidOid,  /* relation oid (n/a here) */
    1227              :                    0,           /* relation kind (ditto) */
    1228              :                    GetUserId(), /* owner's ID */
    1229              :                    sizeof(Oid), /* internal size */
    1230              :                    TYPTYPE_ENUM,    /* type-type (enum type) */
    1231              :                    TYPCATEGORY_ENUM,    /* type-category (enum type) */
    1232              :                    false,       /* enum types are never preferred */
    1233              :                    DEFAULT_TYPDELIM,    /* array element delimiter */
    1234              :                    F_ENUM_IN,   /* input procedure */
    1235              :                    F_ENUM_OUT,  /* output procedure */
    1236              :                    F_ENUM_RECV, /* receive procedure */
    1237              :                    F_ENUM_SEND, /* send procedure */
    1238              :                    InvalidOid,  /* typmodin procedure - none */
    1239              :                    InvalidOid,  /* typmodout procedure - none */
    1240              :                    InvalidOid,  /* analyze procedure - default */
    1241              :                    InvalidOid,  /* subscript procedure - none */
    1242              :                    InvalidOid,  /* element type ID */
    1243              :                    false,       /* this is not an array type */
    1244              :                    enumArrayOid,    /* array type we are about to create */
    1245              :                    InvalidOid,  /* base type ID (only for domains) */
    1246              :                    NULL,        /* never a default type value */
    1247              :                    NULL,        /* binary default isn't sent either */
    1248              :                    true,        /* always passed by value */
    1249              :                    TYPALIGN_INT,    /* int alignment */
    1250              :                    TYPSTORAGE_PLAIN,    /* TOAST strategy always plain */
    1251              :                    -1,          /* typMod (Domains only) */
    1252              :                    0,           /* Array dimensions of typbasetype */
    1253              :                    false,       /* Type NOT NULL */
    1254              :                    InvalidOid); /* type's collation */
    1255              : 
    1256              :     /* Enter the enum's values into pg_enum */
    1257          250 :     EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
    1258              : 
    1259              :     /*
    1260              :      * Create the array type that goes with it.
    1261              :      */
    1262          246 :     enumArrayName = makeArrayTypeName(enumName, enumNamespace);
    1263              : 
    1264          246 :     TypeCreate(enumArrayOid,    /* force assignment of this type OID */
    1265              :                enumArrayName,   /* type name */
    1266              :                enumNamespace,   /* namespace */
    1267              :                InvalidOid,      /* relation oid (n/a here) */
    1268              :                0,               /* relation kind (ditto) */
    1269              :                GetUserId(),     /* owner's ID */
    1270              :                -1,              /* internal size (always varlena) */
    1271              :                TYPTYPE_BASE,    /* type-type (base type) */
    1272              :                TYPCATEGORY_ARRAY,   /* type-category (array) */
    1273              :                false,           /* array types are never preferred */
    1274              :                DEFAULT_TYPDELIM,    /* array element delimiter */
    1275              :                F_ARRAY_IN,      /* input procedure */
    1276              :                F_ARRAY_OUT,     /* output procedure */
    1277              :                F_ARRAY_RECV,    /* receive procedure */
    1278              :                F_ARRAY_SEND,    /* send procedure */
    1279              :                InvalidOid,      /* typmodin procedure - none */
    1280              :                InvalidOid,      /* typmodout procedure - none */
    1281              :                F_ARRAY_TYPANALYZE,  /* analyze procedure */
    1282              :                F_ARRAY_SUBSCRIPT_HANDLER,   /* array subscript procedure */
    1283              :                enumTypeAddr.objectId,   /* element type ID */
    1284              :                true,            /* yes this is an array type */
    1285              :                InvalidOid,      /* no further array type */
    1286              :                InvalidOid,      /* base type ID */
    1287              :                NULL,            /* never a default type value */
    1288              :                NULL,            /* binary default isn't sent either */
    1289              :                false,           /* never passed by value */
    1290              :                TYPALIGN_INT,    /* enums have int align, so do their arrays */
    1291              :                TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
    1292              :                -1,              /* typMod (Domains only) */
    1293              :                0,               /* Array dimensions of typbasetype */
    1294              :                false,           /* Type NOT NULL */
    1295              :                InvalidOid);     /* type's collation */
    1296              : 
    1297          246 :     pfree(enumArrayName);
    1298              : 
    1299          246 :     return enumTypeAddr;
    1300              : }
    1301              : 
    1302              : /*
    1303              :  * AlterEnum
    1304              :  *      Adds a new label to an existing enum.
    1305              :  */
    1306              : ObjectAddress
    1307          246 : AlterEnum(AlterEnumStmt *stmt)
    1308              : {
    1309              :     Oid         enum_type_oid;
    1310              :     TypeName   *typename;
    1311              :     HeapTuple   tup;
    1312              :     ObjectAddress address;
    1313              : 
    1314              :     /* Make a TypeName so we can use standard type lookup machinery */
    1315          246 :     typename = makeTypeNameFromNameList(stmt->typeName);
    1316          246 :     enum_type_oid = typenameTypeId(NULL, typename);
    1317              : 
    1318          246 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
    1319          246 :     if (!HeapTupleIsValid(tup))
    1320            0 :         elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
    1321              : 
    1322              :     /* Check it's an enum and check user has permission to ALTER the enum */
    1323          246 :     checkEnumOwner(tup);
    1324              : 
    1325          246 :     ReleaseSysCache(tup);
    1326              : 
    1327          246 :     if (stmt->oldVal)
    1328              :     {
    1329              :         /* Rename an existing label */
    1330           16 :         RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
    1331              :     }
    1332              :     else
    1333              :     {
    1334              :         /* Add a new label */
    1335          230 :         AddEnumLabel(enum_type_oid, stmt->newVal,
    1336          230 :                      stmt->newValNeighbor, stmt->newValIsAfter,
    1337          230 :                      stmt->skipIfNewValExists);
    1338              :     }
    1339              : 
    1340          226 :     InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
    1341              : 
    1342          226 :     ObjectAddressSet(address, TypeRelationId, enum_type_oid);
    1343              : 
    1344          226 :     return address;
    1345              : }
    1346              : 
    1347              : 
    1348              : /*
    1349              :  * checkEnumOwner
    1350              :  *
    1351              :  * Check that the type is actually an enum and that the current user
    1352              :  * has permission to do ALTER TYPE on it.  Throw an error if not.
    1353              :  */
    1354              : static void
    1355          246 : checkEnumOwner(HeapTuple tup)
    1356              : {
    1357          246 :     Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
    1358              : 
    1359              :     /* Check that this is actually an enum */
    1360          246 :     if (typTup->typtype != TYPTYPE_ENUM)
    1361            0 :         ereport(ERROR,
    1362              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1363              :                  errmsg("%s is not an enum",
    1364              :                         format_type_be(typTup->oid))));
    1365              : 
    1366              :     /* Permission check: must own type */
    1367          246 :     if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
    1368            0 :         aclcheck_error_type(ACLCHECK_NOT_OWNER, typTup->oid);
    1369          246 : }
    1370              : 
    1371              : 
    1372              : /*
    1373              :  * DefineRange
    1374              :  *      Registers a new range type.
    1375              :  *
    1376              :  * Perhaps it might be worthwhile to set pg_type.typelem to the base type,
    1377              :  * and likewise on multiranges to set it to the range type. But having a
    1378              :  * non-zero typelem is treated elsewhere as a synonym for being an array,
    1379              :  * and users might have queries with that same assumption.
    1380              :  */
    1381              : ObjectAddress
    1382          150 : DefineRange(ParseState *pstate, CreateRangeStmt *stmt)
    1383              : {
    1384              :     char       *typeName;
    1385              :     Oid         typeNamespace;
    1386              :     Oid         typoid;
    1387              :     char       *rangeArrayName;
    1388          150 :     char       *multirangeTypeName = NULL;
    1389              :     char       *multirangeArrayName;
    1390          150 :     Oid         multirangeNamespace = InvalidOid;
    1391              :     Oid         rangeArrayOid;
    1392              :     Oid         multirangeOid;
    1393              :     Oid         multirangeArrayOid;
    1394          150 :     Oid         rangeSubtype = InvalidOid;
    1395          150 :     List       *rangeSubOpclassName = NIL;
    1396          150 :     List       *rangeCollationName = NIL;
    1397          150 :     List       *rangeCanonicalName = NIL;
    1398          150 :     List       *rangeSubtypeDiffName = NIL;
    1399              :     Oid         rangeSubOpclass;
    1400              :     Oid         rangeCollation;
    1401              :     regproc     rangeCanonical;
    1402              :     regproc     rangeSubtypeDiff;
    1403              :     int16       subtyplen;
    1404              :     bool        subtypbyval;
    1405              :     char        subtypalign;
    1406              :     char        alignment;
    1407              :     AclResult   aclresult;
    1408              :     ListCell   *lc;
    1409              :     ObjectAddress address;
    1410              :     ObjectAddress mltrngaddress PG_USED_FOR_ASSERTS_ONLY;
    1411          150 :     Oid         rangeConstruct2Oid = InvalidOid;
    1412          150 :     Oid         rangeConstruct3Oid = InvalidOid;
    1413          150 :     Oid         mltrngConstruct0Oid = InvalidOid;
    1414          150 :     Oid         mltrngConstruct1Oid = InvalidOid;
    1415          150 :     Oid         mltrngConstruct2Oid = InvalidOid;
    1416              :     Oid         castFuncOid;
    1417              : 
    1418              :     /* Convert list of names to a name and namespace */
    1419          150 :     typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
    1420              :                                                       &typeName);
    1421              : 
    1422              :     /* Check we have creation rights in target namespace */
    1423          150 :     aclresult = object_aclcheck(NamespaceRelationId, typeNamespace, GetUserId(), ACL_CREATE);
    1424          150 :     if (aclresult != ACLCHECK_OK)
    1425            0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
    1426            0 :                        get_namespace_name(typeNamespace));
    1427              : 
    1428              :     /*
    1429              :      * Look to see if type already exists.
    1430              :      */
    1431          150 :     typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
    1432              :                              CStringGetDatum(typeName),
    1433              :                              ObjectIdGetDatum(typeNamespace));
    1434              : 
    1435              :     /*
    1436              :      * If it's not a shell, see if it's an autogenerated array type, and if so
    1437              :      * rename it out of the way.
    1438              :      */
    1439          150 :     if (OidIsValid(typoid) && get_typisdefined(typoid))
    1440              :     {
    1441            0 :         if (moveArrayTypeName(typoid, typeName, typeNamespace))
    1442            0 :             typoid = InvalidOid;
    1443              :         else
    1444            0 :             ereport(ERROR,
    1445              :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    1446              :                      errmsg("type \"%s\" already exists", typeName)));
    1447              :     }
    1448              : 
    1449              :     /*
    1450              :      * Unlike DefineType(), we don't insist on a shell type existing first, as
    1451              :      * it's only needed if the user wants to specify a canonical function.
    1452              :      */
    1453              : 
    1454              :     /* Extract the parameters from the parameter list */
    1455          392 :     foreach(lc, stmt->params)
    1456              :     {
    1457          246 :         DefElem    *defel = (DefElem *) lfirst(lc);
    1458              : 
    1459          246 :         if (strcmp(defel->defname, "subtype") == 0)
    1460              :         {
    1461          150 :             if (OidIsValid(rangeSubtype))
    1462            0 :                 errorConflictingDefElem(defel, pstate);
    1463              :             /* we can look up the subtype name immediately */
    1464          150 :             rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
    1465              :         }
    1466           96 :         else if (strcmp(defel->defname, "subtype_opclass") == 0)
    1467              :         {
    1468            5 :             if (rangeSubOpclassName != NIL)
    1469            0 :                 errorConflictingDefElem(defel, pstate);
    1470            5 :             rangeSubOpclassName = defGetQualifiedName(defel);
    1471              :         }
    1472           91 :         else if (strcmp(defel->defname, "collation") == 0)
    1473              :         {
    1474           46 :             if (rangeCollationName != NIL)
    1475            0 :                 errorConflictingDefElem(defel, pstate);
    1476           46 :             rangeCollationName = defGetQualifiedName(defel);
    1477              :         }
    1478           45 :         else if (strcmp(defel->defname, "canonical") == 0)
    1479              :         {
    1480            0 :             if (rangeCanonicalName != NIL)
    1481            0 :                 errorConflictingDefElem(defel, pstate);
    1482            0 :             rangeCanonicalName = defGetQualifiedName(defel);
    1483              :         }
    1484           45 :         else if (strcmp(defel->defname, "subtype_diff") == 0)
    1485              :         {
    1486           14 :             if (rangeSubtypeDiffName != NIL)
    1487            0 :                 errorConflictingDefElem(defel, pstate);
    1488           14 :             rangeSubtypeDiffName = defGetQualifiedName(defel);
    1489              :         }
    1490           31 :         else if (strcmp(defel->defname, "multirange_type_name") == 0)
    1491              :         {
    1492           31 :             if (multirangeTypeName != NULL)
    1493            0 :                 errorConflictingDefElem(defel, pstate);
    1494              :             /* we can look up the subtype name immediately */
    1495           31 :             multirangeNamespace = QualifiedNameGetCreationNamespace(defGetQualifiedName(defel),
    1496              :                                                                     &multirangeTypeName);
    1497              : 
    1498              :             /* Check we have creation rights in target namespace */
    1499           31 :             aclresult = object_aclcheck(NamespaceRelationId, multirangeNamespace,
    1500              :                                         GetUserId(), ACL_CREATE);
    1501           31 :             if (aclresult != ACLCHECK_OK)
    1502            4 :                 aclcheck_error(aclresult, OBJECT_SCHEMA,
    1503            4 :                                get_namespace_name(multirangeNamespace));
    1504              :         }
    1505              :         else
    1506            0 :             ereport(ERROR,
    1507              :                     (errcode(ERRCODE_SYNTAX_ERROR),
    1508              :                      errmsg("type attribute \"%s\" not recognized",
    1509              :                             defel->defname)));
    1510              :     }
    1511              : 
    1512              :     /* Must have a subtype */
    1513          146 :     if (!OidIsValid(rangeSubtype))
    1514            0 :         ereport(ERROR,
    1515              :                 (errcode(ERRCODE_SYNTAX_ERROR),
    1516              :                  errmsg("type attribute \"subtype\" is required")));
    1517              :     /* disallow ranges of pseudotypes */
    1518          146 :     if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
    1519            0 :         ereport(ERROR,
    1520              :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    1521              :                  errmsg("range subtype cannot be %s",
    1522              :                         format_type_be(rangeSubtype))));
    1523              : 
    1524              :     /* Identify subopclass */
    1525          146 :     rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
    1526              : 
    1527              :     /* Identify collation to use, if any */
    1528          146 :     if (type_is_collatable(rangeSubtype))
    1529              :     {
    1530           51 :         if (rangeCollationName != NIL)
    1531           46 :             rangeCollation = get_collation_oid(rangeCollationName, false);
    1532              :         else
    1533            5 :             rangeCollation = get_typcollation(rangeSubtype);
    1534              :     }
    1535              :     else
    1536              :     {
    1537           95 :         if (rangeCollationName != NIL)
    1538            0 :             ereport(ERROR,
    1539              :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1540              :                      errmsg("range collation specified but subtype does not support collation")));
    1541           95 :         rangeCollation = InvalidOid;
    1542              :     }
    1543              : 
    1544              :     /* Identify support functions, if provided */
    1545          146 :     if (rangeCanonicalName != NIL)
    1546              :     {
    1547            0 :         if (!OidIsValid(typoid))
    1548            0 :             ereport(ERROR,
    1549              :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1550              :                      errmsg("cannot specify a canonical function without a pre-created shell type"),
    1551              :                      errhint("Create the type as a shell type, then create its canonicalization function, then do a full CREATE TYPE.")));
    1552            0 :         rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
    1553              :                                                     typoid);
    1554              :     }
    1555              :     else
    1556          146 :         rangeCanonical = InvalidOid;
    1557              : 
    1558          146 :     if (rangeSubtypeDiffName != NIL)
    1559           14 :         rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
    1560              :                                                         rangeSubtype);
    1561              :     else
    1562          132 :         rangeSubtypeDiff = InvalidOid;
    1563              : 
    1564          142 :     get_typlenbyvalalign(rangeSubtype,
    1565              :                          &subtyplen, &subtypbyval, &subtypalign);
    1566              : 
    1567              :     /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for ranges */
    1568          142 :     alignment = (subtypalign == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
    1569              : 
    1570              :     /* Allocate OID for array type, its multirange, and its multirange array */
    1571          142 :     rangeArrayOid = AssignTypeArrayOid();
    1572          142 :     multirangeOid = AssignTypeMultirangeOid();
    1573          142 :     multirangeArrayOid = AssignTypeMultirangeArrayOid();
    1574              : 
    1575              :     /* Create the pg_type entry */
    1576              :     address =
    1577          142 :         TypeCreate(InvalidOid,  /* no predetermined type OID */
    1578              :                    typeName,    /* type name */
    1579              :                    typeNamespace,   /* namespace */
    1580              :                    InvalidOid,  /* relation oid (n/a here) */
    1581              :                    0,           /* relation kind (ditto) */
    1582              :                    GetUserId(), /* owner's ID */
    1583              :                    -1,          /* internal size (always varlena) */
    1584              :                    TYPTYPE_RANGE,   /* type-type (range type) */
    1585              :                    TYPCATEGORY_RANGE,   /* type-category (range type) */
    1586              :                    false,       /* range types are never preferred */
    1587              :                    DEFAULT_TYPDELIM,    /* array element delimiter */
    1588              :                    F_RANGE_IN,  /* input procedure */
    1589              :                    F_RANGE_OUT, /* output procedure */
    1590              :                    F_RANGE_RECV,    /* receive procedure */
    1591              :                    F_RANGE_SEND,    /* send procedure */
    1592              :                    InvalidOid,  /* typmodin procedure - none */
    1593              :                    InvalidOid,  /* typmodout procedure - none */
    1594              :                    F_RANGE_TYPANALYZE,  /* analyze procedure */
    1595              :                    InvalidOid,  /* subscript procedure - none */
    1596              :                    InvalidOid,  /* element type ID - none */
    1597              :                    false,       /* this is not an array type */
    1598              :                    rangeArrayOid,   /* array type we are about to create */
    1599              :                    InvalidOid,  /* base type ID (only for domains) */
    1600              :                    NULL,        /* never a default type value */
    1601              :                    NULL,        /* no binary form available either */
    1602              :                    false,       /* never passed by value */
    1603              :                    alignment,   /* alignment */
    1604              :                    TYPSTORAGE_EXTENDED, /* TOAST strategy (always extended) */
    1605              :                    -1,          /* typMod (Domains only) */
    1606              :                    0,           /* Array dimensions of typbasetype */
    1607              :                    false,       /* Type NOT NULL */
    1608              :                    InvalidOid); /* type's collation (ranges never have one) */
    1609              :     Assert(typoid == InvalidOid || typoid == address.objectId);
    1610          142 :     typoid = address.objectId;
    1611              : 
    1612              :     /* Create the multirange that goes with it */
    1613          142 :     if (multirangeTypeName)
    1614              :     {
    1615              :         Oid         old_typoid;
    1616              : 
    1617              :         /*
    1618              :          * Look to see if multirange type already exists.
    1619              :          */
    1620           27 :         old_typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
    1621              :                                      CStringGetDatum(multirangeTypeName),
    1622              :                                      ObjectIdGetDatum(multirangeNamespace));
    1623              : 
    1624              :         /*
    1625              :          * If it's not a shell, see if it's an autogenerated array type, and
    1626              :          * if so rename it out of the way.
    1627              :          */
    1628           27 :         if (OidIsValid(old_typoid) && get_typisdefined(old_typoid))
    1629              :         {
    1630            8 :             if (!moveArrayTypeName(old_typoid, multirangeTypeName, multirangeNamespace))
    1631            4 :                 ereport(ERROR,
    1632              :                         (errcode(ERRCODE_DUPLICATE_OBJECT),
    1633              :                          errmsg("type \"%s\" already exists", multirangeTypeName)));
    1634              :         }
    1635              :     }
    1636              :     else
    1637              :     {
    1638              :         /* Generate multirange name automatically */
    1639          115 :         multirangeNamespace = typeNamespace;
    1640          115 :         multirangeTypeName = makeMultirangeTypeName(typeName, multirangeNamespace);
    1641              :     }
    1642              : 
    1643              :     mltrngaddress =
    1644          130 :         TypeCreate(multirangeOid,   /* force assignment of this type OID */
    1645              :                    multirangeTypeName,  /* type name */
    1646              :                    multirangeNamespace, /* namespace */
    1647              :                    InvalidOid,  /* relation oid (n/a here) */
    1648              :                    0,           /* relation kind (ditto) */
    1649              :                    GetUserId(), /* owner's ID */
    1650              :                    -1,          /* internal size (always varlena) */
    1651              :                    TYPTYPE_MULTIRANGE,  /* type-type (multirange type) */
    1652              :                    TYPCATEGORY_RANGE,   /* type-category (range type) */
    1653              :                    false,       /* multirange types are never preferred */
    1654              :                    DEFAULT_TYPDELIM,    /* array element delimiter */
    1655              :                    F_MULTIRANGE_IN, /* input procedure */
    1656              :                    F_MULTIRANGE_OUT,    /* output procedure */
    1657              :                    F_MULTIRANGE_RECV,   /* receive procedure */
    1658              :                    F_MULTIRANGE_SEND,   /* send procedure */
    1659              :                    InvalidOid,  /* typmodin procedure - none */
    1660              :                    InvalidOid,  /* typmodout procedure - none */
    1661              :                    F_MULTIRANGE_TYPANALYZE, /* analyze procedure */
    1662              :                    InvalidOid,  /* subscript procedure - none */
    1663              :                    InvalidOid,  /* element type ID - none */
    1664              :                    false,       /* this is not an array type */
    1665              :                    multirangeArrayOid,  /* array type we are about to create */
    1666              :                    InvalidOid,  /* base type ID (only for domains) */
    1667              :                    NULL,        /* never a default type value */
    1668              :                    NULL,        /* no binary form available either */
    1669              :                    false,       /* never passed by value */
    1670              :                    alignment,   /* alignment */
    1671              :                    'x',         /* TOAST strategy (always extended) */
    1672              :                    -1,          /* typMod (Domains only) */
    1673              :                    0,           /* Array dimensions of typbasetype */
    1674              :                    false,       /* Type NOT NULL */
    1675              :                    InvalidOid); /* type's collation (ranges never have one) */
    1676              :     Assert(multirangeOid == mltrngaddress.objectId);
    1677              : 
    1678              :     /*
    1679              :      * Create the array type that goes with it.
    1680              :      */
    1681          130 :     rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
    1682              : 
    1683          130 :     TypeCreate(rangeArrayOid,   /* force assignment of this type OID */
    1684              :                rangeArrayName,  /* type name */
    1685              :                typeNamespace,   /* namespace */
    1686              :                InvalidOid,      /* relation oid (n/a here) */
    1687              :                0,               /* relation kind (ditto) */
    1688              :                GetUserId(),     /* owner's ID */
    1689              :                -1,              /* internal size (always varlena) */
    1690              :                TYPTYPE_BASE,    /* type-type (base type) */
    1691              :                TYPCATEGORY_ARRAY,   /* type-category (array) */
    1692              :                false,           /* array types are never preferred */
    1693              :                DEFAULT_TYPDELIM,    /* array element delimiter */
    1694              :                F_ARRAY_IN,      /* input procedure */
    1695              :                F_ARRAY_OUT,     /* output procedure */
    1696              :                F_ARRAY_RECV,    /* receive procedure */
    1697              :                F_ARRAY_SEND,    /* send procedure */
    1698              :                InvalidOid,      /* typmodin procedure - none */
    1699              :                InvalidOid,      /* typmodout procedure - none */
    1700              :                F_ARRAY_TYPANALYZE,  /* analyze procedure */
    1701              :                F_ARRAY_SUBSCRIPT_HANDLER,   /* array subscript procedure */
    1702              :                typoid,          /* element type ID */
    1703              :                true,            /* yes this is an array type */
    1704              :                InvalidOid,      /* no further array type */
    1705              :                InvalidOid,      /* base type ID */
    1706              :                NULL,            /* never a default type value */
    1707              :                NULL,            /* binary default isn't sent either */
    1708              :                false,           /* never passed by value */
    1709              :                alignment,       /* alignment - same as range's */
    1710              :                TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
    1711              :                -1,              /* typMod (Domains only) */
    1712              :                0,               /* Array dimensions of typbasetype */
    1713              :                false,           /* Type NOT NULL */
    1714              :                InvalidOid);     /* typcollation */
    1715              : 
    1716          130 :     pfree(rangeArrayName);
    1717              : 
    1718              :     /* Create the multirange's array type */
    1719              : 
    1720          130 :     multirangeArrayName = makeArrayTypeName(multirangeTypeName, typeNamespace);
    1721              : 
    1722          130 :     TypeCreate(multirangeArrayOid,  /* force assignment of this type OID */
    1723              :                multirangeArrayName, /* type name */
    1724              :                multirangeNamespace, /* namespace */
    1725              :                InvalidOid,      /* relation oid (n/a here) */
    1726              :                0,               /* relation kind (ditto) */
    1727              :                GetUserId(),     /* owner's ID */
    1728              :                -1,              /* internal size (always varlena) */
    1729              :                TYPTYPE_BASE,    /* type-type (base type) */
    1730              :                TYPCATEGORY_ARRAY,   /* type-category (array) */
    1731              :                false,           /* array types are never preferred */
    1732              :                DEFAULT_TYPDELIM,    /* array element delimiter */
    1733              :                F_ARRAY_IN,      /* input procedure */
    1734              :                F_ARRAY_OUT,     /* output procedure */
    1735              :                F_ARRAY_RECV,    /* receive procedure */
    1736              :                F_ARRAY_SEND,    /* send procedure */
    1737              :                InvalidOid,      /* typmodin procedure - none */
    1738              :                InvalidOid,      /* typmodout procedure - none */
    1739              :                F_ARRAY_TYPANALYZE,  /* analyze procedure */
    1740              :                F_ARRAY_SUBSCRIPT_HANDLER,   /* array subscript procedure */
    1741              :                multirangeOid,   /* element type ID */
    1742              :                true,            /* yes this is an array type */
    1743              :                InvalidOid,      /* no further array type */
    1744              :                InvalidOid,      /* base type ID */
    1745              :                NULL,            /* never a default type value */
    1746              :                NULL,            /* binary default isn't sent either */
    1747              :                false,           /* never passed by value */
    1748              :                alignment,       /* alignment - same as range's */
    1749              :                'x',             /* ARRAY is always toastable */
    1750              :                -1,              /* typMod (Domains only) */
    1751              :                0,               /* Array dimensions of typbasetype */
    1752              :                false,           /* Type NOT NULL */
    1753              :                InvalidOid);     /* typcollation */
    1754              : 
    1755              :     /* Ensure these new types are visible to ProcedureCreate */
    1756          130 :     CommandCounterIncrement();
    1757              : 
    1758              :     /* And create the constructor functions for this range type */
    1759          130 :     makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype,
    1760              :                           &rangeConstruct2Oid, &rangeConstruct3Oid);
    1761          130 :     makeMultirangeConstructors(multirangeTypeName, typeNamespace,
    1762              :                                multirangeOid, typoid, rangeArrayOid,
    1763              :                                &mltrngConstruct0Oid, &mltrngConstruct1Oid, &mltrngConstruct2Oid);
    1764          130 :     castFuncOid = mltrngConstruct1Oid;
    1765              : 
    1766              :     /* Create the entry in pg_range */
    1767          130 :     RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
    1768              :                 rangeCanonical, rangeSubtypeDiff, multirangeOid,
    1769              :                 rangeConstruct2Oid, rangeConstruct3Oid,
    1770              :                 mltrngConstruct0Oid, mltrngConstruct1Oid, mltrngConstruct2Oid);
    1771              : 
    1772              :     /* Create cast from the range type to its multirange type */
    1773          130 :     CastCreate(typoid, multirangeOid, castFuncOid, InvalidOid, InvalidOid,
    1774              :                COERCION_CODE_EXPLICIT, COERCION_METHOD_FUNCTION,
    1775              :                DEPENDENCY_INTERNAL);
    1776              : 
    1777          130 :     pfree(multirangeArrayName);
    1778              : 
    1779          130 :     return address;
    1780              : }
    1781              : 
    1782              : /*
    1783              :  * Because there may exist several range types over the same subtype, the
    1784              :  * range type can't be uniquely determined from the subtype.  So it's
    1785              :  * impossible to define a polymorphic constructor; we have to generate new
    1786              :  * constructor functions explicitly for each range type.
    1787              :  *
    1788              :  * We actually define 2 functions, with 2 through 3 arguments.  This is just
    1789              :  * to offer more convenience for the user.
    1790              :  *
    1791              :  * The OIDs of the created functions are returned through the pointer
    1792              :  * arguments.
    1793              :  */
    1794              : static void
    1795          130 : makeRangeConstructors(const char *name, Oid namespace,
    1796              :                       Oid rangeOid, Oid subtype,
    1797              :                       Oid *rangeConstruct2_p, Oid *rangeConstruct3_p)
    1798              : {
    1799              :     static const char *const prosrc[2] = {"range_constructor2",
    1800              :     "range_constructor3"};
    1801              :     static const int pronargs[2] = {2, 3};
    1802              : 
    1803              :     Oid         constructorArgTypes[3];
    1804              :     ObjectAddress myself,
    1805              :                 referenced;
    1806              :     int         i;
    1807              : 
    1808          130 :     constructorArgTypes[0] = subtype;
    1809          130 :     constructorArgTypes[1] = subtype;
    1810          130 :     constructorArgTypes[2] = TEXTOID;
    1811              : 
    1812          130 :     referenced.classId = TypeRelationId;
    1813          130 :     referenced.objectId = rangeOid;
    1814          130 :     referenced.objectSubId = 0;
    1815              : 
    1816          390 :     for (i = 0; i < lengthof(prosrc); i++)
    1817              :     {
    1818              :         oidvector  *constructorArgTypesVector;
    1819              : 
    1820          260 :         constructorArgTypesVector = buildoidvector(constructorArgTypes,
    1821          260 :                                                    pronargs[i]);
    1822              : 
    1823          260 :         myself = ProcedureCreate(name,  /* name: same as range type */
    1824              :                                  namespace, /* namespace */
    1825              :                                  false, /* replace */
    1826              :                                  false, /* returns set */
    1827              :                                  rangeOid,  /* return type */
    1828              :                                  BOOTSTRAP_SUPERUSERID, /* proowner */
    1829              :                                  INTERNALlanguageId,    /* language */
    1830              :                                  F_FMGR_INTERNAL_VALIDATOR, /* language validator */
    1831          260 :                                  prosrc[i], /* prosrc */
    1832              :                                  NULL,  /* probin */
    1833              :                                  NULL,  /* prosqlbody */
    1834              :                                  PROKIND_FUNCTION,
    1835              :                                  false, /* security_definer */
    1836              :                                  false, /* leakproof */
    1837              :                                  false, /* isStrict */
    1838              :                                  PROVOLATILE_IMMUTABLE, /* volatility */
    1839              :                                  PROPARALLEL_SAFE,  /* parallel safety */
    1840              :                                  constructorArgTypesVector, /* parameterTypes */
    1841              :                                  PointerGetDatum(NULL), /* allParameterTypes */
    1842              :                                  PointerGetDatum(NULL), /* parameterModes */
    1843              :                                  PointerGetDatum(NULL), /* parameterNames */
    1844              :                                  NIL,   /* parameterDefaults */
    1845              :                                  PointerGetDatum(NULL), /* trftypes */
    1846              :                                  NIL,   /* trfoids */
    1847              :                                  PointerGetDatum(NULL), /* proconfig */
    1848              :                                  InvalidOid,    /* prosupport */
    1849              :                                  1.0,   /* procost */
    1850              :                                  0.0);  /* prorows */
    1851              : 
    1852              :         /*
    1853              :          * Make the constructors internally-dependent on the range type so
    1854              :          * that they go away silently when the type is dropped.  Note that
    1855              :          * pg_dump depends on this choice to avoid dumping the constructors.
    1856              :          */
    1857          260 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
    1858              : 
    1859          260 :         if (pronargs[i] == 2)
    1860          130 :             *rangeConstruct2_p = myself.objectId;
    1861          130 :         else if (pronargs[i] == 3)
    1862          130 :             *rangeConstruct3_p = myself.objectId;
    1863              :     }
    1864          130 : }
    1865              : 
    1866              : /*
    1867              :  * We make a separate multirange constructor for each range type
    1868              :  * so its name can include the base type, like range constructors do.
    1869              :  * If we had an anyrangearray polymorphic type we could use it here,
    1870              :  * but since each type has its own constructor name there's no need.
    1871              :  *
    1872              :  * The OIDs of the created functions are returned through the pointer
    1873              :  * arguments.
    1874              :  */
    1875              : static void
    1876          130 : makeMultirangeConstructors(const char *name, Oid namespace,
    1877              :                            Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid,
    1878              :                            Oid *mltrngConstruct0_p, Oid *mltrngConstruct1_p, Oid *mltrngConstruct2_p)
    1879              : {
    1880              :     ObjectAddress myself,
    1881              :                 referenced;
    1882              :     oidvector  *argtypes;
    1883              :     Datum       allParamTypes;
    1884              :     ArrayType  *allParameterTypes;
    1885              :     Datum       paramModes;
    1886              :     ArrayType  *parameterModes;
    1887              : 
    1888          130 :     referenced.classId = TypeRelationId;
    1889          130 :     referenced.objectId = multirangeOid;
    1890          130 :     referenced.objectSubId = 0;
    1891              : 
    1892              :     /* 0-arg constructor - for empty multiranges */
    1893          130 :     argtypes = buildoidvector(NULL, 0);
    1894          130 :     myself = ProcedureCreate(name,  /* name: same as multirange type */
    1895              :                              namespace,
    1896              :                              false, /* replace */
    1897              :                              false, /* returns set */
    1898              :                              multirangeOid, /* return type */
    1899              :                              BOOTSTRAP_SUPERUSERID, /* proowner */
    1900              :                              INTERNALlanguageId,    /* language */
    1901              :                              F_FMGR_INTERNAL_VALIDATOR,
    1902              :                              "multirange_constructor0", /* prosrc */
    1903              :                              NULL,  /* probin */
    1904              :                              NULL,  /* prosqlbody */
    1905              :                              PROKIND_FUNCTION,
    1906              :                              false, /* security_definer */
    1907              :                              false, /* leakproof */
    1908              :                              true,  /* isStrict */
    1909              :                              PROVOLATILE_IMMUTABLE, /* volatility */
    1910              :                              PROPARALLEL_SAFE,  /* parallel safety */
    1911              :                              argtypes,  /* parameterTypes */
    1912              :                              PointerGetDatum(NULL), /* allParameterTypes */
    1913              :                              PointerGetDatum(NULL), /* parameterModes */
    1914              :                              PointerGetDatum(NULL), /* parameterNames */
    1915              :                              NIL,   /* parameterDefaults */
    1916              :                              PointerGetDatum(NULL), /* trftypes */
    1917              :                              NIL,   /* trfoids */
    1918              :                              PointerGetDatum(NULL), /* proconfig */
    1919              :                              InvalidOid,    /* prosupport */
    1920              :                              1.0,   /* procost */
    1921              :                              0.0);  /* prorows */
    1922              : 
    1923              :     /*
    1924              :      * Make the constructor internally-dependent on the multirange type so
    1925              :      * that they go away silently when the type is dropped.  Note that pg_dump
    1926              :      * depends on this choice to avoid dumping the constructors.
    1927              :      */
    1928          130 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
    1929          130 :     *mltrngConstruct0_p = myself.objectId;
    1930          130 :     pfree(argtypes);
    1931              : 
    1932              :     /*
    1933              :      * 1-arg constructor - for casts
    1934              :      *
    1935              :      * In theory we shouldn't need both this and the vararg (n-arg)
    1936              :      * constructor, but having a separate 1-arg function lets us define casts
    1937              :      * against it.
    1938              :      */
    1939          130 :     argtypes = buildoidvector(&rangeOid, 1);
    1940          130 :     myself = ProcedureCreate(name,  /* name: same as multirange type */
    1941              :                              namespace,
    1942              :                              false, /* replace */
    1943              :                              false, /* returns set */
    1944              :                              multirangeOid, /* return type */
    1945              :                              BOOTSTRAP_SUPERUSERID, /* proowner */
    1946              :                              INTERNALlanguageId,    /* language */
    1947              :                              F_FMGR_INTERNAL_VALIDATOR,
    1948              :                              "multirange_constructor1", /* prosrc */
    1949              :                              NULL,  /* probin */
    1950              :                              NULL,  /* prosqlbody */
    1951              :                              PROKIND_FUNCTION,
    1952              :                              false, /* security_definer */
    1953              :                              false, /* leakproof */
    1954              :                              true,  /* isStrict */
    1955              :                              PROVOLATILE_IMMUTABLE, /* volatility */
    1956              :                              PROPARALLEL_SAFE,  /* parallel safety */
    1957              :                              argtypes,  /* parameterTypes */
    1958              :                              PointerGetDatum(NULL), /* allParameterTypes */
    1959              :                              PointerGetDatum(NULL), /* parameterModes */
    1960              :                              PointerGetDatum(NULL), /* parameterNames */
    1961              :                              NIL,   /* parameterDefaults */
    1962              :                              PointerGetDatum(NULL), /* trftypes */
    1963              :                              NIL,   /* trfoids */
    1964              :                              PointerGetDatum(NULL), /* proconfig */
    1965              :                              InvalidOid,    /* prosupport */
    1966              :                              1.0,   /* procost */
    1967              :                              0.0);  /* prorows */
    1968              :     /* ditto */
    1969          130 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
    1970          130 :     *mltrngConstruct1_p = myself.objectId;
    1971          130 :     pfree(argtypes);
    1972              : 
    1973              :     /* n-arg constructor - vararg */
    1974          130 :     argtypes = buildoidvector(&rangeArrayOid, 1);
    1975          130 :     allParamTypes = ObjectIdGetDatum(rangeArrayOid);
    1976          130 :     allParameterTypes = construct_array_builtin(&allParamTypes, 1, OIDOID);
    1977          130 :     paramModes = CharGetDatum(FUNC_PARAM_VARIADIC);
    1978          130 :     parameterModes = construct_array_builtin(&paramModes, 1, CHAROID);
    1979          130 :     myself = ProcedureCreate(name,  /* name: same as multirange type */
    1980              :                              namespace,
    1981              :                              false, /* replace */
    1982              :                              false, /* returns set */
    1983              :                              multirangeOid, /* return type */
    1984              :                              BOOTSTRAP_SUPERUSERID, /* proowner */
    1985              :                              INTERNALlanguageId,    /* language */
    1986              :                              F_FMGR_INTERNAL_VALIDATOR,
    1987              :                              "multirange_constructor2", /* prosrc */
    1988              :                              NULL,  /* probin */
    1989              :                              NULL,  /* prosqlbody */
    1990              :                              PROKIND_FUNCTION,
    1991              :                              false, /* security_definer */
    1992              :                              false, /* leakproof */
    1993              :                              true,  /* isStrict */
    1994              :                              PROVOLATILE_IMMUTABLE, /* volatility */
    1995              :                              PROPARALLEL_SAFE,  /* parallel safety */
    1996              :                              argtypes,  /* parameterTypes */
    1997              :                              PointerGetDatum(allParameterTypes),    /* allParameterTypes */
    1998              :                              PointerGetDatum(parameterModes),   /* parameterModes */
    1999              :                              PointerGetDatum(NULL), /* parameterNames */
    2000              :                              NIL,   /* parameterDefaults */
    2001              :                              PointerGetDatum(NULL), /* trftypes */
    2002              :                              NIL,   /* trfoids */
    2003              :                              PointerGetDatum(NULL), /* proconfig */
    2004              :                              InvalidOid,    /* prosupport */
    2005              :                              1.0,   /* procost */
    2006              :                              0.0);  /* prorows */
    2007              :     /* ditto */
    2008          130 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
    2009          130 :     *mltrngConstruct2_p = myself.objectId;
    2010          130 :     pfree(argtypes);
    2011          130 :     pfree(allParameterTypes);
    2012          130 :     pfree(parameterModes);
    2013          130 : }
    2014              : 
    2015              : /*
    2016              :  * Find suitable I/O and other support functions for a type.
    2017              :  *
    2018              :  * typeOid is the type's OID (which will already exist, if only as a shell
    2019              :  * type).
    2020              :  */
    2021              : 
    2022              : static Oid
    2023          129 : findTypeInputFunction(List *procname, Oid typeOid)
    2024              : {
    2025              :     Oid         argList[3];
    2026              :     Oid         procOid;
    2027              :     Oid         procOid2;
    2028              : 
    2029              :     /*
    2030              :      * Input functions can take a single argument of type CSTRING, or three
    2031              :      * arguments (string, typioparam OID, typmod).  Whine about ambiguity if
    2032              :      * both forms exist.
    2033              :      */
    2034          129 :     argList[0] = CSTRINGOID;
    2035          129 :     argList[1] = OIDOID;
    2036          129 :     argList[2] = INT4OID;
    2037              : 
    2038          129 :     procOid = LookupFuncName(procname, 1, argList, true);
    2039          129 :     procOid2 = LookupFuncName(procname, 3, argList, true);
    2040          129 :     if (OidIsValid(procOid))
    2041              :     {
    2042          119 :         if (OidIsValid(procOid2))
    2043            0 :             ereport(ERROR,
    2044              :                     (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
    2045              :                      errmsg("type input function %s has multiple matches",
    2046              :                             NameListToString(procname))));
    2047              :     }
    2048              :     else
    2049              :     {
    2050           10 :         procOid = procOid2;
    2051              :         /* If not found, reference the 1-argument signature in error msg */
    2052           10 :         if (!OidIsValid(procOid))
    2053            0 :             ereport(ERROR,
    2054              :                     (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2055              :                      errmsg("function %s does not exist",
    2056              :                             func_signature_string(procname, 1, NIL, argList))));
    2057              :     }
    2058              : 
    2059              :     /* Input functions must return the target type. */
    2060          129 :     if (get_func_rettype(procOid) != typeOid)
    2061            4 :         ereport(ERROR,
    2062              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2063              :                  errmsg("type input function %s must return type %s",
    2064              :                         NameListToString(procname), format_type_be(typeOid))));
    2065              : 
    2066              :     /*
    2067              :      * Print warnings if any of the type's I/O functions are marked volatile.
    2068              :      * There is a general assumption that I/O functions are stable or
    2069              :      * immutable; this allows us for example to mark record_in/record_out
    2070              :      * stable rather than volatile.  Ideally we would throw errors not just
    2071              :      * warnings here; but since this check is new as of 9.5, and since the
    2072              :      * volatility marking might be just an error-of-omission and not a true
    2073              :      * indication of how the function behaves, we'll let it pass as a warning
    2074              :      * for now.
    2075              :      */
    2076          125 :     if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
    2077            0 :         ereport(WARNING,
    2078              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2079              :                  errmsg("type input function %s should not be volatile",
    2080              :                         NameListToString(procname))));
    2081              : 
    2082          125 :     return procOid;
    2083              : }
    2084              : 
    2085              : static Oid
    2086          125 : findTypeOutputFunction(List *procname, Oid typeOid)
    2087              : {
    2088              :     Oid         argList[1];
    2089              :     Oid         procOid;
    2090              : 
    2091              :     /*
    2092              :      * Output functions always take a single argument of the type and return
    2093              :      * cstring.
    2094              :      */
    2095          125 :     argList[0] = typeOid;
    2096              : 
    2097          125 :     procOid = LookupFuncName(procname, 1, argList, true);
    2098          125 :     if (!OidIsValid(procOid))
    2099            0 :         ereport(ERROR,
    2100              :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2101              :                  errmsg("function %s does not exist",
    2102              :                         func_signature_string(procname, 1, NIL, argList))));
    2103              : 
    2104          125 :     if (get_func_rettype(procOid) != CSTRINGOID)
    2105            0 :         ereport(ERROR,
    2106              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2107              :                  errmsg("type output function %s must return type %s",
    2108              :                         NameListToString(procname), "cstring")));
    2109              : 
    2110              :     /* Just a warning for now, per comments in findTypeInputFunction */
    2111          125 :     if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
    2112            0 :         ereport(WARNING,
    2113              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2114              :                  errmsg("type output function %s should not be volatile",
    2115              :                         NameListToString(procname))));
    2116              : 
    2117          125 :     return procOid;
    2118              : }
    2119              : 
    2120              : static Oid
    2121           24 : findTypeReceiveFunction(List *procname, Oid typeOid)
    2122              : {
    2123              :     Oid         argList[3];
    2124              :     Oid         procOid;
    2125              :     Oid         procOid2;
    2126              : 
    2127              :     /*
    2128              :      * Receive functions can take a single argument of type INTERNAL, or three
    2129              :      * arguments (internal, typioparam OID, typmod).  Whine about ambiguity if
    2130              :      * both forms exist.
    2131              :      */
    2132           24 :     argList[0] = INTERNALOID;
    2133           24 :     argList[1] = OIDOID;
    2134           24 :     argList[2] = INT4OID;
    2135              : 
    2136           24 :     procOid = LookupFuncName(procname, 1, argList, true);
    2137           24 :     procOid2 = LookupFuncName(procname, 3, argList, true);
    2138           24 :     if (OidIsValid(procOid))
    2139              :     {
    2140           18 :         if (OidIsValid(procOid2))
    2141            0 :             ereport(ERROR,
    2142              :                     (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
    2143              :                      errmsg("type receive function %s has multiple matches",
    2144              :                             NameListToString(procname))));
    2145              :     }
    2146              :     else
    2147              :     {
    2148            6 :         procOid = procOid2;
    2149              :         /* If not found, reference the 1-argument signature in error msg */
    2150            6 :         if (!OidIsValid(procOid))
    2151            0 :             ereport(ERROR,
    2152              :                     (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2153              :                      errmsg("function %s does not exist",
    2154              :                             func_signature_string(procname, 1, NIL, argList))));
    2155              :     }
    2156              : 
    2157              :     /* Receive functions must return the target type. */
    2158           24 :     if (get_func_rettype(procOid) != typeOid)
    2159            0 :         ereport(ERROR,
    2160              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2161              :                  errmsg("type receive function %s must return type %s",
    2162              :                         NameListToString(procname), format_type_be(typeOid))));
    2163              : 
    2164              :     /* Just a warning for now, per comments in findTypeInputFunction */
    2165           24 :     if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
    2166            0 :         ereport(WARNING,
    2167              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2168              :                  errmsg("type receive function %s should not be volatile",
    2169              :                         NameListToString(procname))));
    2170              : 
    2171           24 :     return procOid;
    2172              : }
    2173              : 
    2174              : static Oid
    2175           24 : findTypeSendFunction(List *procname, Oid typeOid)
    2176              : {
    2177              :     Oid         argList[1];
    2178              :     Oid         procOid;
    2179              : 
    2180              :     /*
    2181              :      * Send functions always take a single argument of the type and return
    2182              :      * bytea.
    2183              :      */
    2184           24 :     argList[0] = typeOid;
    2185              : 
    2186           24 :     procOid = LookupFuncName(procname, 1, argList, true);
    2187           24 :     if (!OidIsValid(procOid))
    2188            0 :         ereport(ERROR,
    2189              :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2190              :                  errmsg("function %s does not exist",
    2191              :                         func_signature_string(procname, 1, NIL, argList))));
    2192              : 
    2193           24 :     if (get_func_rettype(procOid) != BYTEAOID)
    2194            0 :         ereport(ERROR,
    2195              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2196              :                  errmsg("type send function %s must return type %s",
    2197              :                         NameListToString(procname), "bytea")));
    2198              : 
    2199              :     /* Just a warning for now, per comments in findTypeInputFunction */
    2200           24 :     if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
    2201            0 :         ereport(WARNING,
    2202              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2203              :                  errmsg("type send function %s should not be volatile",
    2204              :                         NameListToString(procname))));
    2205              : 
    2206           24 :     return procOid;
    2207              : }
    2208              : 
    2209              : static Oid
    2210            9 : findTypeTypmodinFunction(List *procname)
    2211              : {
    2212              :     Oid         argList[1];
    2213              :     Oid         procOid;
    2214              : 
    2215              :     /*
    2216              :      * typmodin functions always take one cstring[] argument and return int4.
    2217              :      */
    2218            9 :     argList[0] = CSTRINGARRAYOID;
    2219              : 
    2220            9 :     procOid = LookupFuncName(procname, 1, argList, true);
    2221            9 :     if (!OidIsValid(procOid))
    2222            0 :         ereport(ERROR,
    2223              :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2224              :                  errmsg("function %s does not exist",
    2225              :                         func_signature_string(procname, 1, NIL, argList))));
    2226              : 
    2227            9 :     if (get_func_rettype(procOid) != INT4OID)
    2228            0 :         ereport(ERROR,
    2229              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2230              :                  errmsg("typmod_in function %s must return type %s",
    2231              :                         NameListToString(procname), "integer")));
    2232              : 
    2233              :     /* Just a warning for now, per comments in findTypeInputFunction */
    2234            9 :     if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
    2235            0 :         ereport(WARNING,
    2236              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2237              :                  errmsg("type modifier input function %s should not be volatile",
    2238              :                         NameListToString(procname))));
    2239              : 
    2240            9 :     return procOid;
    2241              : }
    2242              : 
    2243              : static Oid
    2244            9 : findTypeTypmodoutFunction(List *procname)
    2245              : {
    2246              :     Oid         argList[1];
    2247              :     Oid         procOid;
    2248              : 
    2249              :     /*
    2250              :      * typmodout functions always take one int4 argument and return cstring.
    2251              :      */
    2252            9 :     argList[0] = INT4OID;
    2253              : 
    2254            9 :     procOid = LookupFuncName(procname, 1, argList, true);
    2255            9 :     if (!OidIsValid(procOid))
    2256            0 :         ereport(ERROR,
    2257              :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2258              :                  errmsg("function %s does not exist",
    2259              :                         func_signature_string(procname, 1, NIL, argList))));
    2260              : 
    2261            9 :     if (get_func_rettype(procOid) != CSTRINGOID)
    2262            0 :         ereport(ERROR,
    2263              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2264              :                  errmsg("typmod_out function %s must return type %s",
    2265              :                         NameListToString(procname), "cstring")));
    2266              : 
    2267              :     /* Just a warning for now, per comments in findTypeInputFunction */
    2268            9 :     if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
    2269            0 :         ereport(WARNING,
    2270              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2271              :                  errmsg("type modifier output function %s should not be volatile",
    2272              :                         NameListToString(procname))));
    2273              : 
    2274            9 :     return procOid;
    2275              : }
    2276              : 
    2277              : static Oid
    2278            6 : findTypeAnalyzeFunction(List *procname, Oid typeOid)
    2279              : {
    2280              :     Oid         argList[1];
    2281              :     Oid         procOid;
    2282              : 
    2283              :     /*
    2284              :      * Analyze functions always take one INTERNAL argument and return bool.
    2285              :      */
    2286            6 :     argList[0] = INTERNALOID;
    2287              : 
    2288            6 :     procOid = LookupFuncName(procname, 1, argList, true);
    2289            6 :     if (!OidIsValid(procOid))
    2290            0 :         ereport(ERROR,
    2291              :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2292              :                  errmsg("function %s does not exist",
    2293              :                         func_signature_string(procname, 1, NIL, argList))));
    2294              : 
    2295            6 :     if (get_func_rettype(procOid) != BOOLOID)
    2296            0 :         ereport(ERROR,
    2297              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2298              :                  errmsg("type analyze function %s must return type %s",
    2299              :                         NameListToString(procname), "boolean")));
    2300              : 
    2301            6 :     return procOid;
    2302              : }
    2303              : 
    2304              : static Oid
    2305           12 : findTypeSubscriptingFunction(List *procname, Oid typeOid)
    2306              : {
    2307              :     Oid         argList[1];
    2308              :     Oid         procOid;
    2309              : 
    2310              :     /*
    2311              :      * Subscripting support functions always take one INTERNAL argument and
    2312              :      * return INTERNAL.  (The argument is not used, but we must have it to
    2313              :      * maintain type safety.)
    2314              :      */
    2315           12 :     argList[0] = INTERNALOID;
    2316              : 
    2317           12 :     procOid = LookupFuncName(procname, 1, argList, true);
    2318           12 :     if (!OidIsValid(procOid))
    2319            0 :         ereport(ERROR,
    2320              :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2321              :                  errmsg("function %s does not exist",
    2322              :                         func_signature_string(procname, 1, NIL, argList))));
    2323              : 
    2324           12 :     if (get_func_rettype(procOid) != INTERNALOID)
    2325            0 :         ereport(ERROR,
    2326              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2327              :                  errmsg("type subscripting function %s must return type %s",
    2328              :                         NameListToString(procname), "internal")));
    2329              : 
    2330              :     /*
    2331              :      * We disallow array_subscript_handler() from being selected explicitly,
    2332              :      * since that must only be applied to autogenerated array types.
    2333              :      */
    2334           12 :     if (procOid == F_ARRAY_SUBSCRIPT_HANDLER)
    2335            0 :         ereport(ERROR,
    2336              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2337              :                  errmsg("user-defined types cannot use subscripting function %s",
    2338              :                         NameListToString(procname))));
    2339              : 
    2340           12 :     return procOid;
    2341              : }
    2342              : 
    2343              : /*
    2344              :  * Find suitable support functions and opclasses for a range type.
    2345              :  */
    2346              : 
    2347              : /*
    2348              :  * Find named btree opclass for subtype, or default btree opclass if
    2349              :  * opcname is NIL.
    2350              :  */
    2351              : static Oid
    2352          146 : findRangeSubOpclass(List *opcname, Oid subtype)
    2353              : {
    2354              :     Oid         opcid;
    2355              :     Oid         opInputType;
    2356              : 
    2357          146 :     if (opcname != NIL)
    2358              :     {
    2359            5 :         opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
    2360              : 
    2361              :         /*
    2362              :          * Verify that the operator class accepts this datatype. Note we will
    2363              :          * accept binary compatibility.
    2364              :          */
    2365            5 :         opInputType = get_opclass_input_type(opcid);
    2366            5 :         if (!IsBinaryCoercible(subtype, opInputType))
    2367            0 :             ereport(ERROR,
    2368              :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    2369              :                      errmsg("operator class \"%s\" does not accept data type %s",
    2370              :                             NameListToString(opcname),
    2371              :                             format_type_be(subtype))));
    2372              :     }
    2373              :     else
    2374              :     {
    2375          141 :         opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
    2376          141 :         if (!OidIsValid(opcid))
    2377              :         {
    2378              :             /* We spell the error message identically to ResolveOpClass */
    2379            0 :             ereport(ERROR,
    2380              :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    2381              :                      errmsg("data type %s has no default operator class for access method \"%s\"",
    2382              :                             format_type_be(subtype), "btree"),
    2383              :                      errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
    2384              :         }
    2385              :     }
    2386              : 
    2387          146 :     return opcid;
    2388              : }
    2389              : 
    2390              : static Oid
    2391            0 : findRangeCanonicalFunction(List *procname, Oid typeOid)
    2392              : {
    2393              :     Oid         argList[1];
    2394              :     Oid         procOid;
    2395              :     AclResult   aclresult;
    2396              : 
    2397              :     /*
    2398              :      * Range canonical functions must take and return the range type, and must
    2399              :      * be immutable.
    2400              :      */
    2401            0 :     argList[0] = typeOid;
    2402              : 
    2403            0 :     procOid = LookupFuncName(procname, 1, argList, true);
    2404              : 
    2405            0 :     if (!OidIsValid(procOid))
    2406            0 :         ereport(ERROR,
    2407              :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2408              :                  errmsg("function %s does not exist",
    2409              :                         func_signature_string(procname, 1, NIL, argList))));
    2410              : 
    2411            0 :     if (get_func_rettype(procOid) != typeOid)
    2412            0 :         ereport(ERROR,
    2413              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2414              :                  errmsg("range canonical function %s must return range type",
    2415              :                         func_signature_string(procname, 1, NIL, argList))));
    2416              : 
    2417            0 :     if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
    2418            0 :         ereport(ERROR,
    2419              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2420              :                  errmsg("range canonical function %s must be immutable",
    2421              :                         func_signature_string(procname, 1, NIL, argList))));
    2422              : 
    2423              :     /* Also, range type's creator must have permission to call function */
    2424            0 :     aclresult = object_aclcheck(ProcedureRelationId, procOid, GetUserId(), ACL_EXECUTE);
    2425            0 :     if (aclresult != ACLCHECK_OK)
    2426            0 :         aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
    2427              : 
    2428            0 :     return procOid;
    2429              : }
    2430              : 
    2431              : static Oid
    2432           14 : findRangeSubtypeDiffFunction(List *procname, Oid subtype)
    2433              : {
    2434              :     Oid         argList[2];
    2435              :     Oid         procOid;
    2436              :     AclResult   aclresult;
    2437              : 
    2438              :     /*
    2439              :      * Range subtype diff functions must take two arguments of the subtype,
    2440              :      * must return float8, and must be immutable.
    2441              :      */
    2442           14 :     argList[0] = subtype;
    2443           14 :     argList[1] = subtype;
    2444              : 
    2445           14 :     procOid = LookupFuncName(procname, 2, argList, true);
    2446              : 
    2447           14 :     if (!OidIsValid(procOid))
    2448            4 :         ereport(ERROR,
    2449              :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    2450              :                  errmsg("function %s does not exist",
    2451              :                         func_signature_string(procname, 2, NIL, argList))));
    2452              : 
    2453           10 :     if (get_func_rettype(procOid) != FLOAT8OID)
    2454            0 :         ereport(ERROR,
    2455              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2456              :                  errmsg("range subtype diff function %s must return type %s",
    2457              :                         func_signature_string(procname, 2, NIL, argList),
    2458              :                         "double precision")));
    2459              : 
    2460           10 :     if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
    2461            0 :         ereport(ERROR,
    2462              :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    2463              :                  errmsg("range subtype diff function %s must be immutable",
    2464              :                         func_signature_string(procname, 2, NIL, argList))));
    2465              : 
    2466              :     /* Also, range type's creator must have permission to call function */
    2467           10 :     aclresult = object_aclcheck(ProcedureRelationId, procOid, GetUserId(), ACL_EXECUTE);
    2468           10 :     if (aclresult != ACLCHECK_OK)
    2469            0 :         aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
    2470              : 
    2471           10 :     return procOid;
    2472              : }
    2473              : 
    2474              : /*
    2475              :  *  AssignTypeArrayOid
    2476              :  *
    2477              :  *  Pre-assign the type's array OID for use in pg_type.typarray
    2478              :  */
    2479              : Oid
    2480        47284 : AssignTypeArrayOid(void)
    2481              : {
    2482              :     Oid         type_array_oid;
    2483              : 
    2484              :     /* Use binary-upgrade override for pg_type.typarray? */
    2485        47284 :     if (IsBinaryUpgrade)
    2486              :     {
    2487          933 :         if (!OidIsValid(binary_upgrade_next_array_pg_type_oid))
    2488            0 :             ereport(ERROR,
    2489              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2490              :                      errmsg("pg_type array OID value not set when in binary upgrade mode")));
    2491              : 
    2492          933 :         type_array_oid = binary_upgrade_next_array_pg_type_oid;
    2493          933 :         binary_upgrade_next_array_pg_type_oid = InvalidOid;
    2494              :     }
    2495              :     else
    2496              :     {
    2497        46351 :         Relation    pg_type = table_open(TypeRelationId, AccessShareLock);
    2498              : 
    2499        46351 :         type_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
    2500              :                                             Anum_pg_type_oid);
    2501        46351 :         table_close(pg_type, AccessShareLock);
    2502              :     }
    2503              : 
    2504        47284 :     return type_array_oid;
    2505              : }
    2506              : 
    2507              : /*
    2508              :  *  AssignTypeMultirangeOid
    2509              :  *
    2510              :  *  Pre-assign the range type's multirange OID for use in pg_type.oid
    2511              :  */
    2512              : Oid
    2513          142 : AssignTypeMultirangeOid(void)
    2514              : {
    2515              :     Oid         type_multirange_oid;
    2516              : 
    2517              :     /* Use binary-upgrade override for pg_type.oid? */
    2518          142 :     if (IsBinaryUpgrade)
    2519              :     {
    2520            7 :         if (!OidIsValid(binary_upgrade_next_mrng_pg_type_oid))
    2521            0 :             ereport(ERROR,
    2522              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2523              :                      errmsg("pg_type multirange OID value not set when in binary upgrade mode")));
    2524              : 
    2525            7 :         type_multirange_oid = binary_upgrade_next_mrng_pg_type_oid;
    2526            7 :         binary_upgrade_next_mrng_pg_type_oid = InvalidOid;
    2527              :     }
    2528              :     else
    2529              :     {
    2530          135 :         Relation    pg_type = table_open(TypeRelationId, AccessShareLock);
    2531              : 
    2532          135 :         type_multirange_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
    2533              :                                                  Anum_pg_type_oid);
    2534          135 :         table_close(pg_type, AccessShareLock);
    2535              :     }
    2536              : 
    2537          142 :     return type_multirange_oid;
    2538              : }
    2539              : 
    2540              : /*
    2541              :  *  AssignTypeMultirangeArrayOid
    2542              :  *
    2543              :  *  Pre-assign the range type's multirange array OID for use in pg_type.typarray
    2544              :  */
    2545              : Oid
    2546          142 : AssignTypeMultirangeArrayOid(void)
    2547              : {
    2548              :     Oid         type_multirange_array_oid;
    2549              : 
    2550              :     /* Use binary-upgrade override for pg_type.oid? */
    2551          142 :     if (IsBinaryUpgrade)
    2552              :     {
    2553            7 :         if (!OidIsValid(binary_upgrade_next_mrng_array_pg_type_oid))
    2554            0 :             ereport(ERROR,
    2555              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2556              :                      errmsg("pg_type multirange array OID value not set when in binary upgrade mode")));
    2557              : 
    2558            7 :         type_multirange_array_oid = binary_upgrade_next_mrng_array_pg_type_oid;
    2559            7 :         binary_upgrade_next_mrng_array_pg_type_oid = InvalidOid;
    2560              :     }
    2561              :     else
    2562              :     {
    2563          135 :         Relation    pg_type = table_open(TypeRelationId, AccessShareLock);
    2564              : 
    2565          135 :         type_multirange_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
    2566              :                                                        Anum_pg_type_oid);
    2567          135 :         table_close(pg_type, AccessShareLock);
    2568              :     }
    2569              : 
    2570          142 :     return type_multirange_array_oid;
    2571              : }
    2572              : 
    2573              : 
    2574              : /*-------------------------------------------------------------------
    2575              :  * DefineCompositeType
    2576              :  *
    2577              :  * Create a Composite Type relation.
    2578              :  * `DefineRelation' does all the work, we just provide the correct
    2579              :  * arguments!
    2580              :  *
    2581              :  * If the relation already exists, then 'DefineRelation' will abort
    2582              :  * the xact...
    2583              :  *
    2584              :  * Return type is the new type's object address.
    2585              :  *-------------------------------------------------------------------
    2586              :  */
    2587              : ObjectAddress
    2588         2368 : DefineCompositeType(RangeVar *typevar, List *coldeflist)
    2589              : {
    2590         2368 :     CreateStmt *createStmt = makeNode(CreateStmt);
    2591              :     Oid         old_type_oid;
    2592              :     Oid         typeNamespace;
    2593              :     ObjectAddress address;
    2594              : 
    2595              :     /*
    2596              :      * now set the parameters for keys/inheritance etc. All of these are
    2597              :      * uninteresting for composite types...
    2598              :      */
    2599         2368 :     createStmt->relation = typevar;
    2600         2368 :     createStmt->tableElts = coldeflist;
    2601         2368 :     createStmt->inhRelations = NIL;
    2602         2368 :     createStmt->constraints = NIL;
    2603         2368 :     createStmt->options = NIL;
    2604         2368 :     createStmt->oncommit = ONCOMMIT_NOOP;
    2605         2368 :     createStmt->tablespacename = NULL;
    2606         2368 :     createStmt->if_not_exists = false;
    2607              : 
    2608              :     /*
    2609              :      * Check for collision with an existing type name. If there is one and
    2610              :      * it's an autogenerated array, we can rename it out of the way.  This
    2611              :      * check is here mainly to get a better error message about a "type"
    2612              :      * instead of below about a "relation".
    2613              :      */
    2614         2368 :     typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
    2615              :                                                          NoLock, NULL);
    2616         2368 :     RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
    2617              :     old_type_oid =
    2618         2368 :         GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
    2619              :                         CStringGetDatum(createStmt->relation->relname),
    2620              :                         ObjectIdGetDatum(typeNamespace));
    2621         2368 :     if (OidIsValid(old_type_oid))
    2622              :     {
    2623            0 :         if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
    2624            0 :             ereport(ERROR,
    2625              :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    2626              :                      errmsg("type \"%s\" already exists", createStmt->relation->relname)));
    2627              :     }
    2628              : 
    2629              :     /*
    2630              :      * Finally create the relation.  This also creates the type.
    2631              :      */
    2632         2368 :     DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
    2633              :                    NULL);
    2634              : 
    2635         2360 :     return address;
    2636              : }
    2637              : 
    2638              : /*
    2639              :  * AlterDomainDefault
    2640              :  *
    2641              :  * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
    2642              :  *
    2643              :  * Returns ObjectAddress of the modified domain.
    2644              :  */
    2645              : ObjectAddress
    2646            9 : AlterDomainDefault(List *names, Node *defaultRaw)
    2647              : {
    2648              :     TypeName   *typename;
    2649              :     Oid         domainoid;
    2650              :     HeapTuple   tup;
    2651              :     ParseState *pstate;
    2652              :     Relation    rel;
    2653              :     char       *defaultValue;
    2654            9 :     Node       *defaultExpr = NULL; /* NULL if no default specified */
    2655            9 :     Datum       new_record[Natts_pg_type] = {0};
    2656            9 :     bool        new_record_nulls[Natts_pg_type] = {0};
    2657            9 :     bool        new_record_repl[Natts_pg_type] = {0};
    2658              :     HeapTuple   newtuple;
    2659              :     Form_pg_type typTup;
    2660              :     ObjectAddress address;
    2661              : 
    2662              :     /* Make a TypeName so we can use standard type lookup machinery */
    2663            9 :     typename = makeTypeNameFromNameList(names);
    2664            9 :     domainoid = typenameTypeId(NULL, typename);
    2665              : 
    2666              :     /* Look up the domain in the type table */
    2667            9 :     rel = table_open(TypeRelationId, RowExclusiveLock);
    2668              : 
    2669            9 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
    2670            9 :     if (!HeapTupleIsValid(tup))
    2671            0 :         elog(ERROR, "cache lookup failed for type %u", domainoid);
    2672            9 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    2673              : 
    2674              :     /* Check it's a domain and check user has permission for ALTER DOMAIN */
    2675            9 :     checkDomainOwner(tup);
    2676              : 
    2677              :     /* Setup new tuple */
    2678              : 
    2679              :     /* Store the new default into the tuple */
    2680            9 :     if (defaultRaw)
    2681              :     {
    2682              :         /* Create a dummy ParseState for transformExpr */
    2683            5 :         pstate = make_parsestate(NULL);
    2684              : 
    2685              :         /*
    2686              :          * Cook the colDef->raw_expr into an expression. Note: Name is
    2687              :          * strictly for error message
    2688              :          */
    2689            5 :         defaultExpr = cookDefault(pstate, defaultRaw,
    2690              :                                   typTup->typbasetype,
    2691              :                                   typTup->typtypmod,
    2692            5 :                                   NameStr(typTup->typname),
    2693              :                                   0);
    2694              : 
    2695              :         /*
    2696              :          * If the expression is just a NULL constant, we treat the command
    2697              :          * like ALTER ... DROP DEFAULT.  (But see note for same test in
    2698              :          * DefineDomain.)
    2699              :          */
    2700            5 :         if (defaultExpr == NULL ||
    2701            5 :             (IsA(defaultExpr, Const) && ((Const *) defaultExpr)->constisnull))
    2702              :         {
    2703              :             /* Default is NULL, drop it */
    2704            0 :             defaultExpr = NULL;
    2705            0 :             new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
    2706            0 :             new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
    2707            0 :             new_record_nulls[Anum_pg_type_typdefault - 1] = true;
    2708            0 :             new_record_repl[Anum_pg_type_typdefault - 1] = true;
    2709              :         }
    2710              :         else
    2711              :         {
    2712              :             /*
    2713              :              * Expression must be stored as a nodeToString result, but we also
    2714              :              * require a valid textual representation (mainly to make life
    2715              :              * easier for pg_dump).
    2716              :              */
    2717            5 :             defaultValue = deparse_expression(defaultExpr,
    2718              :                                               NIL, false, false);
    2719              : 
    2720              :             /*
    2721              :              * Form an updated tuple with the new default and write it back.
    2722              :              */
    2723            5 :             new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
    2724              : 
    2725            5 :             new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
    2726            5 :             new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
    2727            5 :             new_record_repl[Anum_pg_type_typdefault - 1] = true;
    2728              :         }
    2729              :     }
    2730              :     else
    2731              :     {
    2732              :         /* ALTER ... DROP DEFAULT */
    2733            4 :         new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
    2734            4 :         new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
    2735            4 :         new_record_nulls[Anum_pg_type_typdefault - 1] = true;
    2736            4 :         new_record_repl[Anum_pg_type_typdefault - 1] = true;
    2737              :     }
    2738              : 
    2739            9 :     newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
    2740              :                                  new_record, new_record_nulls,
    2741              :                                  new_record_repl);
    2742              : 
    2743            9 :     CatalogTupleUpdate(rel, &tup->t_self, newtuple);
    2744              : 
    2745              :     /* Rebuild dependencies */
    2746            9 :     GenerateTypeDependencies(newtuple,
    2747              :                              rel,
    2748              :                              defaultExpr,
    2749              :                              NULL,  /* don't have typacl handy */
    2750              :                              0, /* relation kind is n/a */
    2751              :                              false, /* a domain isn't an implicit array */
    2752              :                              false, /* nor is it any kind of dependent type */
    2753              :                              false, /* don't touch extension membership */
    2754              :                              true); /* We do need to rebuild dependencies */
    2755              : 
    2756            9 :     InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
    2757              : 
    2758            9 :     ObjectAddressSet(address, TypeRelationId, domainoid);
    2759              : 
    2760              :     /* Clean up */
    2761            9 :     table_close(rel, RowExclusiveLock);
    2762            9 :     heap_freetuple(newtuple);
    2763              : 
    2764            9 :     return address;
    2765              : }
    2766              : 
    2767              : /*
    2768              :  * AlterDomainNotNull
    2769              :  *
    2770              :  * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
    2771              :  *
    2772              :  * Returns ObjectAddress of the modified domain.
    2773              :  */
    2774              : ObjectAddress
    2775           24 : AlterDomainNotNull(List *names, bool notNull)
    2776              : {
    2777              :     TypeName   *typename;
    2778              :     Oid         domainoid;
    2779              :     Relation    typrel;
    2780              :     HeapTuple   tup;
    2781              :     Form_pg_type typTup;
    2782           24 :     ObjectAddress address = InvalidObjectAddress;
    2783              : 
    2784              :     /* Make a TypeName so we can use standard type lookup machinery */
    2785           24 :     typename = makeTypeNameFromNameList(names);
    2786           24 :     domainoid = typenameTypeId(NULL, typename);
    2787              : 
    2788              :     /* Look up the domain in the type table */
    2789           24 :     typrel = table_open(TypeRelationId, RowExclusiveLock);
    2790              : 
    2791           24 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
    2792           24 :     if (!HeapTupleIsValid(tup))
    2793            0 :         elog(ERROR, "cache lookup failed for type %u", domainoid);
    2794           24 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    2795              : 
    2796              :     /* Check it's a domain and check user has permission for ALTER DOMAIN */
    2797           24 :     checkDomainOwner(tup);
    2798              : 
    2799              :     /* Is the domain already set to the desired constraint? */
    2800           24 :     if (typTup->typnotnull == notNull)
    2801              :     {
    2802            0 :         table_close(typrel, RowExclusiveLock);
    2803            0 :         return address;
    2804              :     }
    2805              : 
    2806           24 :     if (notNull)
    2807              :     {
    2808              :         Constraint *constr;
    2809              : 
    2810           16 :         constr = makeNode(Constraint);
    2811           16 :         constr->contype = CONSTR_NOTNULL;
    2812           16 :         constr->initially_valid = true;
    2813           16 :         constr->location = -1;
    2814              : 
    2815           16 :         domainAddNotNullConstraint(domainoid, typTup->typnamespace,
    2816              :                                    typTup->typbasetype, typTup->typtypmod,
    2817           16 :                                    constr, NameStr(typTup->typname), NULL);
    2818              : 
    2819           16 :         validateDomainNotNullConstraint(domainoid);
    2820              :     }
    2821              :     else
    2822              :     {
    2823              :         HeapTuple   conTup;
    2824              :         ObjectAddress conobj;
    2825              : 
    2826            8 :         conTup = findDomainNotNullConstraint(domainoid);
    2827            8 :         if (conTup == NULL)
    2828            0 :             elog(ERROR, "could not find not-null constraint on domain \"%s\"", NameStr(typTup->typname));
    2829              : 
    2830            8 :         ObjectAddressSet(conobj, ConstraintRelationId, ((Form_pg_constraint) GETSTRUCT(conTup))->oid);
    2831            8 :         performDeletion(&conobj, DROP_RESTRICT, 0);
    2832              :     }
    2833              : 
    2834              :     /*
    2835              :      * Okay to update pg_type row.  We can scribble on typTup because it's a
    2836              :      * copy.
    2837              :      */
    2838           16 :     typTup->typnotnull = notNull;
    2839              : 
    2840           16 :     CatalogTupleUpdate(typrel, &tup->t_self, tup);
    2841              : 
    2842           16 :     InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
    2843              : 
    2844           16 :     ObjectAddressSet(address, TypeRelationId, domainoid);
    2845              : 
    2846              :     /* Clean up */
    2847           16 :     heap_freetuple(tup);
    2848           16 :     table_close(typrel, RowExclusiveLock);
    2849              : 
    2850           16 :     return address;
    2851              : }
    2852              : 
    2853              : /*
    2854              :  * AlterDomainDropConstraint
    2855              :  *
    2856              :  * Implements the ALTER DOMAIN DROP CONSTRAINT statement
    2857              :  *
    2858              :  * Returns ObjectAddress of the modified domain.
    2859              :  */
    2860              : ObjectAddress
    2861           40 : AlterDomainDropConstraint(List *names, const char *constrName,
    2862              :                           DropBehavior behavior, bool missing_ok)
    2863              : {
    2864              :     TypeName   *typename;
    2865              :     Oid         domainoid;
    2866              :     HeapTuple   tup;
    2867              :     Relation    rel;
    2868              :     Relation    conrel;
    2869              :     SysScanDesc conscan;
    2870              :     ScanKeyData skey[3];
    2871              :     HeapTuple   contup;
    2872           40 :     bool        found = false;
    2873              :     ObjectAddress address;
    2874              : 
    2875              :     /* Make a TypeName so we can use standard type lookup machinery */
    2876           40 :     typename = makeTypeNameFromNameList(names);
    2877           40 :     domainoid = typenameTypeId(NULL, typename);
    2878              : 
    2879              :     /* Look up the domain in the type table */
    2880           40 :     rel = table_open(TypeRelationId, RowExclusiveLock);
    2881              : 
    2882           40 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
    2883           40 :     if (!HeapTupleIsValid(tup))
    2884            0 :         elog(ERROR, "cache lookup failed for type %u", domainoid);
    2885              : 
    2886              :     /* Check it's a domain and check user has permission for ALTER DOMAIN */
    2887           40 :     checkDomainOwner(tup);
    2888              : 
    2889              :     /* Grab an appropriate lock on the pg_constraint relation */
    2890           40 :     conrel = table_open(ConstraintRelationId, RowExclusiveLock);
    2891              : 
    2892              :     /* Find and remove the target constraint */
    2893           40 :     ScanKeyInit(&skey[0],
    2894              :                 Anum_pg_constraint_conrelid,
    2895              :                 BTEqualStrategyNumber, F_OIDEQ,
    2896              :                 ObjectIdGetDatum(InvalidOid));
    2897           40 :     ScanKeyInit(&skey[1],
    2898              :                 Anum_pg_constraint_contypid,
    2899              :                 BTEqualStrategyNumber, F_OIDEQ,
    2900              :                 ObjectIdGetDatum(domainoid));
    2901           40 :     ScanKeyInit(&skey[2],
    2902              :                 Anum_pg_constraint_conname,
    2903              :                 BTEqualStrategyNumber, F_NAMEEQ,
    2904              :                 CStringGetDatum(constrName));
    2905              : 
    2906           40 :     conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
    2907              :                                  NULL, 3, skey);
    2908              : 
    2909              :     /* There can be at most one matching row */
    2910           40 :     if ((contup = systable_getnext(conscan)) != NULL)
    2911              :     {
    2912           32 :         Form_pg_constraint construct = (Form_pg_constraint) GETSTRUCT(contup);
    2913              :         ObjectAddress conobj;
    2914              : 
    2915           32 :         if (construct->contype == CONSTRAINT_NOTNULL)
    2916              :         {
    2917            8 :             ((Form_pg_type) GETSTRUCT(tup))->typnotnull = false;
    2918            8 :             CatalogTupleUpdate(rel, &tup->t_self, tup);
    2919              :         }
    2920              : 
    2921           32 :         conobj.classId = ConstraintRelationId;
    2922           32 :         conobj.objectId = construct->oid;
    2923           32 :         conobj.objectSubId = 0;
    2924              : 
    2925           32 :         performDeletion(&conobj, behavior, 0);
    2926           32 :         found = true;
    2927              :     }
    2928              : 
    2929              :     /* Clean up after the scan */
    2930           40 :     systable_endscan(conscan);
    2931           40 :     table_close(conrel, RowExclusiveLock);
    2932              : 
    2933           40 :     if (!found)
    2934              :     {
    2935            8 :         if (!missing_ok)
    2936            4 :             ereport(ERROR,
    2937              :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    2938              :                      errmsg("constraint \"%s\" of domain \"%s\" does not exist",
    2939              :                             constrName, TypeNameToString(typename))));
    2940              :         else
    2941            4 :             ereport(NOTICE,
    2942              :                     (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
    2943              :                             constrName, TypeNameToString(typename))));
    2944              :     }
    2945              : 
    2946              :     /*
    2947              :      * We must send out an sinval message for the domain, to ensure that any
    2948              :      * dependent plans get rebuilt.  Since this command doesn't change the
    2949              :      * domain's pg_type row, that won't happen automatically; do it manually.
    2950              :      */
    2951           36 :     CacheInvalidateHeapTuple(rel, tup, NULL);
    2952              : 
    2953           36 :     ObjectAddressSet(address, TypeRelationId, domainoid);
    2954              : 
    2955              :     /* Clean up */
    2956           36 :     table_close(rel, RowExclusiveLock);
    2957              : 
    2958           36 :     return address;
    2959              : }
    2960              : 
    2961              : /*
    2962              :  * AlterDomainAddConstraint
    2963              :  *
    2964              :  * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
    2965              :  */
    2966              : ObjectAddress
    2967          120 : AlterDomainAddConstraint(List *names, Node *newConstraint,
    2968              :                          ObjectAddress *constrAddr)
    2969              : {
    2970              :     TypeName   *typename;
    2971              :     Oid         domainoid;
    2972              :     Relation    typrel;
    2973              :     HeapTuple   tup;
    2974              :     Form_pg_type typTup;
    2975              :     Constraint *constr;
    2976              :     char       *ccbin;
    2977          120 :     ObjectAddress address = InvalidObjectAddress;
    2978              : 
    2979              :     /* Make a TypeName so we can use standard type lookup machinery */
    2980          120 :     typename = makeTypeNameFromNameList(names);
    2981          120 :     domainoid = typenameTypeId(NULL, typename);
    2982              : 
    2983              :     /* Look up the domain in the type table */
    2984          120 :     typrel = table_open(TypeRelationId, RowExclusiveLock);
    2985              : 
    2986          120 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
    2987          120 :     if (!HeapTupleIsValid(tup))
    2988            0 :         elog(ERROR, "cache lookup failed for type %u", domainoid);
    2989          120 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    2990              : 
    2991              :     /* Check it's a domain and check user has permission for ALTER DOMAIN */
    2992          120 :     checkDomainOwner(tup);
    2993              : 
    2994          120 :     if (!IsA(newConstraint, Constraint))
    2995            0 :         elog(ERROR, "unrecognized node type: %d",
    2996              :              (int) nodeTag(newConstraint));
    2997              : 
    2998          120 :     constr = (Constraint *) newConstraint;
    2999              : 
    3000              :     /* enforced by parser */
    3001              :     Assert(constr->contype == CONSTR_CHECK || constr->contype == CONSTR_NOTNULL);
    3002              : 
    3003          120 :     if (constr->contype == CONSTR_CHECK)
    3004              :     {
    3005              :         /*
    3006              :          * First, process the constraint expression and add an entry to
    3007              :          * pg_constraint.
    3008              :          */
    3009              : 
    3010          100 :         ccbin = domainAddCheckConstraint(domainoid, typTup->typnamespace,
    3011              :                                          typTup->typbasetype, typTup->typtypmod,
    3012          100 :                                          constr, NameStr(typTup->typname), constrAddr);
    3013              : 
    3014              : 
    3015              :         /*
    3016              :          * If requested to validate the constraint, test all values stored in
    3017              :          * the attributes based on the domain the constraint is being added
    3018              :          * to.
    3019              :          */
    3020           96 :         if (!constr->skip_validation)
    3021           87 :             validateDomainCheckConstraint(domainoid, ccbin, ShareLock);
    3022              : 
    3023              :         /*
    3024              :          * We must send out an sinval message for the domain, to ensure that
    3025              :          * any dependent plans get rebuilt.  Since this command doesn't change
    3026              :          * the domain's pg_type row, that won't happen automatically; do it
    3027              :          * manually.
    3028              :          */
    3029           56 :         CacheInvalidateHeapTuple(typrel, tup, NULL);
    3030              :     }
    3031           20 :     else if (constr->contype == CONSTR_NOTNULL)
    3032              :     {
    3033              :         /* Is the domain already set NOT NULL? */
    3034           20 :         if (typTup->typnotnull)
    3035              :         {
    3036            4 :             table_close(typrel, RowExclusiveLock);
    3037            4 :             return address;
    3038              :         }
    3039           16 :         domainAddNotNullConstraint(domainoid, typTup->typnamespace,
    3040              :                                    typTup->typbasetype, typTup->typtypmod,
    3041           16 :                                    constr, NameStr(typTup->typname), constrAddr);
    3042              : 
    3043           16 :         if (!constr->skip_validation)
    3044           16 :             validateDomainNotNullConstraint(domainoid);
    3045              : 
    3046            8 :         typTup->typnotnull = true;
    3047            8 :         CatalogTupleUpdate(typrel, &tup->t_self, tup);
    3048              :     }
    3049              : 
    3050           64 :     ObjectAddressSet(address, TypeRelationId, domainoid);
    3051              : 
    3052              :     /* Clean up */
    3053           64 :     table_close(typrel, RowExclusiveLock);
    3054              : 
    3055           64 :     return address;
    3056              : }
    3057              : 
    3058              : /*
    3059              :  * AlterDomainValidateConstraint
    3060              :  *
    3061              :  * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
    3062              :  *
    3063              :  * Return value is the address of the validated constraint.  If the constraint
    3064              :  * was already validated, InvalidObjectAddress is returned.
    3065              :  */
    3066              : ObjectAddress
    3067            8 : AlterDomainValidateConstraint(List *names, const char *constrName)
    3068              : {
    3069              :     TypeName   *typename;
    3070              :     Oid         domainoid;
    3071              :     Relation    typrel;
    3072              :     Relation    conrel;
    3073              :     HeapTuple   tup;
    3074              :     Form_pg_constraint con;
    3075              :     Form_pg_constraint copy_con;
    3076              :     char       *conbin;
    3077              :     SysScanDesc scan;
    3078              :     Datum       val;
    3079              :     HeapTuple   tuple;
    3080              :     HeapTuple   copyTuple;
    3081              :     ScanKeyData skey[3];
    3082            8 :     ObjectAddress address = InvalidObjectAddress;
    3083              : 
    3084              :     /* Make a TypeName so we can use standard type lookup machinery */
    3085            8 :     typename = makeTypeNameFromNameList(names);
    3086            8 :     domainoid = typenameTypeId(NULL, typename);
    3087              : 
    3088              :     /* Look up the domain in the type table */
    3089            8 :     typrel = table_open(TypeRelationId, AccessShareLock);
    3090              : 
    3091            8 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
    3092            8 :     if (!HeapTupleIsValid(tup))
    3093            0 :         elog(ERROR, "cache lookup failed for type %u", domainoid);
    3094              : 
    3095              :     /* Check it's a domain and check user has permission for ALTER DOMAIN */
    3096            8 :     checkDomainOwner(tup);
    3097              : 
    3098              :     /*
    3099              :      * Find and check the target constraint
    3100              :      */
    3101            8 :     conrel = table_open(ConstraintRelationId, RowExclusiveLock);
    3102              : 
    3103            8 :     ScanKeyInit(&skey[0],
    3104              :                 Anum_pg_constraint_conrelid,
    3105              :                 BTEqualStrategyNumber, F_OIDEQ,
    3106              :                 ObjectIdGetDatum(InvalidOid));
    3107            8 :     ScanKeyInit(&skey[1],
    3108              :                 Anum_pg_constraint_contypid,
    3109              :                 BTEqualStrategyNumber, F_OIDEQ,
    3110              :                 ObjectIdGetDatum(domainoid));
    3111            8 :     ScanKeyInit(&skey[2],
    3112              :                 Anum_pg_constraint_conname,
    3113              :                 BTEqualStrategyNumber, F_NAMEEQ,
    3114              :                 CStringGetDatum(constrName));
    3115              : 
    3116            8 :     scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
    3117              :                               NULL, 3, skey);
    3118              : 
    3119              :     /* There can be at most one matching row */
    3120            8 :     if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
    3121            0 :         ereport(ERROR,
    3122              :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3123              :                  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
    3124              :                         constrName, TypeNameToString(typename))));
    3125              : 
    3126            8 :     con = (Form_pg_constraint) GETSTRUCT(tuple);
    3127            8 :     if (con->contype != CONSTRAINT_CHECK)
    3128            0 :         ereport(ERROR,
    3129              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3130              :                  errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
    3131              :                         constrName, TypeNameToString(typename))));
    3132              : 
    3133            8 :     if (!con->convalidated)
    3134              :     {
    3135            8 :         val = SysCacheGetAttrNotNull(CONSTROID, tuple, Anum_pg_constraint_conbin);
    3136            8 :         conbin = TextDatumGetCString(val);
    3137              : 
    3138              :         /*
    3139              :          * Locking related relations with ShareUpdateExclusiveLock is ok
    3140              :          * because not-yet-valid constraints are still enforced against
    3141              :          * concurrent inserts or updates.
    3142              :          */
    3143            8 :         validateDomainCheckConstraint(domainoid, conbin, ShareUpdateExclusiveLock);
    3144              : 
    3145              :         /*
    3146              :          * Now update the catalog, while we have the door open.
    3147              :          */
    3148            4 :         copyTuple = heap_copytuple(tuple);
    3149            4 :         copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
    3150            4 :         copy_con->convalidated = true;
    3151            4 :         CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
    3152              : 
    3153            4 :         InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
    3154              : 
    3155            4 :         ObjectAddressSet(address, TypeRelationId, domainoid);
    3156              : 
    3157            4 :         heap_freetuple(copyTuple);
    3158              :     }
    3159              : 
    3160            4 :     systable_endscan(scan);
    3161              : 
    3162            4 :     table_close(typrel, AccessShareLock);
    3163            4 :     table_close(conrel, RowExclusiveLock);
    3164              : 
    3165            4 :     ReleaseSysCache(tup);
    3166              : 
    3167            4 :     return address;
    3168              : }
    3169              : 
    3170              : /*
    3171              :  * Verify that all columns currently using the domain are not null.
    3172              :  */
    3173              : static void
    3174           32 : validateDomainNotNullConstraint(Oid domainoid)
    3175              : {
    3176              :     List       *rels;
    3177              :     ListCell   *rt;
    3178              : 
    3179              :     /* Fetch relation list with attributes based on this domain */
    3180              :     /* ShareLock is sufficient to prevent concurrent data changes */
    3181              : 
    3182           32 :     rels = get_rels_with_domain(domainoid, ShareLock);
    3183              : 
    3184           44 :     foreach(rt, rels)
    3185              :     {
    3186           28 :         RelToCheck *rtc = (RelToCheck *) lfirst(rt);
    3187           28 :         Relation    testrel = rtc->rel;
    3188           28 :         TupleDesc   tupdesc = RelationGetDescr(testrel);
    3189              :         TupleTableSlot *slot;
    3190              :         TableScanDesc scan;
    3191              :         Snapshot    snapshot;
    3192              : 
    3193              :         /* Scan all tuples in this relation */
    3194           28 :         snapshot = RegisterSnapshot(GetLatestSnapshot());
    3195           28 :         scan = table_beginscan(testrel, snapshot, 0, NULL,
    3196              :                                SO_NONE);
    3197           28 :         slot = table_slot_create(testrel, NULL);
    3198           40 :         while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
    3199              :         {
    3200              :             int         i;
    3201              : 
    3202              :             /* Test attributes that are of the domain */
    3203           60 :             for (i = 0; i < rtc->natts; i++)
    3204              :             {
    3205           48 :                 int         attnum = rtc->atts[i];
    3206           48 :                 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
    3207              : 
    3208           48 :                 if (slot_attisnull(slot, attnum))
    3209              :                 {
    3210              :                     /*
    3211              :                      * In principle the auxiliary information for this error
    3212              :                      * should be errdatatype(), but errtablecol() seems
    3213              :                      * considerably more useful in practice.  Since this code
    3214              :                      * only executes in an ALTER DOMAIN command, the client
    3215              :                      * should already know which domain is in question.
    3216              :                      */
    3217           16 :                     ereport(ERROR,
    3218              :                             (errcode(ERRCODE_NOT_NULL_VIOLATION),
    3219              :                              errmsg("column \"%s\" of table \"%s\" contains null values",
    3220              :                                     NameStr(attr->attname),
    3221              :                                     RelationGetRelationName(testrel)),
    3222              :                              errtablecol(testrel, attnum)));
    3223              :                 }
    3224              :             }
    3225              :         }
    3226           12 :         ExecDropSingleTupleTableSlot(slot);
    3227           12 :         table_endscan(scan);
    3228           12 :         UnregisterSnapshot(snapshot);
    3229              : 
    3230              :         /* Close each rel after processing, but keep lock */
    3231           12 :         table_close(testrel, NoLock);
    3232              :     }
    3233           16 : }
    3234              : 
    3235              : /*
    3236              :  * Verify that all columns currently using the domain satisfy the given check
    3237              :  * constraint expression.
    3238              :  *
    3239              :  * It is used to validate existing constraints and to add newly created check
    3240              :  * constraints to a domain.
    3241              :  *
    3242              :  * The lockmode is used for relations using the domain.  It should be
    3243              :  * ShareLock when adding a new constraint to domain.  It can be
    3244              :  * ShareUpdateExclusiveLock when validating an existing constraint.
    3245              :  */
    3246              : static void
    3247           95 : validateDomainCheckConstraint(Oid domainoid, const char *ccbin, LOCKMODE lockmode)
    3248              : {
    3249           95 :     Expr       *expr = (Expr *) stringToNode(ccbin);
    3250              :     List       *rels;
    3251              :     ListCell   *rt;
    3252              :     EState     *estate;
    3253              :     ExprContext *econtext;
    3254              :     ExprState  *exprstate;
    3255              : 
    3256              :     /* Need an EState to run ExecEvalExpr */
    3257           95 :     estate = CreateExecutorState();
    3258           95 :     econtext = GetPerTupleExprContext(estate);
    3259              : 
    3260              :     /* build execution state for expr */
    3261           95 :     exprstate = ExecPrepareExpr(expr, estate);
    3262              : 
    3263              :     /* Fetch relation list with attributes based on this domain */
    3264           95 :     rels = get_rels_with_domain(domainoid, lockmode);
    3265              : 
    3266           99 :     foreach(rt, rels)
    3267              :     {
    3268           48 :         RelToCheck *rtc = (RelToCheck *) lfirst(rt);
    3269           48 :         Relation    testrel = rtc->rel;
    3270           48 :         TupleDesc   tupdesc = RelationGetDescr(testrel);
    3271              :         TupleTableSlot *slot;
    3272              :         TableScanDesc scan;
    3273              :         Snapshot    snapshot;
    3274              : 
    3275              :         /* Scan all tuples in this relation */
    3276           48 :         snapshot = RegisterSnapshot(GetLatestSnapshot());
    3277           48 :         scan = table_beginscan(testrel, snapshot, 0, NULL,
    3278              :                                SO_NONE);
    3279           48 :         slot = table_slot_create(testrel, NULL);
    3280          112 :         while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
    3281              :         {
    3282              :             int         i;
    3283              : 
    3284              :             /* Test attributes that are of the domain */
    3285          152 :             for (i = 0; i < rtc->natts; i++)
    3286              :             {
    3287           88 :                 int         attnum = rtc->atts[i];
    3288              :                 Datum       d;
    3289              :                 bool        isNull;
    3290              :                 Datum       conResult;
    3291              : 
    3292           88 :                 d = slot_getattr(slot, attnum, &isNull);
    3293              : 
    3294           88 :                 econtext->domainValue_datum = d;
    3295           88 :                 econtext->domainValue_isNull = isNull;
    3296              : 
    3297           88 :                 conResult = ExecEvalExprSwitchContext(exprstate,
    3298              :                                                       econtext,
    3299              :                                                       &isNull);
    3300              : 
    3301           88 :                 if (!isNull && !DatumGetBool(conResult))
    3302              :                 {
    3303           24 :                     Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
    3304              : 
    3305              :                     /*
    3306              :                      * In principle the auxiliary information for this error
    3307              :                      * should be errdomainconstraint(), but errtablecol()
    3308              :                      * seems considerably more useful in practice.  Since this
    3309              :                      * code only executes in an ALTER DOMAIN command, the
    3310              :                      * client should already know which domain is in question,
    3311              :                      * and which constraint too.
    3312              :                      */
    3313           24 :                     ereport(ERROR,
    3314              :                             (errcode(ERRCODE_CHECK_VIOLATION),
    3315              :                              errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
    3316              :                                     NameStr(attr->attname),
    3317              :                                     RelationGetRelationName(testrel)),
    3318              :                              errtablecol(testrel, attnum)));
    3319              :                 }
    3320              :             }
    3321              : 
    3322           64 :             ResetExprContext(econtext);
    3323              :         }
    3324           24 :         ExecDropSingleTupleTableSlot(slot);
    3325           24 :         table_endscan(scan);
    3326           24 :         UnregisterSnapshot(snapshot);
    3327              : 
    3328              :         /* Hold relation lock till commit (XXX bad for concurrency) */
    3329           24 :         table_close(testrel, NoLock);
    3330              :     }
    3331              : 
    3332           51 :     FreeExecutorState(estate);
    3333           51 : }
    3334              : 
    3335              : /*
    3336              :  * get_rels_with_domain
    3337              :  *
    3338              :  * Fetch all relations / attributes which are using the domain
    3339              :  *
    3340              :  * The result is a list of RelToCheck structs, one for each distinct
    3341              :  * relation, each containing one or more attribute numbers that are of
    3342              :  * the domain type.  We have opened each rel and acquired the specified lock
    3343              :  * type on it.
    3344              :  *
    3345              :  * We support nested domains by including attributes that are of derived
    3346              :  * domain types.  Current callers do not need to distinguish between attributes
    3347              :  * that are of exactly the given domain and those that are of derived domains.
    3348              :  *
    3349              :  * XXX this is completely broken because there is no way to lock the domain
    3350              :  * to prevent columns from being added or dropped while our command runs.
    3351              :  * We can partially protect against column drops by locking relations as we
    3352              :  * come across them, but there is still a race condition (the window between
    3353              :  * seeing a pg_depend entry and acquiring lock on the relation it references).
    3354              :  * Also, holding locks on all these relations simultaneously creates a non-
    3355              :  * trivial risk of deadlock.  We can minimize but not eliminate the deadlock
    3356              :  * risk by using the weakest suitable lock (ShareLock for most callers).
    3357              :  *
    3358              :  * XXX the API for this is not sufficient to support checking domain values
    3359              :  * that are inside container types, such as composite types, arrays, or
    3360              :  * ranges.  Currently we just error out if a container type containing the
    3361              :  * target domain is stored anywhere.
    3362              :  *
    3363              :  * Generally used for retrieving a list of tests when adding
    3364              :  * new constraints to a domain.
    3365              :  */
    3366              : static List *
    3367          135 : get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
    3368              : {
    3369          135 :     List       *result = NIL;
    3370          135 :     char       *domainTypeName = format_type_be(domainOid);
    3371              :     Relation    depRel;
    3372              :     ScanKeyData key[2];
    3373              :     SysScanDesc depScan;
    3374              :     HeapTuple   depTup;
    3375              : 
    3376              :     Assert(lockmode != NoLock);
    3377              : 
    3378              :     /* since this function recurses, it could be driven to stack overflow */
    3379          135 :     check_stack_depth();
    3380              : 
    3381              :     /*
    3382              :      * We scan pg_depend to find those things that depend on the domain. (We
    3383              :      * assume we can ignore refobjsubid for a domain.)
    3384              :      */
    3385          135 :     depRel = table_open(DependRelationId, AccessShareLock);
    3386              : 
    3387          135 :     ScanKeyInit(&key[0],
    3388              :                 Anum_pg_depend_refclassid,
    3389              :                 BTEqualStrategyNumber, F_OIDEQ,
    3390              :                 ObjectIdGetDatum(TypeRelationId));
    3391          135 :     ScanKeyInit(&key[1],
    3392              :                 Anum_pg_depend_refobjid,
    3393              :                 BTEqualStrategyNumber, F_OIDEQ,
    3394              :                 ObjectIdGetDatum(domainOid));
    3395              : 
    3396          135 :     depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
    3397              :                                  NULL, 2, key);
    3398              : 
    3399          467 :     while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
    3400              :     {
    3401          352 :         Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
    3402          352 :         RelToCheck *rtc = NULL;
    3403              :         ListCell   *rellist;
    3404              :         Form_pg_attribute pg_att;
    3405              :         int         ptr;
    3406              : 
    3407              :         /* Check for directly dependent types */
    3408          352 :         if (pg_depend->classid == TypeRelationId)
    3409              :         {
    3410          147 :             if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
    3411              :             {
    3412              :                 /*
    3413              :                  * This is a sub-domain, so recursively add dependent columns
    3414              :                  * to the output list.  This is a bit inefficient since we may
    3415              :                  * fail to combine RelToCheck entries when attributes of the
    3416              :                  * same rel have different derived domain types, but it's
    3417              :                  * probably not worth improving.
    3418              :                  */
    3419            8 :                 result = list_concat(result,
    3420            8 :                                      get_rels_with_domain(pg_depend->objid,
    3421              :                                                           lockmode));
    3422              :             }
    3423              :             else
    3424              :             {
    3425              :                 /*
    3426              :                  * Otherwise, it is some container type using the domain, so
    3427              :                  * fail if there are any columns of this type.
    3428              :                  */
    3429          139 :                 find_composite_type_dependencies(pg_depend->objid,
    3430              :                                                  NULL,
    3431              :                                                  domainTypeName);
    3432              :             }
    3433          143 :             continue;
    3434              :         }
    3435              : 
    3436              :         /* Else, ignore dependees that aren't user columns of relations */
    3437              :         /* (we assume system columns are never of domain types) */
    3438          205 :         if (pg_depend->classid != RelationRelationId ||
    3439          144 :             pg_depend->objsubid <= 0)
    3440           61 :             continue;
    3441              : 
    3442              :         /* See if we already have an entry for this relation */
    3443          144 :         foreach(rellist, result)
    3444              :         {
    3445           28 :             RelToCheck *rt = (RelToCheck *) lfirst(rellist);
    3446              : 
    3447           28 :             if (RelationGetRelid(rt->rel) == pg_depend->objid)
    3448              :             {
    3449           28 :                 rtc = rt;
    3450           28 :                 break;
    3451              :             }
    3452              :         }
    3453              : 
    3454          144 :         if (rtc == NULL)
    3455              :         {
    3456              :             /* First attribute found for this relation */
    3457              :             Relation    rel;
    3458              : 
    3459              :             /* Acquire requested lock on relation */
    3460          116 :             rel = relation_open(pg_depend->objid, lockmode);
    3461              : 
    3462              :             /*
    3463              :              * Check to see if rowtype is stored anyplace as a composite-type
    3464              :              * column; if so we have to fail, for now anyway.
    3465              :              */
    3466          116 :             if (OidIsValid(rel->rd_rel->reltype))
    3467          116 :                 find_composite_type_dependencies(rel->rd_rel->reltype,
    3468              :                                                  NULL,
    3469              :                                                  domainTypeName);
    3470              : 
    3471              :             /*
    3472              :              * Otherwise, we can ignore relations except those with both
    3473              :              * storage and user-chosen column types.
    3474              :              *
    3475              :              * XXX If an index-only scan could satisfy "col::some_domain" from
    3476              :              * a suitable expression index, this should also check expression
    3477              :              * index columns.
    3478              :              */
    3479          100 :             if (rel->rd_rel->relkind != RELKIND_RELATION &&
    3480           24 :                 rel->rd_rel->relkind != RELKIND_MATVIEW)
    3481              :             {
    3482           24 :                 relation_close(rel, lockmode);
    3483           24 :                 continue;
    3484              :             }
    3485              : 
    3486              :             /* Build the RelToCheck entry with enough space for all atts */
    3487           76 :             rtc = palloc_object(RelToCheck);
    3488           76 :             rtc->rel = rel;
    3489           76 :             rtc->natts = 0;
    3490           76 :             rtc->atts = palloc_array(int, RelationGetNumberOfAttributes(rel));
    3491           76 :             result = lappend(result, rtc);
    3492              :         }
    3493              : 
    3494              :         /*
    3495              :          * Confirm column has not been dropped, and is of the expected type.
    3496              :          * This defends against an ALTER DROP COLUMN occurring just before we
    3497              :          * acquired lock ... but if the whole table were dropped, we'd still
    3498              :          * have a problem.
    3499              :          */
    3500          104 :         if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
    3501            0 :             continue;
    3502          104 :         pg_att = TupleDescAttr(rtc->rel->rd_att, pg_depend->objsubid - 1);
    3503          104 :         if (pg_att->attisdropped || pg_att->atttypid != domainOid)
    3504            0 :             continue;
    3505              : 
    3506              :         /*
    3507              :          * Okay, add column to result.  We store the columns in column-number
    3508              :          * order; this is just a hack to improve predictability of regression
    3509              :          * test output ...
    3510              :          */
    3511              :         Assert(rtc->natts < RelationGetNumberOfAttributes(rtc->rel));
    3512              : 
    3513          104 :         ptr = rtc->natts++;
    3514          104 :         while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
    3515              :         {
    3516            0 :             rtc->atts[ptr] = rtc->atts[ptr - 1];
    3517            0 :             ptr--;
    3518              :         }
    3519          104 :         rtc->atts[ptr] = pg_depend->objsubid;
    3520              :     }
    3521              : 
    3522          115 :     systable_endscan(depScan);
    3523              : 
    3524          115 :     relation_close(depRel, AccessShareLock);
    3525              : 
    3526          115 :     return result;
    3527              : }
    3528              : 
    3529              : /*
    3530              :  * checkDomainOwner
    3531              :  *
    3532              :  * Check that the type is actually a domain and that the current user
    3533              :  * has permission to do ALTER DOMAIN on it.  Throw an error if not.
    3534              :  */
    3535              : void
    3536          205 : checkDomainOwner(HeapTuple tup)
    3537              : {
    3538          205 :     Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
    3539              : 
    3540              :     /* Check that this is actually a domain */
    3541          205 :     if (typTup->typtype != TYPTYPE_DOMAIN)
    3542            0 :         ereport(ERROR,
    3543              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3544              :                  errmsg("%s is not a domain",
    3545              :                         format_type_be(typTup->oid))));
    3546              : 
    3547              :     /* Permission check: must own type */
    3548          205 :     if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
    3549            0 :         aclcheck_error_type(ACLCHECK_NOT_OWNER, typTup->oid);
    3550          205 : }
    3551              : 
    3552              : /*
    3553              :  * domainAddCheckConstraint - code shared between CREATE and ALTER DOMAIN
    3554              :  */
    3555              : static char *
    3556          507 : domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
    3557              :                          int typMod, Constraint *constr,
    3558              :                          const char *domainName, ObjectAddress *constrAddr)
    3559              : {
    3560              :     Node       *expr;
    3561              :     char       *ccbin;
    3562              :     ParseState *pstate;
    3563              :     CoerceToDomainValue *domVal;
    3564              :     Oid         ccoid;
    3565              : 
    3566              :     Assert(constr->contype == CONSTR_CHECK);
    3567              : 
    3568              :     /*
    3569              :      * Assign or validate constraint name
    3570              :      */
    3571          507 :     if (constr->conname)
    3572              :     {
    3573          243 :         if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
    3574              :                                  domainOid,
    3575          243 :                                  constr->conname))
    3576            0 :             ereport(ERROR,
    3577              :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    3578              :                      errmsg("constraint \"%s\" for domain \"%s\" already exists",
    3579              :                             constr->conname, domainName)));
    3580              :     }
    3581              :     else
    3582          264 :         constr->conname = ChooseConstraintName(domainName,
    3583              :                                                NULL,
    3584              :                                                "check",
    3585              :                                                domainNamespace,
    3586              :                                                NIL);
    3587              : 
    3588              :     /*
    3589              :      * Convert the A_EXPR in raw_expr into an EXPR
    3590              :      */
    3591          507 :     pstate = make_parsestate(NULL);
    3592              : 
    3593              :     /*
    3594              :      * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
    3595              :      * the expression.  Note that it will appear to have the type of the base
    3596              :      * type, not the domain.  This seems correct since within the check
    3597              :      * expression, we should not assume the input value can be considered a
    3598              :      * member of the domain.
    3599              :      */
    3600          507 :     domVal = makeNode(CoerceToDomainValue);
    3601          507 :     domVal->typeId = baseTypeOid;
    3602          507 :     domVal->typeMod = typMod;
    3603          507 :     domVal->collation = get_typcollation(baseTypeOid);
    3604          507 :     domVal->location = -1;       /* will be set when/if used */
    3605              : 
    3606          507 :     pstate->p_pre_columnref_hook = replace_domain_constraint_value;
    3607          507 :     pstate->p_ref_hook_state = domVal;
    3608              : 
    3609          507 :     expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
    3610              : 
    3611              :     /*
    3612              :      * Make sure it yields a boolean result.
    3613              :      */
    3614          503 :     expr = coerce_to_boolean(pstate, expr, "CHECK");
    3615              : 
    3616              :     /*
    3617              :      * Fix up collation information.
    3618              :      */
    3619          503 :     assign_expr_collations(pstate, expr);
    3620              : 
    3621              :     /*
    3622              :      * Domains don't allow variables (this is probably dead code now that
    3623              :      * add_missing_from is history, but let's be sure).
    3624              :      */
    3625         1006 :     if (pstate->p_rtable != NIL ||
    3626          503 :         contain_var_clause(expr))
    3627            0 :         ereport(ERROR,
    3628              :                 (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
    3629              :                  errmsg("cannot use table references in domain check constraint")));
    3630              : 
    3631              :     /*
    3632              :      * Convert to string form for storage.
    3633              :      */
    3634          503 :     ccbin = nodeToString(expr);
    3635              : 
    3636              :     /*
    3637              :      * Store the constraint in pg_constraint
    3638              :      */
    3639              :     ccoid =
    3640          503 :         CreateConstraintEntry(constr->conname,   /* Constraint Name */
    3641              :                               domainNamespace,  /* namespace */
    3642              :                               CONSTRAINT_CHECK, /* Constraint Type */
    3643              :                               false,    /* Is Deferrable */
    3644              :                               false,    /* Is Deferred */
    3645              :                               true, /* Is Enforced */
    3646          503 :                               !constr->skip_validation, /* Is Validated */
    3647              :                               InvalidOid,   /* no parent constraint */
    3648              :                               InvalidOid,   /* not a relation constraint */
    3649              :                               NULL,
    3650              :                               0,
    3651              :                               0,
    3652              :                               domainOid,    /* domain constraint */
    3653              :                               InvalidOid,   /* no associated index */
    3654              :                               InvalidOid,   /* Foreign key fields */
    3655              :                               NULL,
    3656              :                               NULL,
    3657              :                               NULL,
    3658              :                               NULL,
    3659              :                               0,
    3660              :                               ' ',
    3661              :                               ' ',
    3662              :                               NULL,
    3663              :                               0,
    3664              :                               ' ',
    3665              :                               NULL, /* not an exclusion constraint */
    3666              :                               expr, /* Tree form of check constraint */
    3667              :                               ccbin,    /* Binary form of check constraint */
    3668              :                               true, /* is local */
    3669              :                               0,    /* inhcount */
    3670              :                               false,    /* connoinherit */
    3671              :                               false,    /* conperiod */
    3672          503 :                               false);   /* is_internal */
    3673          503 :     if (constrAddr)
    3674           91 :         ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
    3675              : 
    3676              :     /*
    3677              :      * Return the compiled constraint expression so the calling routine can
    3678              :      * perform any additional required tests.
    3679              :      */
    3680          503 :     return ccbin;
    3681              : }
    3682              : 
    3683              : /* Parser pre_columnref_hook for domain CHECK constraint parsing */
    3684              : static Node *
    3685          571 : replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
    3686              : {
    3687              :     /*
    3688              :      * Check for a reference to "value", and if that's what it is, replace
    3689              :      * with a CoerceToDomainValue as prepared for us by
    3690              :      * domainAddCheckConstraint. (We handle VALUE as a name, not a keyword, to
    3691              :      * avoid breaking a lot of applications that have used VALUE as a column
    3692              :      * name in the past.)
    3693              :      */
    3694          571 :     if (list_length(cref->fields) == 1)
    3695              :     {
    3696          571 :         Node       *field1 = (Node *) linitial(cref->fields);
    3697              :         char       *colname;
    3698              : 
    3699          571 :         colname = strVal(field1);
    3700          571 :         if (strcmp(colname, "value") == 0)
    3701              :         {
    3702          571 :             CoerceToDomainValue *domVal = copyObject(pstate->p_ref_hook_state);
    3703              : 
    3704              :             /* Propagate location knowledge, if any */
    3705          571 :             domVal->location = cref->location;
    3706          571 :             return (Node *) domVal;
    3707              :         }
    3708              :     }
    3709            0 :     return NULL;
    3710              : }
    3711              : 
    3712              : /*
    3713              :  * domainAddNotNullConstraint - code shared between CREATE and ALTER DOMAIN
    3714              :  */
    3715              : static void
    3716           92 : domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
    3717              :                            int typMod, Constraint *constr,
    3718              :                            const char *domainName, ObjectAddress *constrAddr)
    3719              : {
    3720              :     Oid         ccoid;
    3721              : 
    3722              :     Assert(constr->contype == CONSTR_NOTNULL);
    3723              : 
    3724              :     /*
    3725              :      * Assign or validate constraint name
    3726              :      */
    3727           92 :     if (constr->conname)
    3728              :     {
    3729            9 :         if (ConstraintNameIsUsed(CONSTRAINT_DOMAIN,
    3730              :                                  domainOid,
    3731            9 :                                  constr->conname))
    3732            0 :             ereport(ERROR,
    3733              :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    3734              :                      errmsg("constraint \"%s\" for domain \"%s\" already exists",
    3735              :                             constr->conname, domainName)));
    3736              :     }
    3737              :     else
    3738           83 :         constr->conname = ChooseConstraintName(domainName,
    3739              :                                                NULL,
    3740              :                                                "not_null",
    3741              :                                                domainNamespace,
    3742              :                                                NIL);
    3743              : 
    3744              :     /*
    3745              :      * Store the constraint in pg_constraint
    3746              :      */
    3747              :     ccoid =
    3748           92 :         CreateConstraintEntry(constr->conname,   /* Constraint Name */
    3749              :                               domainNamespace,  /* namespace */
    3750              :                               CONSTRAINT_NOTNULL,   /* Constraint Type */
    3751              :                               false,    /* Is Deferrable */
    3752              :                               false,    /* Is Deferred */
    3753              :                               true, /* Is Enforced */
    3754           92 :                               !constr->skip_validation, /* Is Validated */
    3755              :                               InvalidOid,   /* no parent constraint */
    3756              :                               InvalidOid,   /* not a relation constraint */
    3757              :                               NULL,
    3758              :                               0,
    3759              :                               0,
    3760              :                               domainOid,    /* domain constraint */
    3761              :                               InvalidOid,   /* no associated index */
    3762              :                               InvalidOid,   /* Foreign key fields */
    3763              :                               NULL,
    3764              :                               NULL,
    3765              :                               NULL,
    3766              :                               NULL,
    3767              :                               0,
    3768              :                               ' ',
    3769              :                               ' ',
    3770              :                               NULL,
    3771              :                               0,
    3772              :                               ' ',
    3773              :                               NULL, /* not an exclusion constraint */
    3774              :                               NULL,
    3775              :                               NULL,
    3776              :                               true, /* is local */
    3777              :                               0,    /* inhcount */
    3778              :                               false,    /* connoinherit */
    3779              :                               false,    /* conperiod */
    3780           92 :                               false);   /* is_internal */
    3781              : 
    3782           92 :     if (constrAddr)
    3783           16 :         ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
    3784           92 : }
    3785              : 
    3786              : 
    3787              : /*
    3788              :  * Execute ALTER TYPE RENAME
    3789              :  */
    3790              : ObjectAddress
    3791           21 : RenameType(RenameStmt *stmt)
    3792              : {
    3793           21 :     List       *names = castNode(List, stmt->object);
    3794           21 :     const char *newTypeName = stmt->newname;
    3795              :     TypeName   *typename;
    3796              :     Oid         typeOid;
    3797              :     Relation    rel;
    3798              :     HeapTuple   tup;
    3799              :     Form_pg_type typTup;
    3800              :     ObjectAddress address;
    3801              : 
    3802              :     /* Make a TypeName so we can use standard type lookup machinery */
    3803           21 :     typename = makeTypeNameFromNameList(names);
    3804           21 :     typeOid = typenameTypeId(NULL, typename);
    3805              : 
    3806              :     /* Look up the type in the type table */
    3807           21 :     rel = table_open(TypeRelationId, RowExclusiveLock);
    3808              : 
    3809           21 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
    3810           21 :     if (!HeapTupleIsValid(tup))
    3811            0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
    3812           21 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    3813              : 
    3814              :     /* check permissions on type */
    3815           21 :     if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
    3816            0 :         aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
    3817              : 
    3818              :     /* ALTER DOMAIN used on a non-domain? */
    3819           21 :     if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
    3820            0 :         ereport(ERROR,
    3821              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3822              :                  errmsg("%s is not a domain",
    3823              :                         format_type_be(typeOid))));
    3824              : 
    3825              :     /*
    3826              :      * If it's a composite type, we need to check that it really is a
    3827              :      * free-standing composite type, and not a table's rowtype. We want people
    3828              :      * to use ALTER TABLE not ALTER TYPE for that case.
    3829              :      */
    3830           22 :     if (typTup->typtype == TYPTYPE_COMPOSITE &&
    3831            1 :         get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
    3832            0 :         ereport(ERROR,
    3833              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3834              :                  errmsg("%s is a table's row type",
    3835              :                         format_type_be(typeOid)),
    3836              :         /* translator: %s is an SQL ALTER command */
    3837              :                  errhint("Use %s instead.",
    3838              :                          "ALTER TABLE")));
    3839              : 
    3840              :     /* don't allow direct alteration of array types, either */
    3841           21 :     if (IsTrueArrayType(typTup))
    3842            0 :         ereport(ERROR,
    3843              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3844              :                  errmsg("cannot alter array type %s",
    3845              :                         format_type_be(typeOid)),
    3846              :                  errhint("You can alter type %s, which will alter the array type as well.",
    3847              :                          format_type_be(typTup->typelem))));
    3848              : 
    3849              :     /* we do allow separate renaming of multirange types, though */
    3850              : 
    3851              :     /*
    3852              :      * If type is composite we need to rename associated pg_class entry too.
    3853              :      * RenameRelationInternal will call RenameTypeInternal automatically.
    3854              :      */
    3855           21 :     if (typTup->typtype == TYPTYPE_COMPOSITE)
    3856            1 :         RenameRelationInternal(typTup->typrelid, newTypeName, false, false);
    3857              :     else
    3858           20 :         RenameTypeInternal(typeOid, newTypeName,
    3859              :                            typTup->typnamespace);
    3860              : 
    3861           21 :     ObjectAddressSet(address, TypeRelationId, typeOid);
    3862              :     /* Clean up */
    3863           21 :     table_close(rel, RowExclusiveLock);
    3864              : 
    3865           21 :     return address;
    3866              : }
    3867              : 
    3868              : /*
    3869              :  * Change the owner of a type.
    3870              :  */
    3871              : ObjectAddress
    3872           73 : AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
    3873              : {
    3874              :     TypeName   *typename;
    3875              :     Oid         typeOid;
    3876              :     Relation    rel;
    3877              :     HeapTuple   tup;
    3878              :     HeapTuple   newtup;
    3879              :     Form_pg_type typTup;
    3880              :     AclResult   aclresult;
    3881              :     ObjectAddress address;
    3882              : 
    3883           73 :     rel = table_open(TypeRelationId, RowExclusiveLock);
    3884              : 
    3885              :     /* Make a TypeName so we can use standard type lookup machinery */
    3886           73 :     typename = makeTypeNameFromNameList(names);
    3887              : 
    3888              :     /* Use LookupTypeName here so that shell types can be processed */
    3889           73 :     tup = LookupTypeName(NULL, typename, NULL, false);
    3890           73 :     if (tup == NULL)
    3891            0 :         ereport(ERROR,
    3892              :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3893              :                  errmsg("type \"%s\" does not exist",
    3894              :                         TypeNameToString(typename))));
    3895           73 :     typeOid = typeTypeId(tup);
    3896              : 
    3897              :     /* Copy the syscache entry so we can scribble on it below */
    3898           73 :     newtup = heap_copytuple(tup);
    3899           73 :     ReleaseSysCache(tup);
    3900           73 :     tup = newtup;
    3901           73 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    3902              : 
    3903              :     /* Don't allow ALTER DOMAIN on a type */
    3904           73 :     if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
    3905            0 :         ereport(ERROR,
    3906              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3907              :                  errmsg("%s is not a domain",
    3908              :                         format_type_be(typeOid))));
    3909              : 
    3910              :     /*
    3911              :      * If it's a composite type, we need to check that it really is a
    3912              :      * free-standing composite type, and not a table's rowtype. We want people
    3913              :      * to use ALTER TABLE not ALTER TYPE for that case.
    3914              :      */
    3915           89 :     if (typTup->typtype == TYPTYPE_COMPOSITE &&
    3916           16 :         get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
    3917            0 :         ereport(ERROR,
    3918              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3919              :                  errmsg("%s is a table's row type",
    3920              :                         format_type_be(typeOid)),
    3921              :         /* translator: %s is an SQL ALTER command */
    3922              :                  errhint("Use %s instead.",
    3923              :                          "ALTER TABLE")));
    3924              : 
    3925              :     /* don't allow direct alteration of array types, either */
    3926           73 :     if (IsTrueArrayType(typTup))
    3927            0 :         ereport(ERROR,
    3928              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3929              :                  errmsg("cannot alter array type %s",
    3930              :                         format_type_be(typeOid)),
    3931              :                  errhint("You can alter type %s, which will alter the array type as well.",
    3932              :                          format_type_be(typTup->typelem))));
    3933              : 
    3934              :     /* don't allow direct alteration of multirange types, either */
    3935           73 :     if (typTup->typtype == TYPTYPE_MULTIRANGE)
    3936              :     {
    3937            4 :         Oid         rangetype = get_multirange_range(typeOid);
    3938              : 
    3939              :         /* We don't expect get_multirange_range to fail, but cope if so */
    3940            4 :         ereport(ERROR,
    3941              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    3942              :                  errmsg("cannot alter multirange type %s",
    3943              :                         format_type_be(typeOid)),
    3944              :                  OidIsValid(rangetype) ?
    3945              :                  errhint("You can alter type %s, which will alter the multirange type as well.",
    3946              :                          format_type_be(rangetype)) : 0));
    3947              :     }
    3948              : 
    3949              :     /*
    3950              :      * If the new owner is the same as the existing owner, consider the
    3951              :      * command to have succeeded.  This is for dump restoration purposes.
    3952              :      */
    3953           69 :     if (typTup->typowner != newOwnerId)
    3954              :     {
    3955              :         /* Superusers can always do it */
    3956            4 :         if (!superuser())
    3957              :         {
    3958              :             /* Otherwise, must be owner of the existing object */
    3959            0 :             if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
    3960            0 :                 aclcheck_error_type(ACLCHECK_NOT_OWNER, typTup->oid);
    3961              : 
    3962              :             /* Must be able to become new owner */
    3963            0 :             check_can_set_role(GetUserId(), newOwnerId);
    3964              : 
    3965              :             /* New owner must have CREATE privilege on namespace */
    3966            0 :             aclresult = object_aclcheck(NamespaceRelationId, typTup->typnamespace,
    3967              :                                         newOwnerId,
    3968              :                                         ACL_CREATE);
    3969            0 :             if (aclresult != ACLCHECK_OK)
    3970            0 :                 aclcheck_error(aclresult, OBJECT_SCHEMA,
    3971            0 :                                get_namespace_name(typTup->typnamespace));
    3972              :         }
    3973              : 
    3974            4 :         AlterTypeOwner_oid(typeOid, newOwnerId, true);
    3975              :     }
    3976              : 
    3977           69 :     ObjectAddressSet(address, TypeRelationId, typeOid);
    3978              : 
    3979              :     /* Clean up */
    3980           69 :     table_close(rel, RowExclusiveLock);
    3981              : 
    3982           69 :     return address;
    3983              : }
    3984              : 
    3985              : /*
    3986              :  * AlterTypeOwner_oid - change type owner unconditionally
    3987              :  *
    3988              :  * This function recurses to handle dependent types (arrays and multiranges).
    3989              :  * It invokes any necessary access object hooks.  If hasDependEntry is true,
    3990              :  * this function modifies the pg_shdepend entry appropriately (this should be
    3991              :  * passed as false only for table rowtypes and dependent types).
    3992              :  *
    3993              :  * This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
    3994              :  * OWNED BY.  It assumes the caller has done all needed checks.
    3995              :  */
    3996              : void
    3997           17 : AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
    3998              : {
    3999              :     Relation    rel;
    4000              :     HeapTuple   tup;
    4001              :     Form_pg_type typTup;
    4002              : 
    4003           17 :     rel = table_open(TypeRelationId, RowExclusiveLock);
    4004              : 
    4005           17 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
    4006           17 :     if (!HeapTupleIsValid(tup))
    4007            0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
    4008           17 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    4009              : 
    4010              :     /*
    4011              :      * If it's a composite type, invoke ATExecChangeOwner so that we fix up
    4012              :      * the pg_class entry properly.  That will call back to
    4013              :      * AlterTypeOwnerInternal to take care of the pg_type entry(s).
    4014              :      */
    4015           17 :     if (typTup->typtype == TYPTYPE_COMPOSITE)
    4016            5 :         ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
    4017              :     else
    4018           12 :         AlterTypeOwnerInternal(typeOid, newOwnerId);
    4019              : 
    4020              :     /* Update owner dependency reference */
    4021           17 :     if (hasDependEntry)
    4022           17 :         changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
    4023              : 
    4024           17 :     InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
    4025              : 
    4026           17 :     ReleaseSysCache(tup);
    4027           17 :     table_close(rel, RowExclusiveLock);
    4028           17 : }
    4029              : 
    4030              : /*
    4031              :  * AlterTypeOwnerInternal - bare-bones type owner change.
    4032              :  *
    4033              :  * This routine simply modifies the owner of a pg_type entry, and recurses
    4034              :  * to handle any dependent types.
    4035              :  */
    4036              : void
    4037          526 : AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
    4038              : {
    4039              :     Relation    rel;
    4040              :     HeapTuple   tup;
    4041              :     Form_pg_type typTup;
    4042              :     Datum       repl_val[Natts_pg_type];
    4043              :     bool        repl_null[Natts_pg_type];
    4044              :     bool        repl_repl[Natts_pg_type];
    4045              :     Acl        *newAcl;
    4046              :     Datum       aclDatum;
    4047              :     bool        isNull;
    4048              : 
    4049          526 :     rel = table_open(TypeRelationId, RowExclusiveLock);
    4050              : 
    4051          526 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
    4052          526 :     if (!HeapTupleIsValid(tup))
    4053            0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
    4054          526 :     typTup = (Form_pg_type) GETSTRUCT(tup);
    4055              : 
    4056          526 :     memset(repl_null, false, sizeof(repl_null));
    4057          526 :     memset(repl_repl, false, sizeof(repl_repl));
    4058              : 
    4059          526 :     repl_repl[Anum_pg_type_typowner - 1] = true;
    4060          526 :     repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
    4061              : 
    4062          526 :     aclDatum = heap_getattr(tup,
    4063              :                             Anum_pg_type_typacl,
    4064              :                             RelationGetDescr(rel),
    4065              :                             &isNull);
    4066              :     /* Null ACLs do not require changes */
    4067          526 :     if (!isNull)
    4068              :     {
    4069            1 :         newAcl = aclnewowner(DatumGetAclP(aclDatum),
    4070              :                              typTup->typowner, newOwnerId);
    4071            1 :         repl_repl[Anum_pg_type_typacl - 1] = true;
    4072            1 :         repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
    4073              :     }
    4074              : 
    4075          526 :     tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
    4076              :                             repl_repl);
    4077              : 
    4078          526 :     CatalogTupleUpdate(rel, &tup->t_self, tup);
    4079              : 
    4080              :     /* If it has an array type, update that too */
    4081          526 :     if (OidIsValid(typTup->typarray))
    4082          263 :         AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
    4083              : 
    4084              :     /* If it is a range type, update the associated multirange too */
    4085          526 :     if (typTup->typtype == TYPTYPE_RANGE)
    4086              :     {
    4087            8 :         Oid         multirange_typeid = get_range_multirange(typeOid);
    4088              : 
    4089            8 :         if (!OidIsValid(multirange_typeid))
    4090            0 :             ereport(ERROR,
    4091              :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    4092              :                      errmsg("could not find multirange type for data type %s",
    4093              :                             format_type_be(typeOid))));
    4094            8 :         AlterTypeOwnerInternal(multirange_typeid, newOwnerId);
    4095              :     }
    4096              : 
    4097              :     /* Clean up */
    4098          526 :     table_close(rel, RowExclusiveLock);
    4099          526 : }
    4100              : 
    4101              : /*
    4102              :  * Execute ALTER TYPE SET SCHEMA
    4103              :  */
    4104              : ObjectAddress
    4105           12 : AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype,
    4106              :                    Oid *oldschema)
    4107              : {
    4108              :     TypeName   *typename;
    4109              :     Oid         typeOid;
    4110              :     Oid         nspOid;
    4111              :     Oid         oldNspOid;
    4112              :     ObjectAddresses *objsMoved;
    4113              :     ObjectAddress myself;
    4114              : 
    4115              :     /* Make a TypeName so we can use standard type lookup machinery */
    4116           12 :     typename = makeTypeNameFromNameList(names);
    4117           12 :     typeOid = typenameTypeId(NULL, typename);
    4118              : 
    4119              :     /* Don't allow ALTER DOMAIN on a non-domain type */
    4120           12 :     if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
    4121            0 :         ereport(ERROR,
    4122              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    4123              :                  errmsg("%s is not a domain",
    4124              :                         format_type_be(typeOid))));
    4125              : 
    4126              :     /* get schema OID and check its permissions */
    4127           12 :     nspOid = LookupCreationNamespace(newschema);
    4128              : 
    4129           12 :     objsMoved = new_object_addresses();
    4130           12 :     oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, false, objsMoved);
    4131           12 :     free_object_addresses(objsMoved);
    4132              : 
    4133           12 :     if (oldschema)
    4134           12 :         *oldschema = oldNspOid;
    4135              : 
    4136           12 :     ObjectAddressSet(myself, TypeRelationId, typeOid);
    4137              : 
    4138           12 :     return myself;
    4139              : }
    4140              : 
    4141              : /*
    4142              :  * ALTER TYPE SET SCHEMA, where the caller has already looked up the OIDs
    4143              :  * of the type and the target schema and checked the schema's privileges.
    4144              :  *
    4145              :  * If ignoreDependent is true, we silently ignore dependent types
    4146              :  * (array types and table rowtypes) rather than raising errors.
    4147              :  *
    4148              :  * This entry point is exported for use by AlterObjectNamespace_oid,
    4149              :  * which doesn't want errors when it passes OIDs of dependent types.
    4150              :  *
    4151              :  * Returns the type's old namespace OID, or InvalidOid if we did nothing.
    4152              :  */
    4153              : Oid
    4154           20 : AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, bool ignoreDependent,
    4155              :                        ObjectAddresses *objsMoved)
    4156              : {
    4157              :     Oid         elemOid;
    4158              : 
    4159              :     /* check permissions on type */
    4160           20 :     if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
    4161            0 :         aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
    4162              : 
    4163              :     /* don't allow direct alteration of array types */
    4164           20 :     elemOid = get_element_type(typeOid);
    4165           20 :     if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
    4166              :     {
    4167            4 :         if (ignoreDependent)
    4168            4 :             return InvalidOid;
    4169            0 :         ereport(ERROR,
    4170              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    4171              :                  errmsg("cannot alter array type %s",
    4172              :                         format_type_be(typeOid)),
    4173              :                  errhint("You can alter type %s, which will alter the array type as well.",
    4174              :                          format_type_be(elemOid))));
    4175              :     }
    4176              : 
    4177              :     /* and do the work */
    4178           16 :     return AlterTypeNamespaceInternal(typeOid, nspOid,
    4179              :                                       false,    /* isImplicitArray */
    4180              :                                       ignoreDependent,  /* ignoreDependent */
    4181              :                                       true, /* errorOnTableType */
    4182              :                                       objsMoved);
    4183              : }
    4184              : 
    4185              : /*
    4186              :  * Move specified type to new namespace.
    4187              :  *
    4188              :  * Caller must have already checked privileges.
    4189              :  *
    4190              :  * The function automatically recurses to process the type's array type,
    4191              :  * if any.  isImplicitArray should be true only when doing this internal
    4192              :  * recursion (outside callers must never try to move an array type directly).
    4193              :  *
    4194              :  * If ignoreDependent is true, we silently don't process table types.
    4195              :  *
    4196              :  * If errorOnTableType is true, the function errors out if the type is
    4197              :  * a table type.  ALTER TABLE has to be used to move a table to a new
    4198              :  * namespace.  (This flag is ignored if ignoreDependent is true.)
    4199              :  *
    4200              :  * We also do nothing if the type is already listed in *objsMoved.
    4201              :  * After a successful move, we add the type to *objsMoved.
    4202              :  *
    4203              :  * Returns the type's old namespace OID, or InvalidOid if we did nothing.
    4204              :  */
    4205              : Oid
    4206          141 : AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
    4207              :                            bool isImplicitArray,
    4208              :                            bool ignoreDependent,
    4209              :                            bool errorOnTableType,
    4210              :                            ObjectAddresses *objsMoved)
    4211              : {
    4212              :     Relation    rel;
    4213              :     HeapTuple   tup;
    4214              :     Form_pg_type typform;
    4215              :     Oid         oldNspOid;
    4216              :     Oid         arrayOid;
    4217              :     bool        isCompositeType;
    4218              :     ObjectAddress thisobj;
    4219              : 
    4220              :     /*
    4221              :      * Make sure we haven't moved this object previously.
    4222              :      */
    4223          141 :     thisobj.classId = TypeRelationId;
    4224          141 :     thisobj.objectId = typeOid;
    4225          141 :     thisobj.objectSubId = 0;
    4226              : 
    4227          141 :     if (object_address_present(&thisobj, objsMoved))
    4228            0 :         return InvalidOid;
    4229              : 
    4230          141 :     rel = table_open(TypeRelationId, RowExclusiveLock);
    4231              : 
    4232          141 :     tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
    4233          141 :     if (!HeapTupleIsValid(tup))
    4234            0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
    4235          141 :     typform = (Form_pg_type) GETSTRUCT(tup);
    4236              : 
    4237          141 :     oldNspOid = typform->typnamespace;
    4238          141 :     arrayOid = typform->typarray;
    4239              : 
    4240              :     /* If the type is already there, we scan skip these next few checks. */
    4241          141 :     if (oldNspOid != nspOid)
    4242              :     {
    4243              :         /* common checks on switching namespaces */
    4244          117 :         CheckSetNamespace(oldNspOid, nspOid);
    4245              : 
    4246              :         /* check for duplicate name (more friendly than unique-index failure) */
    4247          117 :         if (SearchSysCacheExists2(TYPENAMENSP,
    4248              :                                   NameGetDatum(&typform->typname),
    4249              :                                   ObjectIdGetDatum(nspOid)))
    4250            0 :             ereport(ERROR,
    4251              :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    4252              :                      errmsg("type \"%s\" already exists in schema \"%s\"",
    4253              :                             NameStr(typform->typname),
    4254              :                             get_namespace_name(nspOid))));
    4255              :     }
    4256              : 
    4257              :     /* Detect whether type is a composite type (but not a table rowtype) */
    4258          141 :     isCompositeType =
    4259          206 :         (typform->typtype == TYPTYPE_COMPOSITE &&
    4260           65 :          get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
    4261              : 
    4262              :     /* Enforce not-table-type if requested */
    4263          141 :     if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType)
    4264              :     {
    4265           56 :         if (ignoreDependent)
    4266              :         {
    4267            1 :             table_close(rel, RowExclusiveLock);
    4268            1 :             return InvalidOid;
    4269              :         }
    4270           55 :         if (errorOnTableType)
    4271            0 :             ereport(ERROR,
    4272              :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    4273              :                      errmsg("%s is a table's row type",
    4274              :                             format_type_be(typeOid)),
    4275              :             /* translator: %s is an SQL ALTER command */
    4276              :                      errhint("Use %s instead.", "ALTER TABLE")));
    4277              :     }
    4278              : 
    4279          140 :     if (oldNspOid != nspOid)
    4280              :     {
    4281              :         /* OK, modify the pg_type row */
    4282              : 
    4283              :         /* tup is a copy, so we can scribble directly on it */
    4284          116 :         typform->typnamespace = nspOid;
    4285              : 
    4286          116 :         CatalogTupleUpdate(rel, &tup->t_self, tup);
    4287              :     }
    4288              : 
    4289              :     /*
    4290              :      * Composite types have pg_class entries.
    4291              :      *
    4292              :      * We need to modify the pg_class tuple as well to reflect the change of
    4293              :      * schema.
    4294              :      */
    4295          140 :     if (isCompositeType)
    4296              :     {
    4297              :         Relation    classRel;
    4298              : 
    4299            9 :         classRel = table_open(RelationRelationId, RowExclusiveLock);
    4300              : 
    4301            9 :         AlterRelationNamespaceInternal(classRel, typform->typrelid,
    4302              :                                        oldNspOid, nspOid,
    4303              :                                        false, objsMoved);
    4304              : 
    4305            9 :         table_close(classRel, RowExclusiveLock);
    4306              : 
    4307              :         /*
    4308              :          * Check for constraints associated with the composite type (we don't
    4309              :          * currently support this, but probably will someday).
    4310              :          */
    4311            9 :         AlterConstraintNamespaces(typform->typrelid, oldNspOid,
    4312              :                                   nspOid, false, objsMoved);
    4313              :     }
    4314              :     else
    4315              :     {
    4316              :         /* If it's a domain, it might have constraints */
    4317          131 :         if (typform->typtype == TYPTYPE_DOMAIN)
    4318            4 :             AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
    4319              :                                       objsMoved);
    4320              :     }
    4321              : 
    4322              :     /*
    4323              :      * Update dependency on schema, if any --- a table rowtype has not got
    4324              :      * one, and neither does an implicit array.
    4325              :      */
    4326          140 :     if (oldNspOid != nspOid &&
    4327          111 :         (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
    4328           69 :         !isImplicitArray)
    4329           11 :         if (changeDependencyFor(TypeRelationId, typeOid,
    4330              :                                 NamespaceRelationId, oldNspOid, nspOid) != 1)
    4331            0 :             elog(ERROR, "could not change schema dependency for type \"%s\"",
    4332              :                  format_type_be(typeOid));
    4333              : 
    4334          140 :     InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
    4335              : 
    4336          140 :     heap_freetuple(tup);
    4337              : 
    4338          140 :     table_close(rel, RowExclusiveLock);
    4339              : 
    4340          140 :     add_exact_object_address(&thisobj, objsMoved);
    4341              : 
    4342              :     /* Recursively alter the associated array type, if any */
    4343          140 :     if (OidIsValid(arrayOid))
    4344           70 :         AlterTypeNamespaceInternal(arrayOid, nspOid,
    4345              :                                    true,    /* isImplicitArray */
    4346              :                                    false,   /* ignoreDependent */
    4347              :                                    true,    /* errorOnTableType */
    4348              :                                    objsMoved);
    4349              : 
    4350          140 :     return oldNspOid;
    4351              : }
    4352              : 
    4353              : /*
    4354              :  * AlterType
    4355              :  *      ALTER TYPE <type> SET (option = ...)
    4356              :  *
    4357              :  * NOTE: the set of changes that can be allowed here is constrained by many
    4358              :  * non-obvious implementation restrictions.  Tread carefully when considering
    4359              :  * adding new flexibility.
    4360              :  */
    4361              : ObjectAddress
    4362           36 : AlterType(AlterTypeStmt *stmt)
    4363              : {
    4364              :     ObjectAddress address;
    4365              :     Relation    catalog;
    4366              :     TypeName   *typename;
    4367              :     HeapTuple   tup;
    4368              :     Oid         typeOid;
    4369              :     Form_pg_type typForm;
    4370           36 :     bool        requireSuper = false;
    4371              :     AlterTypeRecurseParams atparams;
    4372              :     ListCell   *pl;
    4373              : 
    4374           36 :     catalog = table_open(TypeRelationId, RowExclusiveLock);
    4375              : 
    4376              :     /* Make a TypeName so we can use standard type lookup machinery */
    4377           36 :     typename = makeTypeNameFromNameList(stmt->typeName);
    4378           36 :     tup = typenameType(NULL, typename, NULL);
    4379              : 
    4380           32 :     typeOid = typeTypeId(tup);
    4381           32 :     typForm = (Form_pg_type) GETSTRUCT(tup);
    4382              : 
    4383              :     /* Process options */
    4384           32 :     memset(&atparams, 0, sizeof(atparams));
    4385           91 :     foreach(pl, stmt->options)
    4386              :     {
    4387           63 :         DefElem    *defel = (DefElem *) lfirst(pl);
    4388              : 
    4389           63 :         if (strcmp(defel->defname, "storage") == 0)
    4390              :         {
    4391            8 :             char       *a = defGetString(defel);
    4392              : 
    4393            8 :             if (pg_strcasecmp(a, "plain") == 0)
    4394            4 :                 atparams.storage = TYPSTORAGE_PLAIN;
    4395            4 :             else if (pg_strcasecmp(a, "external") == 0)
    4396            0 :                 atparams.storage = TYPSTORAGE_EXTERNAL;
    4397            4 :             else if (pg_strcasecmp(a, "extended") == 0)
    4398            4 :                 atparams.storage = TYPSTORAGE_EXTENDED;
    4399            0 :             else if (pg_strcasecmp(a, "main") == 0)
    4400            0 :                 atparams.storage = TYPSTORAGE_MAIN;
    4401              :             else
    4402            0 :                 ereport(ERROR,
    4403              :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4404              :                          errmsg("storage \"%s\" not recognized", a)));
    4405              : 
    4406              :             /*
    4407              :              * Validate the storage request.  If the type isn't varlena, it
    4408              :              * certainly doesn't support non-PLAIN storage.
    4409              :              */
    4410            8 :             if (atparams.storage != TYPSTORAGE_PLAIN && typForm->typlen != -1)
    4411            0 :                 ereport(ERROR,
    4412              :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    4413              :                          errmsg("fixed-size types must have storage PLAIN")));
    4414              : 
    4415              :             /*
    4416              :              * Switching from PLAIN to non-PLAIN is allowed, but it requires
    4417              :              * superuser, since we can't validate that the type's C functions
    4418              :              * will support it.  Switching from non-PLAIN to PLAIN is
    4419              :              * disallowed outright, because it's not practical to ensure that
    4420              :              * no tables have toasted values of the type.  Switching among
    4421              :              * different non-PLAIN settings is OK, since it just constitutes a
    4422              :              * change in the strategy requested for columns created in the
    4423              :              * future.
    4424              :              */
    4425            8 :             if (atparams.storage != TYPSTORAGE_PLAIN &&
    4426            4 :                 typForm->typstorage == TYPSTORAGE_PLAIN)
    4427            0 :                 requireSuper = true;
    4428            8 :             else if (atparams.storage == TYPSTORAGE_PLAIN &&
    4429            4 :                      typForm->typstorage != TYPSTORAGE_PLAIN)
    4430            4 :                 ereport(ERROR,
    4431              :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    4432              :                          errmsg("cannot change type's storage to PLAIN")));
    4433              : 
    4434            4 :             atparams.updateStorage = true;
    4435              :         }
    4436           55 :         else if (strcmp(defel->defname, "receive") == 0)
    4437              :         {
    4438           15 :             if (defel->arg != NULL)
    4439           15 :                 atparams.receiveOid =
    4440           15 :                     findTypeReceiveFunction(defGetQualifiedName(defel),
    4441              :                                             typeOid);
    4442              :             else
    4443            0 :                 atparams.receiveOid = InvalidOid;   /* NONE, remove function */
    4444           15 :             atparams.updateReceive = true;
    4445              :             /* Replacing an I/O function requires superuser. */
    4446           15 :             requireSuper = true;
    4447              :         }
    4448           40 :         else if (strcmp(defel->defname, "send") == 0)
    4449              :         {
    4450           15 :             if (defel->arg != NULL)
    4451           15 :                 atparams.sendOid =
    4452           15 :                     findTypeSendFunction(defGetQualifiedName(defel),
    4453              :                                          typeOid);
    4454              :             else
    4455            0 :                 atparams.sendOid = InvalidOid;  /* NONE, remove function */
    4456           15 :             atparams.updateSend = true;
    4457              :             /* Replacing an I/O function requires superuser. */
    4458           15 :             requireSuper = true;
    4459              :         }
    4460           25 :         else if (strcmp(defel->defname, "typmod_in") == 0)
    4461              :         {
    4462            4 :             if (defel->arg != NULL)
    4463            4 :                 atparams.typmodinOid =
    4464            4 :                     findTypeTypmodinFunction(defGetQualifiedName(defel));
    4465              :             else
    4466            0 :                 atparams.typmodinOid = InvalidOid;  /* NONE, remove function */
    4467            4 :             atparams.updateTypmodin = true;
    4468              :             /* Replacing an I/O function requires superuser. */
    4469            4 :             requireSuper = true;
    4470              :         }
    4471           21 :         else if (strcmp(defel->defname, "typmod_out") == 0)
    4472              :         {
    4473            4 :             if (defel->arg != NULL)
    4474            4 :                 atparams.typmodoutOid =
    4475            4 :                     findTypeTypmodoutFunction(defGetQualifiedName(defel));
    4476              :             else
    4477            0 :                 atparams.typmodoutOid = InvalidOid; /* NONE, remove function */
    4478            4 :             atparams.updateTypmodout = true;
    4479              :             /* Replacing an I/O function requires superuser. */
    4480            4 :             requireSuper = true;
    4481              :         }
    4482           17 :         else if (strcmp(defel->defname, "analyze") == 0)
    4483              :         {
    4484            6 :             if (defel->arg != NULL)
    4485            6 :                 atparams.analyzeOid =
    4486            6 :                     findTypeAnalyzeFunction(defGetQualifiedName(defel),
    4487              :                                             typeOid);
    4488              :             else
    4489            0 :                 atparams.analyzeOid = InvalidOid;   /* NONE, remove function */
    4490            6 :             atparams.updateAnalyze = true;
    4491              :             /* Replacing an analyze function requires superuser. */
    4492            6 :             requireSuper = true;
    4493              :         }
    4494           11 :         else if (strcmp(defel->defname, "subscript") == 0)
    4495              :         {
    4496           11 :             if (defel->arg != NULL)
    4497           11 :                 atparams.subscriptOid =
    4498           11 :                     findTypeSubscriptingFunction(defGetQualifiedName(defel),
    4499              :                                                  typeOid);
    4500              :             else
    4501            0 :                 atparams.subscriptOid = InvalidOid; /* NONE, remove function */
    4502           11 :             atparams.updateSubscript = true;
    4503              :             /* Replacing a subscript function requires superuser. */
    4504           11 :             requireSuper = true;
    4505              :         }
    4506              : 
    4507              :         /*
    4508              :          * The rest of the options that CREATE accepts cannot be changed.
    4509              :          * Check for them so that we can give a meaningful error message.
    4510              :          */
    4511            0 :         else if (strcmp(defel->defname, "input") == 0 ||
    4512            0 :                  strcmp(defel->defname, "output") == 0 ||
    4513            0 :                  strcmp(defel->defname, "internallength") == 0 ||
    4514            0 :                  strcmp(defel->defname, "passedbyvalue") == 0 ||
    4515            0 :                  strcmp(defel->defname, "alignment") == 0 ||
    4516            0 :                  strcmp(defel->defname, "like") == 0 ||
    4517            0 :                  strcmp(defel->defname, "category") == 0 ||
    4518            0 :                  strcmp(defel->defname, "preferred") == 0 ||
    4519            0 :                  strcmp(defel->defname, "default") == 0 ||
    4520            0 :                  strcmp(defel->defname, "element") == 0 ||
    4521            0 :                  strcmp(defel->defname, "delimiter") == 0 ||
    4522            0 :                  strcmp(defel->defname, "collatable") == 0)
    4523            0 :             ereport(ERROR,
    4524              :                     (errcode(ERRCODE_SYNTAX_ERROR),
    4525              :                      errmsg("type attribute \"%s\" cannot be changed",
    4526              :                             defel->defname)));
    4527              :         else
    4528            0 :             ereport(ERROR,
    4529              :                     (errcode(ERRCODE_SYNTAX_ERROR),
    4530              :                      errmsg("type attribute \"%s\" not recognized",
    4531              :                             defel->defname)));
    4532              :     }
    4533              : 
    4534              :     /*
    4535              :      * Permissions check.  Require superuser if we decided the command
    4536              :      * requires that, else must own the type.
    4537              :      */
    4538           28 :     if (requireSuper)
    4539              :     {
    4540           24 :         if (!superuser())
    4541            0 :             ereport(ERROR,
    4542              :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    4543              :                      errmsg("must be superuser to alter a type")));
    4544              :     }
    4545              :     else
    4546              :     {
    4547            4 :         if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
    4548            0 :             aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid);
    4549              :     }
    4550              : 
    4551              :     /*
    4552              :      * We disallow all forms of ALTER TYPE SET on types that aren't plain base
    4553              :      * types.  It would for example be highly unsafe, not to mention
    4554              :      * pointless, to change the send/receive functions for a composite type.
    4555              :      * Moreover, pg_dump has no support for changing these properties on
    4556              :      * non-base types.  We might weaken this someday, but not now.
    4557              :      *
    4558              :      * Note: if you weaken this enough to allow composite types, be sure to
    4559              :      * adjust the GenerateTypeDependencies call in AlterTypeRecurse.
    4560              :      */
    4561           28 :     if (typForm->typtype != TYPTYPE_BASE)
    4562            0 :         ereport(ERROR,
    4563              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    4564              :                  errmsg("%s is not a base type",
    4565              :                         format_type_be(typeOid))));
    4566              : 
    4567              :     /*
    4568              :      * For the same reasons, don't allow direct alteration of array types.
    4569              :      */
    4570           28 :     if (IsTrueArrayType(typForm))
    4571            0 :         ereport(ERROR,
    4572              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    4573              :                  errmsg("%s is not a base type",
    4574              :                         format_type_be(typeOid))));
    4575              : 
    4576              :     /* OK, recursively update this type and any arrays/domains over it */
    4577           28 :     AlterTypeRecurse(typeOid, false, tup, catalog, &atparams);
    4578              : 
    4579              :     /* Clean up */
    4580           28 :     ReleaseSysCache(tup);
    4581              : 
    4582           28 :     table_close(catalog, RowExclusiveLock);
    4583              : 
    4584           28 :     ObjectAddressSet(address, TypeRelationId, typeOid);
    4585              : 
    4586           28 :     return address;
    4587              : }
    4588              : 
    4589              : /*
    4590              :  * AlterTypeRecurse: one recursion step for AlterType()
    4591              :  *
    4592              :  * Apply the changes specified by "atparams" to the type identified by
    4593              :  * "typeOid", whose existing pg_type tuple is "tup".  If necessary,
    4594              :  * recursively update its array type as well.  Then search for any domains
    4595              :  * over this type, and recursively apply (most of) the same changes to those
    4596              :  * domains.
    4597              :  *
    4598              :  * We need this because the system generally assumes that a domain inherits
    4599              :  * many properties from its base type.  See DefineDomain() above for details
    4600              :  * of what is inherited.  Arrays inherit a smaller number of properties,
    4601              :  * but not none.
    4602              :  *
    4603              :  * There's a race condition here, in that some other transaction could
    4604              :  * concurrently add another domain atop this base type; we'd miss updating
    4605              :  * that one.  Hence, be wary of allowing ALTER TYPE to change properties for
    4606              :  * which it'd be really fatal for a domain to be out of sync with its base
    4607              :  * type (typlen, for example).  In practice, races seem unlikely to be an
    4608              :  * issue for plausible use-cases for ALTER TYPE.  If one does happen, it could
    4609              :  * be fixed by re-doing the same ALTER TYPE once all prior transactions have
    4610              :  * committed.
    4611              :  */
    4612              : static void
    4613           40 : AlterTypeRecurse(Oid typeOid, bool isImplicitArray,
    4614              :                  HeapTuple tup, Relation catalog,
    4615              :                  AlterTypeRecurseParams *atparams)
    4616              : {
    4617              :     Datum       values[Natts_pg_type];
    4618              :     bool        nulls[Natts_pg_type];
    4619              :     bool        replaces[Natts_pg_type];
    4620              :     HeapTuple   newtup;
    4621              :     SysScanDesc scan;
    4622              :     ScanKeyData key[1];
    4623              :     HeapTuple   domainTup;
    4624              : 
    4625              :     /* Since this function recurses, it could be driven to stack overflow */
    4626           40 :     check_stack_depth();
    4627              : 
    4628              :     /* Update the current type's tuple */
    4629           40 :     memset(values, 0, sizeof(values));
    4630           40 :     memset(nulls, 0, sizeof(nulls));
    4631           40 :     memset(replaces, 0, sizeof(replaces));
    4632              : 
    4633           40 :     if (atparams->updateStorage)
    4634              :     {
    4635            8 :         replaces[Anum_pg_type_typstorage - 1] = true;
    4636            8 :         values[Anum_pg_type_typstorage - 1] = CharGetDatum(atparams->storage);
    4637              :     }
    4638           40 :     if (atparams->updateReceive)
    4639              :     {
    4640           15 :         replaces[Anum_pg_type_typreceive - 1] = true;
    4641           15 :         values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(atparams->receiveOid);
    4642              :     }
    4643           40 :     if (atparams->updateSend)
    4644              :     {
    4645           19 :         replaces[Anum_pg_type_typsend - 1] = true;
    4646           19 :         values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(atparams->sendOid);
    4647              :     }
    4648           40 :     if (atparams->updateTypmodin)
    4649              :     {
    4650            8 :         replaces[Anum_pg_type_typmodin - 1] = true;
    4651            8 :         values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(atparams->typmodinOid);
    4652              :     }
    4653           40 :     if (atparams->updateTypmodout)
    4654              :     {
    4655            8 :         replaces[Anum_pg_type_typmodout - 1] = true;
    4656            8 :         values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(atparams->typmodoutOid);
    4657              :     }
    4658           40 :     if (atparams->updateAnalyze)
    4659              :     {
    4660           10 :         replaces[Anum_pg_type_typanalyze - 1] = true;
    4661           10 :         values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(atparams->analyzeOid);
    4662              :     }
    4663           40 :     if (atparams->updateSubscript)
    4664              :     {
    4665           11 :         replaces[Anum_pg_type_typsubscript - 1] = true;
    4666           11 :         values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(atparams->subscriptOid);
    4667              :     }
    4668              : 
    4669           40 :     newtup = heap_modify_tuple(tup, RelationGetDescr(catalog),
    4670              :                                values, nulls, replaces);
    4671              : 
    4672           40 :     CatalogTupleUpdate(catalog, &newtup->t_self, newtup);
    4673              : 
    4674              :     /* Rebuild dependencies for this type */
    4675           40 :     GenerateTypeDependencies(newtup,
    4676              :                              catalog,
    4677              :                              NULL,  /* don't have defaultExpr handy */
    4678              :                              NULL,  /* don't have typacl handy */
    4679              :                              0, /* we rejected composite types above */
    4680              :                              isImplicitArray,   /* it might be an array */
    4681              :                              isImplicitArray,   /* dependent iff it's array */
    4682              :                              false, /* don't touch extension membership */
    4683              :                              true);
    4684              : 
    4685           40 :     InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
    4686              : 
    4687              :     /*
    4688              :      * Arrays inherit their base type's typmodin and typmodout, but none of
    4689              :      * the other properties we're concerned with here.  Recurse to the array
    4690              :      * type if needed.
    4691              :      */
    4692           40 :     if (!isImplicitArray &&
    4693           36 :         (atparams->updateTypmodin || atparams->updateTypmodout))
    4694              :     {
    4695            4 :         Oid         arrtypoid = ((Form_pg_type) GETSTRUCT(newtup))->typarray;
    4696              : 
    4697            4 :         if (OidIsValid(arrtypoid))
    4698              :         {
    4699              :             HeapTuple   arrtup;
    4700              :             AlterTypeRecurseParams arrparams;
    4701              : 
    4702            4 :             arrtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrtypoid));
    4703            4 :             if (!HeapTupleIsValid(arrtup))
    4704            0 :                 elog(ERROR, "cache lookup failed for type %u", arrtypoid);
    4705              : 
    4706            4 :             memset(&arrparams, 0, sizeof(arrparams));
    4707            4 :             arrparams.updateTypmodin = atparams->updateTypmodin;
    4708            4 :             arrparams.updateTypmodout = atparams->updateTypmodout;
    4709            4 :             arrparams.typmodinOid = atparams->typmodinOid;
    4710            4 :             arrparams.typmodoutOid = atparams->typmodoutOid;
    4711              : 
    4712            4 :             AlterTypeRecurse(arrtypoid, true, arrtup, catalog, &arrparams);
    4713              : 
    4714            4 :             ReleaseSysCache(arrtup);
    4715              :         }
    4716              :     }
    4717              : 
    4718              :     /*
    4719              :      * Now we need to recurse to domains.  However, some properties are not
    4720              :      * inherited by domains, so clear the update flags for those.
    4721              :      */
    4722           40 :     atparams->updateReceive = false; /* domains use F_DOMAIN_RECV */
    4723           40 :     atparams->updateTypmodin = false;    /* domains don't have typmods */
    4724           40 :     atparams->updateTypmodout = false;
    4725           40 :     atparams->updateSubscript = false;   /* domains don't have subscriptors */
    4726              : 
    4727              :     /* Skip the scan if nothing remains to be done */
    4728           40 :     if (!(atparams->updateStorage ||
    4729           32 :           atparams->updateSend ||
    4730           13 :           atparams->updateAnalyze))
    4731           11 :         return;
    4732              : 
    4733              :     /* Search pg_type for possible domains over this type */
    4734           29 :     ScanKeyInit(&key[0],
    4735              :                 Anum_pg_type_typbasetype,
    4736              :                 BTEqualStrategyNumber, F_OIDEQ,
    4737              :                 ObjectIdGetDatum(typeOid));
    4738              : 
    4739           29 :     scan = systable_beginscan(catalog, InvalidOid, false,
    4740              :                               NULL, 1, key);
    4741              : 
    4742           37 :     while ((domainTup = systable_getnext(scan)) != NULL)
    4743              :     {
    4744            8 :         Form_pg_type domainForm = (Form_pg_type) GETSTRUCT(domainTup);
    4745              : 
    4746              :         /*
    4747              :          * Shouldn't have a nonzero typbasetype in a non-domain, but let's
    4748              :          * check
    4749              :          */
    4750            8 :         if (domainForm->typtype != TYPTYPE_DOMAIN)
    4751            0 :             continue;
    4752              : 
    4753            8 :         AlterTypeRecurse(domainForm->oid, false, domainTup, catalog, atparams);
    4754              :     }
    4755              : 
    4756           29 :     systable_endscan(scan);
    4757              : }
        

Generated by: LCOV version 2.0-1