]> granicus.if.org Git - postgresql/blobdiff - src/backend/commands/typecmds.c
Improve internationalization of messages involving type names
[postgresql] / src / backend / commands / typecmds.c
index 1ba6d5e6e99c0132ed2d220800b67819e2848fd6..3de29b766dea32293f1fdded61f327940381eab5 100644 (file)
@@ -3,7 +3,7 @@
  * typecmds.c
  *       Routines for SQL commands that manipulate types (and domains).
  *
- * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  */
 #include "postgres.h"
 
-#include "access/genam.h"
-#include "access/heapam.h"
 #include "access/htup_details.h"
 #include "access/xact.h"
+#include "catalog/binary_upgrade.h"
 #include "catalog/catalog.h"
-#include "catalog/dependency.h"
 #include "catalog/heap.h"
-#include "catalog/indexing.h"
+#include "catalog/objectaccess.h"
+#include "catalog/pg_am.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_constraint.h"
+#include "catalog/pg_constraint_fn.h"
 #include "catalog/pg_depend.h"
 #include "catalog/pg_enum.h"
 #include "catalog/pg_language.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
-#include "optimizer/planner.h"
 #include "optimizer/var.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_func.h"
 #include "parser/parse_type.h"
-#include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
+#include "utils/ruleutils.h"
+#include "utils/snapmgr.h"
 #include "utils/syscache.h"
-#include "utils/tqual.h"
 
 
 /* result structure for get_rels_with_domain() */
@@ -83,7 +82,7 @@ typedef struct
        /* atts[] is of allocated length RelationGetNumberOfAttributes(rel) */
 } RelToCheck;
 
-/* Potentially set by contrib/pg_upgrade_support functions */
+/* Potentially set by pg_upgrade_support functions */
 Oid                    binary_upgrade_next_array_pg_type_oid = InvalidOid;
 
 static void makeRangeConstructors(const char *name, Oid namespace,
@@ -104,14 +103,14 @@ static void checkEnumOwner(HeapTuple tup);
 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
                                        Oid baseTypeOid,
                                        int typMod, Constraint *constr,
-                                       char *domainName);
+                                       char *domainName, ObjectAddress *constrAddr);
 
 
 /*
  * DefineType
  *             Registers a new base type.
  */
-Oid
+ObjectAddress
 DefineType(List *names, List *parameters)
 {
        char       *typeName;
@@ -163,6 +162,7 @@ DefineType(List *names, List *parameters)
        Oid                     typoid;
        Oid                     resulttype;
        ListCell   *pl;
+       ObjectAddress address;
 
        /*
         * As of Postgres 8.4, we require superuser privilege to create a base
@@ -216,7 +216,8 @@ DefineType(List *names, List *parameters)
         */
        if (!OidIsValid(typoid))
        {
-               typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
+               address = TypeShellMake(typeName, typeNamespace, GetUserId());
+               typoid = address.objectId;
                /* Make new shell type visible for modification below */
                CommandCounterIncrement();
 
@@ -225,7 +226,7 @@ DefineType(List *names, List *parameters)
                 * creating the shell type was all we're supposed to do.
                 */
                if (parameters == NIL)
-                       return InvalidOid;
+                       return address;
        }
        else
        {
@@ -449,14 +450,14 @@ DefineType(List *names, List *parameters)
                {
                        /* backwards-compatibility hack */
                        ereport(WARNING,
-                                       (errmsg("changing return type of function %s from \"opaque\" to %s",
-                                                       NameListToString(inputName), typeName)));
+                                       (errmsg("changing return type of function %s from \"%s\" to \"%s\"",
+                                                       NameListToString(inputName), "opaque", typeName)));
                        SetFunctionReturnType(inputOid, typoid);
                }
                else
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                        errmsg("type input function %s must return type %s",
+                                        errmsg("type input function %s must return type \"%s\"",
                                                        NameListToString(inputName), typeName)));
        }
        resulttype = get_func_rettype(outputOid);
@@ -466,15 +467,15 @@ DefineType(List *names, List *parameters)
                {
                        /* backwards-compatibility hack */
                        ereport(WARNING,
-                                       (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"",
-                                                       NameListToString(outputName))));
+                                       (errmsg("changing return type of function %s from \"%s\" to \"%s\"",
+                                                       NameListToString(outputName), "opaque", "cstring")));
                        SetFunctionReturnType(outputOid, CSTRINGOID);
                }
                else
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                          errmsg("type output function %s must return type \"cstring\"",
-                                         NameListToString(outputName))));
+                          errmsg("type output function %s must return type \"%s\"",
+                                         NameListToString(outputName), "cstring")));
        }
        if (receiveOid)
        {
@@ -482,7 +483,7 @@ DefineType(List *names, List *parameters)
                if (resulttype != typoid)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                        errmsg("type receive function %s must return type %s",
+                                        errmsg("type receive function %s must return type \"%s\"",
                                                        NameListToString(receiveName), typeName)));
        }
        if (sendOid)
@@ -491,8 +492,8 @@ DefineType(List *names, List *parameters)
                if (resulttype != BYTEAOID)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                  errmsg("type send function %s must return type \"bytea\"",
-                                                 NameListToString(sendName))));
+                                  errmsg("type send function %s must return type \"%s\"",
+                                                 NameListToString(sendName), "bytea")));
        }
 
        /*
@@ -511,8 +512,8 @@ DefineType(List *names, List *parameters)
                analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
 
        /*
-        * Check permissions on functions.      We choose to require the creator/owner
-        * of a type to also own the underlying functions.      Since creating a type
+        * Check permissions on functions.  We choose to require the creator/owner
+        * of a type to also own the underlying functions.  Since creating a type
         * is tantamount to granting public execute access on the functions, the
         * minimum sane check would be for execute-with-grant-option.  But we
         * don't have a way to make the type go away if the grant option is
@@ -543,16 +544,62 @@ DefineType(List *names, List *parameters)
                                           NameListToString(analyzeName));
 #endif
 
+       /*
+        * Print warnings if any of the type's I/O functions are marked volatile.
+        * There is a general assumption that I/O functions are stable or
+        * immutable; this allows us for example to mark record_in/record_out
+        * stable rather than volatile.  Ideally we would throw errors not just
+        * warnings here; but since this check is new as of 9.5, and since the
+        * volatility marking might be just an error-of-omission and not a true
+        * indication of how the function behaves, we'll let it pass as a warning
+        * for now.
+        */
+       if (inputOid && func_volatile(inputOid) == PROVOLATILE_VOLATILE)
+               ereport(WARNING,
+                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                errmsg("type input function %s should not be volatile",
+                                               NameListToString(inputName))));
+       if (outputOid && func_volatile(outputOid) == PROVOLATILE_VOLATILE)
+               ereport(WARNING,
+                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                errmsg("type output function %s should not be volatile",
+                                               NameListToString(outputName))));
+       if (receiveOid && func_volatile(receiveOid) == PROVOLATILE_VOLATILE)
+               ereport(WARNING,
+                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                errmsg("type receive function %s should not be volatile",
+                                               NameListToString(receiveName))));
+       if (sendOid && func_volatile(sendOid) == PROVOLATILE_VOLATILE)
+               ereport(WARNING,
+                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                errmsg("type send function %s should not be volatile",
+                                               NameListToString(sendName))));
+       if (typmodinOid && func_volatile(typmodinOid) == PROVOLATILE_VOLATILE)
+               ereport(WARNING,
+                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                        errmsg("type modifier input function %s should not be volatile",
+                                       NameListToString(typmodinName))));
+       if (typmodoutOid && func_volatile(typmodoutOid) == PROVOLATILE_VOLATILE)
+               ereport(WARNING,
+                               (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                       errmsg("type modifier output function %s should not be volatile",
+                                  NameListToString(typmodoutName))));
+
+       /*
+        * OK, we're done checking, time to make the type.  We must assign the
+        * array type OID ahead of calling TypeCreate, since the base type and
+        * array type each refer to the other.
+        */
        array_oid = AssignTypeArrayOid();
 
        /*
         * now have TypeCreate do all the real work.
         *
         * Note: the pg_type.oid is stored in user tables as array elements (base
-        * types) in ArrayType and in composite types in DatumTupleFields.      This
+        * types) in ArrayType and in composite types in DatumTupleFields.  This
         * oid must be preserved by binary upgrades.
         */
