LCOV - code coverage report
Current view: top level - src/backend/commands - typecmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 964 1186 81.3 %
Date: 2020-06-01 09:07:10 Functions: 38 39 97.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13