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

Generated by: LCOV version 1.16