-       typoid =
+       address =
                TypeCreate(InvalidOid,  /* no predetermined type OID */
                                   typeName,    /* type name */
                                   typeNamespace,               /* namespace */
@@ -584,6 +631,7 @@ DefineType(List *names, List *parameters)
                                   0,                   /* Array Dimensions of typbasetype */
                                   false,               /* Type NOT NULL */
                                   collation);  /* type's collation */
+       Assert(typoid == address.objectId);
 
        /*
         * Create the array type that goes with it.
@@ -593,41 +641,41 @@ DefineType(List *names, List *parameters)
        /* alignment must be 'i' or 'd' for arrays */
        alignment = (alignment == 'd') ? 'd' : 'i';
 
-       typoid = TypeCreate(array_oid,          /* force assignment of this type OID */
-                                               array_type,             /* type name */
-                                               typeNamespace,  /* namespace */
-                                               InvalidOid,             /* relation oid (n/a here) */
-                                               0,                              /* relation kind (ditto) */
-                                               GetUserId(),            /* owner's ID */
-                                               -1,                             /* internal size (always varlena) */
-                                               TYPTYPE_BASE,   /* type-type (base type) */
-                                               TYPCATEGORY_ARRAY,              /* type-category (array) */
-                                               false,                  /* array types are never preferred */
-                                               delimiter,              /* array element delimiter */
-                                               F_ARRAY_IN,             /* input procedure */
-                                               F_ARRAY_OUT,            /* output procedure */
-                                               F_ARRAY_RECV,   /* receive procedure */
-                                               F_ARRAY_SEND,   /* send procedure */
-                                               typmodinOid,            /* typmodin procedure */
-                                               typmodoutOid,   /* typmodout procedure */
-                                               F_ARRAY_TYPANALYZE,             /* analyze procedure */
-                                               typoid,                 /* element type ID */
-                                               true,                   /* yes this is an array type */
-                                               InvalidOid,             /* no further array type */
-                                               InvalidOid,             /* base type ID */
-                                               NULL,                   /* never a default type value */
-                                               NULL,                   /* binary default isn't sent either */
-                                               false,                  /* never passed by value */
-                                               alignment,              /* see above */
-                                               'x',                            /* ARRAY is always toastable */
-                                               -1,                             /* typMod (Domains only) */
-                                               0,                              /* Array dimensions of typbasetype */
-                                               false,                  /* Type NOT NULL */
-                                               collation);             /* type's collation */
+       TypeCreate(array_oid,           /* force assignment of this type OID */
+                          array_type,          /* type name */
+                          typeNamespace,       /* namespace */
+                          InvalidOid,          /* relation oid (n/a here) */
+                          0,                           /* relation kind (ditto) */
+                          GetUserId(),         /* owner's ID */
+                          -1,                          /* internal size (always varlena) */
+                          TYPTYPE_BASE,        /* type-type (base type) */
+                          TYPCATEGORY_ARRAY,           /* type-category (array) */
+                          false,                       /* array types are never preferred */
+                          delimiter,           /* array element delimiter */
+                          F_ARRAY_IN,          /* input procedure */
+                          F_ARRAY_OUT,         /* output procedure */
+                          F_ARRAY_RECV,        /* receive procedure */
+                          F_ARRAY_SEND,        /* send procedure */
+                          typmodinOid,         /* typmodin procedure */
+                          typmodoutOid,        /* typmodout procedure */
+                          F_ARRAY_TYPANALYZE,          /* analyze procedure */
+                          typoid,                      /* element type ID */
+                          true,                        /* yes this is an array type */
+                          InvalidOid,          /* no further array type */
+                          InvalidOid,          /* base type ID */
+                          NULL,                        /* never a default type value */
+                          NULL,                        /* binary default isn't sent either */
+                          false,                       /* never passed by value */
+                          alignment,           /* see above */
+                          'x',                         /* ARRAY is always toastable */
+                          -1,                          /* typMod (Domains only) */
+                          0,                           /* Array dimensions of typbasetype */
+                          false,                       /* Type NOT NULL */
+                          collation);          /* type's collation */
 
        pfree(array_type);
 
-       return typoid;
+       return address;
 }
 
 /*
@@ -673,7 +721,7 @@ RemoveTypeById(Oid typeOid)
  * DefineDomain
  *             Registers a new domain.
  */
