LCOV - differential code coverage report
Current view: top level - src/backend/commands - typecmds.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 82.5 % 1311 1081 4 22 105 99 53 429 18 581 74 459 4 19
Current Date: 2023-04-08 15:15:32 Functions: 97.7 % 43 42 1 35 4 3 1 35
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a