-Oid
+ObjectAddress
 DefineDomain(CreateDomainStmt *stmt)
 {
        char       *domainName;
@@ -703,12 +751,12 @@ DefineDomain(CreateDomainStmt *stmt)
        List       *schema = stmt->constraints;
        ListCell   *listptr;
        Oid                     basetypeoid;
-       Oid                     domainoid;
        Oid                     old_type_oid;
        Oid                     domaincoll;
        Form_pg_type baseType;
        int32           basetypeMod;
        Oid                     baseColl;
+       ObjectAddress address;
 
        /* Convert list of names to a name and namespace */
        domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
@@ -722,7 +770,7 @@ DefineDomain(CreateDomainStmt *stmt)
                                           get_namespace_name(domainNamespace));
 
        /*
-        * Check for collision with an existing type name.      If there is one and
+        * Check for collision with an existing type name.  If there is one and
         * it's an autogenerated array, we can rename it out of the way.
         */
        old_type_oid = GetSysCacheOid2(TYPENAMENSP,
@@ -923,8 +971,8 @@ DefineDomain(CreateDomainStmt *stmt)
                                /*
                                 * Check constraints are handled after domain creation, as
                                 * they require the Oid of the domain; at this point we can
-                                * only check that they're not marked NO INHERIT, because
-                                * that would be bogus.
+                                * only check that they're not marked NO INHERIT, because that
+                                * would be bogus.
                                 */
                                if (constr->is_no_inherit)
                                        ereport(ERROR,
@@ -978,7 +1026,7 @@ DefineDomain(CreateDomainStmt *stmt)
        /*
         * Have TypeCreate do all the real work.
         */
-       domainoid =
+       address =
                TypeCreate(InvalidOid,  /* no predetermined type OID */
                                   domainName,  /* type name */
                                   domainNamespace,             /* namespace */
@@ -1023,9 +1071,9 @@ DefineDomain(CreateDomainStmt *stmt)
                switch (constr->contype)
                {
                        case CONSTR_CHECK:
-                               domainAddConstraint(domainoid, domainNamespace,
+                               domainAddConstraint(address.objectId, domainNamespace,
                                                                        basetypeoid, basetypeMod,
-                                                                       constr, domainName);
+                                                                       constr, domainName, NULL);
                                break;
 
                                /* Other constraint types were fully processed above */
@@ -1043,7 +1091,7 @@ DefineDomain(CreateDomainStmt *stmt)
         */
        ReleaseSysCache(typeTup);
 
-       return domainoid;
+       return address;
 }
 
 
@@ -1051,16 +1099,16 @@ DefineDomain(CreateDomainStmt *stmt)
  * DefineEnum
  *             Registers a new enum.
  */
-Oid
+ObjectAddress
 DefineEnum(CreateEnumStmt *stmt)
 {
        char       *enumName;
        char       *enumArrayName;
        Oid                     enumNamespace;
-       Oid                     enumTypeOid;
        AclResult       aclresult;
        Oid                     old_type_oid;
        Oid                     enumArrayOid;
+       ObjectAddress enumTypeAddr;
 
        /* Convert list of names to a name and namespace */
        enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
@@ -1073,7 +1121,7 @@ DefineEnum(CreateEnumStmt *stmt)
                                           get_namespace_name(enumNamespace));
 
        /*
-        * Check for collision with an existing type name.      If there is one and
+        * Check for collision with an existing type name.  If there is one and
         * it's an autogenerated array, we can rename it out of the way.
         */
        old_type_oid = GetSysCacheOid2(TYPENAMENSP,
@@ -1090,7 +1138,7 @@ DefineEnum(CreateEnumStmt *stmt)
        enumArrayOid = AssignTypeArrayOid();
 
        /* Create the pg_type entry */
-       enumTypeOid =
+       enumTypeAddr =
                TypeCreate(InvalidOid,  /* no predetermined type OID */
                                   enumName,    /* type name */
                                   enumNamespace,               /* namespace */
@@ -1124,7 +1172,7 @@ DefineEnum(CreateEnumStmt *stmt)
                                   InvalidOid); /* type's collation */
 
        /* Enter the enum's values into pg_enum */
-       EnumValuesCreate(enumTypeOid, stmt->vals);
+       EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
 
        /*
         * Create the array type that goes with it.
@@ -1149,7 +1197,7 @@ DefineEnum(CreateEnumStmt *stmt)
                           InvalidOid,          /* typmodin procedure - none */
                           InvalidOid,          /* typmodout procedure - none */
                           F_ARRAY_TYPANALYZE,          /* analyze procedure */
-                          enumTypeOid,         /* element type ID */
+                          enumTypeAddr.objectId,       /* element type ID */
                           true,                        /* yes this is an array type */
                           InvalidOid,          /* no further array type */
                           InvalidOid,          /* base type ID */
@@ -1165,19 +1213,20 @@ DefineEnum(CreateEnumStmt *stmt)
 
        pfree(enumArrayName);
 
-       return enumTypeOid;
+       return enumTypeAddr;
 }
 
 /*
  * AlterEnum
  *             Adds a new label to an existing enum.
  */
-Oid
+ObjectAddress
 AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
 {
        Oid                     enum_type_oid;
        TypeName   *typename;
        HeapTuple       tup;
+       ObjectAddress address;
 
        /* Make a TypeName so we can use standard type lookup machinery */
        typename = makeTypeNameFromNameList(stmt->typeName);
@@ -1191,18 +1240,18 @@ AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
         * Ordinarily we disallow adding values within transaction blocks, because
         * we can't cope with enum OID values getting into indexes and then having
         * their defining pg_enum entries go away.  However, it's okay if the enum
-        * type was created in the current transaction, since then there can be
-        * no such indexes that wouldn't themselves go away on rollback.  (We
-        * support this case because pg_dump --binary-upgrade needs it.)  We test
-        * this by seeing if the pg_type row has xmin == current XID and is not
-        * HEAP_UPDATED.  If it is HEAP_UPDATED, we can't be sure whether the
-        * type was created or only modified in this xact.  So we are disallowing
-        * some cases that could theoretically be safe; but fortunately pg_dump
-        * only needs the simplest case.
+        * type was created in the current transaction, since then there can be no
+        * such indexes that wouldn't themselves go away on rollback.  (We support
+        * this case because pg_dump --binary-upgrade needs it.)  We test this by
+        * seeing if the pg_type row has xmin == current XID and is not
+        * HEAP_UPDATED.  If it is HEAP_UPDATED, we can't be sure whether the type
+        * was created or only modified in this xact.  So we are disallowing some
+        * cases that could theoretically be safe; but fortunately pg_dump only
+        * needs the simplest case.
         */
        if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() &&
                !(tup->t_data->t_infomask & HEAP_UPDATED))
-               /* safe to do inside transaction block */ ;
+                /* safe to do inside transaction block */ ;
        else
                PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
 
@@ -1214,9 +1263,13 @@ AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
                                 stmt->newValNeighbor, stmt->newValIsAfter,
                                 stmt->skipIfExists);
 
+       InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
+
+       ObjectAddressSet(address, TypeRelationId, enum_type_oid);
+
        ReleaseSysCache(tup);
 
-       return enum_type_oid;
+       return address;
 }
 
 
@@ -1248,7 +1301,7 @@ checkEnumOwner(HeapTuple tup)
  * DefineRange
  *             Registers a new range type.
  */
-Oid
+ObjectAddress
 DefineRange(CreateRangeStmt *stmt)
 {
        char       *typeName;
@@ -1271,6 +1324,7 @@ DefineRange(CreateRangeStmt *stmt)
        char            alignment;
        AclResult       aclresult;
        ListCell   *lc;
+       ObjectAddress address;
 
        /* Convert list of names to a name and namespace */
        typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
@@ -1309,7 +1363,8 @@ DefineRange(CreateRangeStmt *stmt)
         */
        if (!OidIsValid(typoid))
        {
-               typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
+               address = TypeShellMake(typeName, typeNamespace, GetUserId());
+               typoid = address.objectId;
                /* Make new shell type visible for modification below */
                CommandCounterIncrement();
        }
@@ -1422,7 +1477,7 @@ DefineRange(CreateRangeStmt *stmt)
        rangeArrayOid = AssignTypeArrayOid();
 
        /* Create the pg_type entry */
-       typoid =
+       address =
                TypeCreate(InvalidOid,  /* no predetermined type OID */
                                   typeName,    /* type name */
                                   typeNamespace,               /* namespace */
@@ -1454,6 +1509,7 @@ DefineRange(CreateRangeStmt *stmt)
                                   0,                   /* Array dimensions of typbasetype */
                                   false,               /* Type NOT NULL */
                                   InvalidOid); /* type's collation (ranges never have one) */
+       Assert(typoid == address.objectId);
 
        /* Create the entry in pg_range */
        RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
@@ -1501,7 +1557,7 @@ DefineRange(CreateRangeStmt *stmt)
        /* And create the constructor functions for this range type */
        makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
 
-       return typoid;
+       return address;
 }
 
 /*
@@ -1510,7 +1566,7 @@ DefineRange(CreateRangeStmt *stmt)
  * impossible to define a polymorphic constructor; we have to generate new
  * constructor functions explicitly for each range type.
  *
- * We actually define 4 functions, with 0 through 3 arguments. This is just
+ * We actually define 4 functions, with 0 through 3 arguments.  This is just
  * to offer more convenience for the user.
  */
 static void
@@ -1537,45 +1593,42 @@ makeRangeConstructors(const char *name, Oid namespace,
        for (i = 0; i < lengthof(prosrc); i++)
        {
                oidvector  *constructorArgTypesVector;
-               Oid                     procOid;
 
                constructorArgTypesVector = buildoidvector(constructorArgTypes,
                                                                                                   pronargs[i]);
 
-               procOid = ProcedureCreate(name, /* name: same as range type */
-                                                                 namespace,    /* namespace */
-                                                                 false,                /* replace */
-                                                                 false,                /* returns set */
-                                                                 rangeOid,             /* return type */
-                                                                 BOOTSTRAP_SUPERUSERID,                /* proowner */
-                                                                 INTERNALlanguageId,   /* language */
-                                                                 F_FMGR_INTERNAL_VALIDATOR,    /* language validator */
-                                                                 prosrc[i],    /* prosrc */
-                                                                 NULL, /* probin */
-                                                                 false,                /* isAgg */
-                                                                 false,                /* isWindowFunc */
-                                                                 false,                /* security_definer */
-                                                                 false,                /* leakproof */
-                                                                 false,                /* isStrict */
-                                                                 PROVOLATILE_IMMUTABLE,                /* volatility */
-                                                                 constructorArgTypesVector,    /* parameterTypes */
-                                                                 PointerGetDatum(NULL),                /* allParameterTypes */
-                                                                 PointerGetDatum(NULL),                /* parameterModes */
-                                                                 PointerGetDatum(NULL),                /* parameterNames */
-                                                                 NIL,  /* parameterDefaults */
-                                                                 PointerGetDatum(NULL),                /* proconfig */
-                                                                 1.0,  /* procost */
-                                                                 0.0); /* prorows */
+               myself = ProcedureCreate(name,  /* name: same as range type */
+                                                                namespace,             /* namespace */
+                                                                false, /* replace */
+                                                                false, /* returns set */
+                                                                rangeOid,              /* return type */
+                                                                BOOTSTRAP_SUPERUSERID, /* proowner */
+                                                                INTERNALlanguageId,    /* language */
+                                                                F_FMGR_INTERNAL_VALIDATOR,             /* language validator */
+                                                                prosrc[i],             /* prosrc */
+                                                                NULL,  /* probin */
+                                                                false, /* isAgg */
+                                                                false, /* isWindowFunc */
+                                                                false, /* security_definer */
+                                                                false, /* leakproof */
+                                                                false, /* isStrict */
+                                                                PROVOLATILE_IMMUTABLE, /* volatility */
+                                                                PROPARALLEL_SAFE,              /* parallel safety */
+                                                                constructorArgTypesVector,             /* parameterTypes */
+                                                                PointerGetDatum(NULL), /* allParameterTypes */
+                                                                PointerGetDatum(NULL), /* parameterModes */
+                                                                PointerGetDatum(NULL), /* parameterNames */
+                                                                NIL,   /* parameterDefaults */
+                                                                PointerGetDatum(NULL), /* trftypes */
+                                                                PointerGetDatum(NULL), /* proconfig */
+                                                                1.0,   /* procost */
+                                                                0.0);  /* prorows */
 
                /*
                 * Make the constructors internally-dependent on the range type so
                 * that they go away silently when the type is dropped.  Note that
                 * pg_dump depends on this choice to avoid dumping the constructors.
                 */
-               myself.classId = ProcedureRelationId;
-               myself.objectId = procOid;
-               myself.objectSubId = 0;
-
                recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
        }
 }
@@ -1781,8 +1834,8 @@ findTypeTypmodinFunction(List *procname)
        if (get_func_rettype(procOid) != INT4OID)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                errmsg("typmod_in function %s must return type \"integer\"",
-                                               NameListToString(procname))));
+                                errmsg("typmod_in function %s must return type \"%s\"",
+                                               NameListToString(procname), "integer")));
 
        return procOid;
 }
@@ -1808,8 +1861,8 @@ findTypeTypmodoutFunction(List *procname)
        if (get_func_rettype(procOid) != CSTRINGOID)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                errmsg("typmod_out function %s must return type \"cstring\"",
-                                               NameListToString(procname))));
+                                errmsg("typmod_out function %s must return type \"%s\"",
+                                               NameListToString(procname), "cstring")));
 
        return procOid;
 }
@@ -1835,8 +1888,8 @@ findTypeAnalyzeFunction(List *procname, Oid typeOid)
        if (get_func_rettype(procOid) != BOOLOID)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                         errmsg("type analyze function %s must return type \"boolean\"",
-                                        NameListToString(procname))));
+                         errmsg("type analyze function %s must return type \"%s\"",
+                                        NameListToString(procname), "boolean")));
 
        return procOid;
 }
@@ -1954,8 +2007,9 @@ findRangeSubtypeDiffFunction(List *procname, Oid subtype)
        if (get_func_rettype(procOid) != FLOAT8OID)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                errmsg("range subtype diff function %s must return type double precision",
-                                               func_signature_string(procname, 2, NIL, argList))));
+                                errmsg("range subtype diff function %s must return type \"%s\"",
+                                               func_signature_string(procname, 2, NIL, argList),
+                                               "double precision")));
 
        if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
                ereport(ERROR,
@@ -1981,9 +2035,14 @@ AssignTypeArrayOid(void)
 {
        Oid                     type_array_oid;
 
-       /* Use binary-upgrade override for pg_type.typarray, if supplied. */
-       if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid))
+       /* Use binary-upgrade override for pg_type.typarray? */
+       if (IsBinaryUpgrade)
        {
+               if (!OidIsValid(binary_upgrade_next_array_pg_type_oid))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                        errmsg("pg_type array OID value not set when in binary upgrade mode")));
+
                type_array_oid = binary_upgrade_next_array_pg_type_oid;
                binary_upgrade_next_array_pg_type_oid = InvalidOid;
        }
@@ -2009,17 +2068,16 @@ AssignTypeArrayOid(void)
  * If the relation already exists, then 'DefineRelation' will abort
  * the xact...
  *
- * DefineCompositeType returns relid for use when creating
- * an implicit composite type during function creation
+ * Return type is the new type's object address.
  *-------------------------------------------------------------------
  */
-Oid
+ObjectAddress
 DefineCompositeType(RangeVar *typevar, List *coldeflist)
 {
        CreateStmt *createStmt = makeNode(CreateStmt);
        Oid                     old_type_oid;
        Oid                     typeNamespace;
-       Oid                     relid;
+       ObjectAddress address;
 
        /*
         * now set the parameters for keys/inheritance etc. All of these are
@@ -2029,7 +2087,7 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
        createStmt->tableElts = coldeflist;
        createStmt->inhRelations = NIL;
        createStmt->constraints = NIL;
-       createStmt->options = list_make1(defWithOids(false));
+       createStmt->options = NIL;
        createStmt->oncommit = ONCOMMIT_NOOP;
        createStmt->tablespacename = NULL;
        createStmt->if_not_exists = false;
@@ -2058,17 +2116,19 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
        /*
         * Finally create the relation.  This also creates the type.
         */
-       relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
-       Assert(relid != InvalidOid);
-       return relid;
+       DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address);
+
+       return address;
 }
 
 /*
  * AlterDomainDefault
  *
  * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
+ *
+ * Returns ObjectAddress of the modified domain.
  */
-Oid
+ObjectAddress
 AlterDomainDefault(List *names, Node *defaultRaw)
 {
        TypeName   *typename;
@@ -2083,6 +2143,7 @@ AlterDomainDefault(List *names, Node *defaultRaw)
        bool            new_record_repl[Natts_pg_type];
        HeapTuple       newtuple;
        Form_pg_type typTup;
+       ObjectAddress address;
 
        /* Make a TypeName so we can use standard type lookup machinery */
        typename = makeTypeNameFromNameList(names);
@@ -2190,19 +2251,25 @@ AlterDomainDefault(List *names, Node *defaultRaw)
                                                         defaultExpr,
                                                         true);         /* Rebuild is true */
 
+       InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
+
+       ObjectAddressSet(address, TypeRelationId, domainoid);
+
        /* Clean up */
        heap_close(rel, NoLock);
        heap_freetuple(newtuple);
 
-       return domainoid;
+       return address;
 }
 
 /*
  * AlterDomainNotNull
  *
  * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
+ *
+ * Returns ObjectAddress of the modified domain.
  */
-Oid
+ObjectAddress
 AlterDomainNotNull(List *names, bool notNull)
 {
        TypeName   *typename;
@@ -2210,6 +2277,7 @@ AlterDomainNotNull(List *names, bool notNull)
        Relation        typrel;
        HeapTuple       tup;
        Form_pg_type typTup;
+       ObjectAddress address = InvalidObjectAddress;
 
        /* Make a TypeName so we can use standard type lookup machinery */
        typename = makeTypeNameFromNameList(names);
@@ -2230,7 +2298,7 @@ AlterDomainNotNull(List *names, bool notNull)
        if (typTup->typnotnull == notNull)
        {
                heap_close(typrel, RowExclusiveLock);
-               return InvalidOid;
+               return address;
        }
 
        /* Adding a NOT NULL constraint requires checking existing columns */
@@ -2251,9 +2319,11 @@ AlterDomainNotNull(List *names, bool notNull)
                        TupleDesc       tupdesc = RelationGetDescr(testrel);
                        HeapScanDesc scan;
                        HeapTuple       tuple;
+                       Snapshot        snapshot;
 
                        /* Scan all tuples in this relation */
-                       scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
+                       snapshot = RegisterSnapshot(GetLatestSnapshot());
+                       scan = heap_beginscan(testrel, snapshot, 0, NULL);
                        while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
                        {
                                int                     i;
@@ -2283,6 +2353,7 @@ AlterDomainNotNull(List *names, bool notNull)
                                }
                        }
                        heap_endscan(scan);
+                       UnregisterSnapshot(snapshot);
 
                        /* Close each rel after processing, but keep lock */
                        heap_close(testrel, NoLock);
@@ -2290,7 +2361,7 @@ AlterDomainNotNull(List *names, bool notNull)
        }
 
        /*
-        * Okay to update pg_type row.  We can scribble on typTup because it's a
+        * Okay to update pg_type row.  We can scribble on typTup because it's a
         * copy.
         */
        typTup->typnotnull = notNull;
@@ -2299,11 +2370,15 @@ AlterDomainNotNull(List *names, bool notNull)
 
        CatalogUpdateIndexes(typrel, tup);
 
+       InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
+
+       ObjectAddressSet(address, TypeRelationId, domainoid);
+
        /* Clean up */
        heap_freetuple(tup);
        heap_close(typrel, RowExclusiveLock);
 
-       return domainoid;
+       return address;
 }
 
 /*
@@ -2311,7 +2386,7 @@ AlterDomainNotNull(List *names, bool notNull)
  *
  * Implements the ALTER DOMAIN DROP CONSTRAINT statement
  */
-Oid
+ObjectAddress
 AlterDomainDropConstraint(List *names, const char *constrName,
                                                  DropBehavior behavior, bool missing_ok)
 {
@@ -2324,6 +2399,7 @@ AlterDomainDropConstraint(List *names, const char *constrName,
        ScanKeyData key[1];
        HeapTuple       contup;
        bool            found = false;
+       ObjectAddress address = InvalidObjectAddress;
 
        /* Make a TypeName so we can use standard type lookup machinery */
        typename = makeTypeNameFromNameList(names);
@@ -2349,7 +2425,7 @@ AlterDomainDropConstraint(List *names, const char *constrName,
                                ObjectIdGetDatum(HeapTupleGetOid(tup)));
 
        conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
-                                                                SnapshotNow, 1, key);
+                                                                NULL, 1, key);
 
        /*
         * Scan over the result set, removing any matching entries.
@@ -2370,6 +2446,9 @@ AlterDomainDropConstraint(List *names, const char *constrName,
                        found = true;
                }
        }
+
+       ObjectAddressSet(address, TypeRelationId, domainoid);
+
        /* Clean up after the scan */
        systable_endscan(conscan);
        heap_close(conrel, RowExclusiveLock);
@@ -2389,7 +2468,7 @@ AlterDomainDropConstraint(List *names, const char *constrName,
                                                        constrName, TypeNameToString(typename))));
        }
 
-       return domainoid;
+       return address;
 }
 
 /*
@@ -2397,8 +2476,9 @@ AlterDomainDropConstraint(List *names, const char *constrName,
  *
  * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
  */
-Oid
-AlterDomainAddConstraint(List *names, Node *newConstraint)
+ObjectAddress
+AlterDomainAddConstraint(List *names, Node *newConstraint,
+                                                ObjectAddress *constrAddr)
 {
        TypeName   *typename;
        Oid                     domainoid;
@@ -2407,6 +2487,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
        Form_pg_type typTup;
        Constraint *constr;
        char       *ccbin;
+       ObjectAddress address;
 
        /* Make a TypeName so we can use standard type lookup machinery */
        typename = makeTypeNameFromNameList(names);
@@ -2476,13 +2557,13 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
 
        /*
         * Since all other constraint types throw errors, this must be a check
-        * constraint.  First, process the constraint expression and add an entry
+        * constraint.  First, process the constraint expression and add an entry
         * to pg_constraint.
         */
 
        ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
                                                                typTup->typbasetype, typTup->typtypmod,
-                                                               constr, NameStr(typTup->typname));
+                                                               constr, NameStr(typTup->typname), constrAddr);
 
        /*
         * If requested to validate the constraint, test all values stored in the
@@ -2491,10 +2572,12 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
        if (!constr->skip_validation)
                validateDomainConstraint(domainoid, ccbin);
 
+       ObjectAddressSet(address, TypeRelationId, domainoid);
+
        /* Clean up */
        heap_close(typrel, RowExclusiveLock);
 
-       return domainoid;
+       return address;
 }
 
 /*
@@ -2502,7 +2585,7 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
  *
  * Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
  */
-Oid
+ObjectAddress
 AlterDomainValidateConstraint(List *names, char *constrName)
 {
        TypeName   *typename;
@@ -2520,6 +2603,7 @@ AlterDomainValidateConstraint(List *names, char *constrName)
        HeapTuple       tuple;
        HeapTuple       copyTuple;
        ScanKeyData key;
+       ObjectAddress address;
 
        /* Make a TypeName so we can use standard type lookup machinery */
        typename = makeTypeNameFromNameList(names);
@@ -2544,7 +2628,7 @@ AlterDomainValidateConstraint(List *names, char *constrName)
                                BTEqualStrategyNumber, F_OIDEQ,
                                ObjectIdGetDatum(domainoid));
        scan = systable_beginscan(conrel, ConstraintTypidIndexId,
-                                                         true, SnapshotNow, 1, &key);
+                                                         true, NULL, 1, &key);
 
        while (HeapTupleIsValid(tuple = systable_getnext(scan)))
        {
@@ -2586,6 +2670,12 @@ AlterDomainValidateConstraint(List *names, char *constrName)
        copy_con->convalidated = true;
        simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
        CatalogUpdateIndexes(conrel, copyTuple);
+
+       InvokeObjectPostAlterHook(ConstraintRelationId,
+                                                         HeapTupleGetOid(copyTuple), 0);
+
+       ObjectAddressSet(address, TypeRelationId, domainoid);
+
        heap_freetuple(copyTuple);
 
        systable_endscan(scan);
@@ -2595,7 +2685,7 @@ AlterDomainValidateConstraint(List *names, char *constrName)
 
        ReleaseSysCache(tup);
 
-       return domainoid;
+       return address;
 }
 
 static void
@@ -2627,9 +2717,11 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
                TupleDesc       tupdesc = RelationGetDescr(testrel);
                HeapScanDesc scan;
                HeapTuple       tuple;
+               Snapshot        snapshot;
 
                /* Scan all tuples in this relation */
-               scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);
+               snapshot = RegisterSnapshot(GetLatestSnapshot());
+               scan = heap_beginscan(testrel, snapshot, 0, NULL);
                while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
                {
                        int                     i;
@@ -2673,6 +2765,7 @@ validateDomainConstraint(Oid domainoid, char *ccbin)
                        ResetExprContext(econtext);
                }
                heap_endscan(scan);
+               UnregisterSnapshot(snapshot);
 
                /* Hold relation lock till commit (XXX bad for concurrency) */
                heap_close(testrel, NoLock);
@@ -2740,7 +2833,7 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
                                ObjectIdGetDatum(domainOid));
 
        depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
-                                                                SnapshotNow, 2, key);
+                                                                NULL, 2, key);
 
        while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
        {
@@ -2802,7 +2895,14 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
                                                                                                 NULL,
                                                                                                 format_type_be(domainOid));
 
-                       /* Otherwise we can ignore views, composite types, etc */
+                       /*
+                        * Otherwise, we can ignore relations except those with both
+                        * storage and user-chosen column types.
+                        *
+                        * XXX If an index-only scan could satisfy "col::some_domain" from
+                        * a suitable expression index, this should also check expression
+                        * index columns.
+                        */
                        if (rel->rd_rel->relkind != RELKIND_RELATION &&
                                rel->rd_rel->relkind != RELKIND_MATVIEW)
                        {
@@ -2831,7 +2931,7 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
                        continue;
 
                /*
-                * Okay, add column to result.  We store the columns in column-number
+                * Okay, add column to result.  We store the columns in column-number
                 * order; this is just a hack to improve predictability of regression
                 * test output ...
                 */
@@ -2882,13 +2982,14 @@ checkDomainOwner(HeapTuple tup)
 static char *
 domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
                                        int typMod, Constraint *constr,
-                                       char *domainName)
+                                       char *domainName, ObjectAddress *constrAddr)
 {
        Node       *expr;
        char       *ccsrc;
        char       *ccbin;
        ParseState *pstate;
        CoerceToDomainValue *domVal;
+       Oid                     ccoid;
 
        /*
         * Assign or validate constraint name
@@ -2918,7 +3019,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
 
        /*
         * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
-        * the expression.      Note that it will appear to have the type of the base
+        * the expression.  Note that it will appear to have the type of the base
         * type, not the domain.  This seems correct since within the check
         * expression, we should not assume the input value can be considered a
         * member of the domain.
@@ -2967,33 +3068,37 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
        /*
         * Store the constraint in pg_constraint
         */
-       CreateConstraintEntry(constr->conname,          /* Constraint Name */
-                                                 domainNamespace,              /* namespace */
-                                                 CONSTRAINT_CHECK,             /* Constraint Type */
-                                                 false,        /* Is Deferrable */
-                                                 false,        /* Is Deferred */
-                                                 !constr->skip_validation,             /* Is Validated */
-                                                 InvalidOid,   /* not a relation constraint */
-                                                 NULL,
-                                                 0,
-                                                 domainOid,    /* domain constraint */
-                                                 InvalidOid,   /* no associated index */
-                                                 InvalidOid,   /* Foreign key fields */
-                                                 NULL,
-                                                 NULL,
-                                                 NULL,
-                                                 NULL,
-                                                 0,
-                                                 ' ',
-                                                 ' ',
-                                                 ' ',
-                                                 NULL, /* not an exclusion constraint */
-                                                 expr, /* Tree form of check constraint */
-                                                 ccbin,        /* Binary form of check constraint */
-                                                 ccsrc,        /* Source form of check constraint */
-                                                 true, /* is local */
-                                                 0,    /* inhcount */
-                                                 false);               /* connoinherit */
+       ccoid =
+               CreateConstraintEntry(constr->conname,  /* Constraint Name */
+                                                         domainNamespace,      /* namespace */
+                                                         CONSTRAINT_CHECK, /* Constraint Type */
+                                                         false,        /* Is Deferrable */
+                                                         false,        /* Is Deferred */
+                                                         !constr->skip_validation, /* Is Validated */
+                                                         InvalidOid,           /* not a relation constraint */
+                                                         NULL,
+                                                         0,
+                                                         domainOid,            /* domain constraint */
+                                                         InvalidOid,           /* no associated index */
+                                                         InvalidOid,           /* Foreign key fields */
+                                                         NULL,
+                                                         NULL,
+                                                         NULL,
+                                                         NULL,
+                                                         0,
+                                                         ' ',
+                                                         ' ',
+                                                         ' ',
+                                                         NULL,         /* not an exclusion constraint */
+                                                         expr,         /* Tree form of check constraint */
+                                                         ccbin,        /* Binary form of check constraint */
+                                                         ccsrc,        /* Source form of check constraint */
+                                                         true,         /* is local */
+                                                         0,    /* inhcount */
+                                                         false,        /* connoinherit */
+                                                         false);       /* is_internal */
+       if (constrAddr)
+               ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
 
        /*
         * Return the compiled constraint expression so the calling routine can
@@ -3002,131 +3107,11 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
        return ccbin;
 }
 
-/*
- * GetDomainConstraints - get a list of the current constraints of domain
- *
- * Returns a possibly-empty list of DomainConstraintState nodes.
- *
- * This is called by the executor during plan startup for a CoerceToDomain
- * expression node.  The given constraints will be checked for each value
- * passed through the node.
- *
- * We allow this to be called for non-domain types, in which case the result
- * is always NIL.
- */
-List *
-GetDomainConstraints(Oid typeOid)
-{
-       List       *result = NIL;
-       bool            notNull = false;
-       Relation        conRel;
-
-       conRel = heap_open(ConstraintRelationId, AccessShareLock);
-
-       for (;;)
-       {
-               HeapTuple       tup;
-               HeapTuple       conTup;
-               Form_pg_type typTup;
-               ScanKeyData key[1];
-               SysScanDesc scan;
-
-               tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
-               if (!HeapTupleIsValid(tup))
-                       elog(ERROR, "cache lookup failed for type %u", typeOid);
-               typTup = (Form_pg_type) GETSTRUCT(tup);
-
-               if (typTup->typtype != TYPTYPE_DOMAIN)
-               {
-                       /* Not a domain, so done */
-                       ReleaseSysCache(tup);
-                       break;
-               }
-
-               /* Test for NOT NULL Constraint */
-               if (typTup->typnotnull)
-                       notNull = true;
-
-               /* Look for CHECK Constraints on this domain */
-               ScanKeyInit(&key[0],
-                                       Anum_pg_constraint_contypid,
-                                       BTEqualStrategyNumber, F_OIDEQ,
-                                       ObjectIdGetDatum(typeOid));
-
-               scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
-                                                                 SnapshotNow, 1, key);
-
-               while (HeapTupleIsValid(conTup = systable_getnext(scan)))
-               {
-                       Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
-                       Datum           val;
-                       bool            isNull;
-                       Expr       *check_expr;
-                       DomainConstraintState *r;
-
-                       /* Ignore non-CHECK constraints (presently, shouldn't be any) */
-                       if (c->contype != CONSTRAINT_CHECK)
-                               continue;
-
-                       /*
-                        * Not expecting conbin to be NULL, but we'll test for it anyway
-                        */
-                       val = fastgetattr(conTup, Anum_pg_constraint_conbin,
-                                                         conRel->rd_att, &isNull);
-                       if (isNull)
-                               elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
-                                        NameStr(typTup->typname), NameStr(c->conname));
-
-                       check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
-
-                       /* ExecInitExpr assumes we've planned the expression */
-                       check_expr = expression_planner(check_expr);
-
-                       r = makeNode(DomainConstraintState);
-                       r->constrainttype = DOM_CONSTRAINT_CHECK;
-                       r->name = pstrdup(NameStr(c->conname));
-                       r->check_expr = ExecInitExpr(check_expr, NULL);
-
-                       /*
-                        * use lcons() here because constraints of lower domains should be
-                        * applied earlier.
-                        */
-                       result = lcons(r, result);
-               }
-
-               systable_endscan(scan);
-
-               /* loop to next domain in stack */
-               typeOid = typTup->typbasetype;
-               ReleaseSysCache(tup);
-       }
-
-       heap_close(conRel, AccessShareLock);
-
-       /*
-        * Only need to add one NOT NULL check regardless of how many domains in
-        * the stack request it.
-        */
-       if (notNull)
-       {
-               DomainConstraintState *r = makeNode(DomainConstraintState);
-
-               r->constrainttype = DOM_CONSTRAINT_NOTNULL;
-               r->name = pstrdup("NOT NULL");
-               r->check_expr = NULL;
-
-               /* lcons to apply the nullness check FIRST */
-               result = lcons(r, result);
-       }
-
-       return result;
-}
-
 
 /*
  * Execute ALTER TYPE RENAME
  */
-Oid
+ObjectAddress
 RenameType(RenameStmt *stmt)
 {
        List       *names = stmt->object;
@@ -3136,6 +3121,7 @@ RenameType(RenameStmt *stmt)
        Relation        rel;
        HeapTuple       tup;
        Form_pg_type typTup;
+       ObjectAddress address;
 
        /* Make a TypeName so we can use standard type lookup machinery */
        typename = makeTypeNameFromNameList(names);
@@ -3188,21 +3174,22 @@ RenameType(RenameStmt *stmt)
         * RenameRelationInternal will call RenameTypeInternal automatically.
         */
        if (typTup->typtype == TYPTYPE_COMPOSITE)
-               RenameRelationInternal(typTup->typrelid, newTypeName);
+               RenameRelationInternal(typTup->typrelid, newTypeName, false);
        else
                RenameTypeInternal(typeOid, newTypeName,
                                                   typTup->typnamespace);
 
+       ObjectAddressSet(address, TypeRelationId, typeOid);
        /* Clean up */
        heap_close(rel, RowExclusiveLock);
 
-       return typeOid;
+       return address;
 }
 
 /*
  * Change the owner of a type.
  */
-Oid
+ObjectAddress
 AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
 {
        TypeName   *typename;
@@ -3212,6 +3199,7 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
        HeapTuple       newtup;
        Form_pg_type typTup;
        AclResult       aclresult;
+       ObjectAddress address;
 
        rel = heap_open(TypeRelationId, RowExclusiveLock);
 
@@ -3219,7 +3207,7 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
        typename = makeTypeNameFromNameList(names);
 
        /* Use LookupTypeName here so that shell types can be processed */
-       tup = LookupTypeName(NULL, typename, NULL);
+       tup = LookupTypeName(NULL, typename, NULL, false);
        if (tup == NULL)
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -3288,55 +3276,30 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
                                                           get_namespace_name(typTup->typnamespace));
                }
 
-               /*
-                * If it's a composite type, invoke ATExecChangeOwner so that we fix
-                * up the pg_class entry properly.      That will call back to
-                * AlterTypeOwnerInternal to take care of the pg_type entry(s).
-                */
-               if (typTup->typtype == TYPTYPE_COMPOSITE)
-                       ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
-               else
-               {
-                       /*
-                        * We can just apply the modification directly.
-                        *
-                        * okay to scribble on typTup because it's a copy
-                        */
-                       typTup->typowner = newOwnerId;
-
-                       simple_heap_update(rel, &tup->t_self, tup);
-
-                       CatalogUpdateIndexes(rel, tup);
-
-                       /* Update owner dependency reference */
-                       changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
-
-                       /* If it has an array type, update that too */
-                       if (OidIsValid(typTup->typarray))
-                               AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
-               }
+               AlterTypeOwner_oid(typeOid, newOwnerId, true);
        }
 
+       ObjectAddressSet(address, TypeRelationId, typeOid);
+
        /* Clean up */
        heap_close(rel, RowExclusiveLock);
 
-       return typeOid;
+       return address;
 }
 
 /*
- * AlterTypeOwnerInternal - change type owner unconditionally
+ * AlterTypeOwner_oid - change type owner unconditionally
  *
- * This is currently only used to propagate ALTER TABLE/TYPE OWNER to a
- * table's rowtype or an array type, and to implement REASSIGN OWNED BY.
- * It assumes the caller has done all needed checks.  The function will
- * automatically recurse to an array type if the type has one.
+ * This function recurses to handle a pg_class entry, if necessary.  It
+ * invokes any necessary access object hooks.  If hasDependEntry is TRUE, this
+ * function modifies the pg_shdepend entry appropriately (this should be
+ * passed as FALSE only for table rowtypes and array types).
  *
- * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
- * entry (ie, it's not a table rowtype nor an array type).
+ * This is used by ALTER TABLE/TYPE OWNER commands, as well as by REASSIGN
+ * OWNED BY.  It assumes the caller has done all needed check.
  */
 void
-AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
-                                          bool hasDependEntry)
+AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
 {
        Relation        rel;
        HeapTuple       tup;
@@ -3344,27 +3307,86 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
 
        rel = heap_open(TypeRelationId, RowExclusiveLock);
 
-       tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
+       tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
        if (!HeapTupleIsValid(tup))
                elog(ERROR, "cache lookup failed for type %u", typeOid);
        typTup = (Form_pg_type) GETSTRUCT(tup);
 
        /*
-        * Modify the owner --- okay to scribble on typTup because it's a copy
+        * If it's a composite type, invoke ATExecChangeOwner so that we fix up the
+        * pg_class entry properly.  That will call back to AlterTypeOwnerInternal
+        * to take care of the pg_type entry(s).
         */
-       typTup->typowner = newOwnerId;
+       if (typTup->typtype == TYPTYPE_COMPOSITE)
+               ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
+       else
+               AlterTypeOwnerInternal(typeOid, newOwnerId);
+
+       /* Update owner dependency reference */
+       if (hasDependEntry)
+               changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
+
+       InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
+       ReleaseSysCache(tup);
+       heap_close(rel, RowExclusiveLock);
+}
+
+/*
+ * AlterTypeOwnerInternal - bare-bones type owner change.
+ *
+ * This routine simply modifies the owner of a pg_type entry, and recurses
+ * to handle a possible array type.
+ */
+void
+AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
+{
+       Relation        rel;
+       HeapTuple       tup;
+       Form_pg_type typTup;
+       Datum           repl_val[Natts_pg_type];
+       bool            repl_null[Natts_pg_type];
+       bool            repl_repl[Natts_pg_type];
+       Acl                *newAcl;
+       Datum           aclDatum;
+       bool            isNull;
+
+       rel = heap_open(TypeRelationId, RowExclusiveLock);
+
+       tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
+       if (!HeapTupleIsValid(tup))
+               elog(ERROR, "cache lookup failed for type %u", typeOid);
+       typTup = (Form_pg_type) GETSTRUCT(tup);
+
+       memset(repl_null, false, sizeof(repl_null));
+       memset(repl_repl, false, sizeof(repl_repl));
+
+       repl_repl[Anum_pg_type_typowner - 1] = true;
+       repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
+
+       aclDatum = heap_getattr(tup,
+                                                       Anum_pg_type_typacl,
+                                                       RelationGetDescr(rel),
+                                                       &isNull);
+       /* Null ACLs do not require changes */
+       if (!isNull)
+       {
+               newAcl = aclnewowner(DatumGetAclP(aclDatum),
+                                                        typTup->typowner, newOwnerId);
+               repl_repl[Anum_pg_type_typacl - 1] = true;
+               repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
+       }
+
+       tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
+                                                       repl_repl);
 
        simple_heap_update(rel, &tup->t_self, tup);
 
        CatalogUpdateIndexes(rel, tup);
 
-       /* Update owner dependency reference, if it has one */
-       if (hasDependEntry)
-               changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
-
        /* If it has an array type, update that too */
        if (OidIsValid(typTup->typarray))
-               AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
+               AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
 
        /* Clean up */
        heap_close(rel, RowExclusiveLock);
@@ -3373,13 +3395,16 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
 /*
  * Execute ALTER TYPE SET SCHEMA
  */
-Oid
-AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype)
+ObjectAddress
+AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype,
+                                  Oid *oldschema)
 {
        TypeName   *typename;
        Oid                     typeOid;
        Oid                     nspOid;
-       ObjectAddresses *objsMoved;
+       Oid                     oldNspOid;
+       ObjectAddresses *objsMoved;
+       ObjectAddress myself;
 
        /* Make a TypeName so we can use standard type lookup machinery */
        typename = makeTypeNameFromNameList(names);
@@ -3396,10 +3421,15 @@ AlterTypeNamespace(List *names, const char *newschema, ObjectType objecttype)
        nspOid = LookupCreationNamespace(newschema);
 
        objsMoved = new_object_addresses();
-       AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
+       oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
        free_object_addresses(objsMoved);
 
-       return typeOid;
+       if (oldschema)
+               *oldschema = oldNspOid;
+
+       ObjectAddressSet(myself, TypeRelationId, typeOid);
+
+       return myself;
 }
 
 Oid
@@ -3431,7 +3461,7 @@ AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
  * Caller must have already checked privileges.
  *
  * The function automatically recurses to process the type's array type,
- * if any.     isImplicitArray should be TRUE only when doing this internal
+ * if any.  isImplicitArray should be TRUE only when doing this internal
  * recursion (outside callers must never try to move an array type directly).
  *
  * If errorOnTableType is TRUE, the function errors out if the type is
@@ -3474,18 +3504,22 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
        oldNspOid = typform->typnamespace;
        arrayOid = typform->typarray;
 
-       /* common checks on switching namespaces */
-       CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid);
+       /* If the type is already there, we scan skip these next few checks. */
+       if (oldNspOid != nspOid)
+       {
+               /* common checks on switching namespaces */
+               CheckSetNamespace(oldNspOid, nspOid);
 
-       /* check for duplicate name (more friendly than unique-index failure) */
-       if (SearchSysCacheExists2(TYPENAMENSP,
-                                                         CStringGetDatum(NameStr(typform->typname)),
-                                                         ObjectIdGetDatum(nspOid)))
-               ereport(ERROR,
-                               (errcode(ERRCODE_DUPLICATE_OBJECT),
-                                errmsg("type \"%s\" already exists in schema \"%s\"",
-                                               NameStr(typform->typname),
-                                               get_namespace_name(nspOid))));
+               /* check for duplicate name (more friendly than unique-index failure) */
+               if (SearchSysCacheExists2(TYPENAMENSP,
+                                                                 CStringGetDatum(NameStr(typform->typname)),
+                                                                 ObjectIdGetDatum(nspOid)))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_DUPLICATE_OBJECT),
+                                        errmsg("type \"%s\" already exists in schema \"%s\"",
+                                                       NameStr(typform->typname),
+                                                       get_namespace_name(nspOid))));
+       }
 
        /* Detect whether type is a composite type (but not a table rowtype) */
        isCompositeType =
@@ -3501,13 +3535,16 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
                                                format_type_be(typeOid)),
                                 errhint("Use ALTER TABLE instead.")));
 
-       /* OK, modify the pg_type row */
+       if (oldNspOid != nspOid)
+       {
+               /* OK, modify the pg_type row */
 
-       /* tup is a copy, so we can scribble directly on it */
-       typform->typnamespace = nspOid;
+               /* tup is a copy, so we can scribble directly on it */
+               typform->typnamespace = nspOid;
 
-       simple_heap_update(rel, &tup->t_self, tup);
-       CatalogUpdateIndexes(rel, tup);
+               simple_heap_update(rel, &tup->t_self, tup);
+               CatalogUpdateIndexes(rel, tup);
+       }
 
        /*
         * Composite types have pg_class entries.
@@ -3546,13 +3583,16 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
         * Update dependency on schema, if any --- a table rowtype has not got
         * one, and neither does an implicit array.
         */
-       if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
+       if (oldNspOid != nspOid &&
+               (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
                !isImplicitArray)
                if (changeDependencyFor(TypeRelationId, typeOid,
                                                                NamespaceRelationId, oldNspOid, nspOid) != 1)
                        elog(ERROR, "failed to change schema dependency for type %s",
                                 format_type_be(typeOid));
 
+       InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
        heap_freetuple(tup);
 
        heap_close(rel, RowExclusiveLock);