Refactor ExecGrant_*() functions
authorPeter Eisentraut <peter@eisentraut.org>
Tue, 13 Dec 2022 06:43:42 +0000 (07:43 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Tue, 13 Dec 2022 06:52:04 +0000 (07:52 +0100)
Instead of half a dozen of mostly-duplicate ExecGrant_Foo() functions,
write one common function ExecGrant_generic() that can handle most of
them.  We already have all the information we need, such as which
system catalog corresponds to which catalog table and which column is
the ACL column.

Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Antonin Houska <ah@cybertec.at>
Discussion: https://www.postgresql.org/message-id/flat/22c7e802-4e7d-8d87-8b71-cba95e6f4bcf%40enterprisedb.com

src/backend/catalog/aclchk.c

index bd967eaa7831af1e6ad96d70b04fc8d2874da938..e48fc1647a6779fe2ff7af7dcd0f5277b8c0d84f 100644 (file)
@@ -106,15 +106,11 @@ bool      binary_upgrade_record_init_privs = false;
 
 static void ExecGrantStmt_oids(InternalGrant *istmt);
 static void ExecGrant_Relation(InternalGrant *istmt);
-static void ExecGrant_Database(InternalGrant *istmt);
-static void ExecGrant_Fdw(InternalGrant *istmt);
-static void ExecGrant_ForeignServer(InternalGrant *istmt);
-static void ExecGrant_Function(InternalGrant *istmt);
-static void ExecGrant_Language(InternalGrant *istmt);
+static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
+                            void (*object_check) (InternalGrant *istmt, HeapTuple tuple));
+static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple);
 static void ExecGrant_Largeobject(InternalGrant *istmt);
-static void ExecGrant_Namespace(InternalGrant *istmt);
-static void ExecGrant_Tablespace(InternalGrant *istmt);
-static void ExecGrant_Type(InternalGrant *istmt);
+static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple);
 static void ExecGrant_Parameter(InternalGrant *istmt);
 
 static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
@@ -602,34 +598,34 @@ ExecGrantStmt_oids(InternalGrant *istmt)
            ExecGrant_Relation(istmt);
            break;
        case OBJECT_DATABASE:
-           ExecGrant_Database(istmt);
+           ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
            break;
        case OBJECT_DOMAIN:
        case OBJECT_TYPE:
-           ExecGrant_Type(istmt);
+           ExecGrant_common(istmt, TypeRelationId, ACL_ALL_RIGHTS_TYPE, ExecGrant_Type_check);
            break;
        case OBJECT_FDW:
-           ExecGrant_Fdw(istmt);
+           ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
            break;
        case OBJECT_FOREIGN_SERVER:
-           ExecGrant_ForeignServer(istmt);
+           ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
            break;
        case OBJECT_FUNCTION:
        case OBJECT_PROCEDURE:
        case OBJECT_ROUTINE:
-           ExecGrant_Function(istmt);
+           ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
            break;
        case OBJECT_LANGUAGE:
-           ExecGrant_Language(istmt);
+           ExecGrant_common(istmt, LanguageRelationId, ACL_ALL_RIGHTS_LANGUAGE, ExecGrant_Language_check);
            break;
        case OBJECT_LARGEOBJECT:
            ExecGrant_Largeobject(istmt);
            break;
        case OBJECT_SCHEMA:
-           ExecGrant_Namespace(istmt);
+           ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
            break;
        case OBJECT_TABLESPACE:
-           ExecGrant_Tablespace(istmt);
+           ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
            break;
        case OBJECT_PARAMETER_ACL:
            ExecGrant_Parameter(istmt);
@@ -2132,21 +2128,25 @@ ExecGrant_Relation(InternalGrant *istmt)
 }
 
 static void
-ExecGrant_Database(InternalGrant *istmt)
+ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
+                void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
 {
+   int         cacheid;
    Relation    relation;
    ListCell   *cell;
 
    if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
-       istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
+       istmt->privileges = default_privs;
+
+   cacheid = get_object_catcache_oid(classid);
 
-   relation = table_open(DatabaseRelationId, RowExclusiveLock);
+   relation = table_open(classid, RowExclusiveLock);
 
    foreach(cell, istmt->objects)
    {
-       Oid         datId = lfirst_oid(cell);
-       Form_pg_database pg_database_tuple;
+       Oid         objectid = lfirst_oid(cell);
        Datum       aclDatum;
+       Datum       nameDatum;
        bool        isNull;
        AclMode     avail_goptions;
        AclMode     this_privileges;
@@ -2154,32 +2154,42 @@ ExecGrant_Database(InternalGrant *istmt)
        Acl        *new_acl;
        Oid         grantorId;
        Oid         ownerId;
+       HeapTuple   tuple;
        HeapTuple   newtuple;
-       Datum       values[Natts_pg_database] = {0};
-       bool        nulls[Natts_pg_database] = {0};
-       bool        replaces[Natts_pg_database] = {0};
+       Datum      *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
+       bool       *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
+       bool       *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
        int         noldmembers;
        int         nnewmembers;
        Oid        *oldmembers;
        Oid        *newmembers;
-       HeapTuple   tuple;
 
-       tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(datId));
+       tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
        if (!HeapTupleIsValid(tuple))
-           elog(ERROR, "cache lookup failed for database %u", datId);
+           elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
 
-       pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
+       /*
+        * Additional object-type-specific checks
+        */
+       if (object_check)
+           object_check(istmt, tuple);
 
        /*
         * Get owner ID and working copy of existing ACL. If there's no ACL,
         * substitute the proper default.
         */
-       ownerId = pg_database_tuple->datdba;
-       aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
-                               RelationGetDescr(relation), &isNull);
+       ownerId = DatumGetObjectId(SysCacheGetAttr(cacheid,
+                                                  tuple,
+                                                  get_object_attnum_owner(classid),
+                                                  &isNull));
+       Assert(!isNull);
+       aclDatum = SysCacheGetAttr(cacheid,
+                                  tuple,
+                                  get_object_attnum_acl(classid),
+                                  &isNull);
        if (isNull)
        {
-           old_acl = acldefault(OBJECT_DATABASE, ownerId);
+           old_acl = acldefault(get_object_type(classid, objectid), ownerId);
            /* There are no old member roles according to the catalogs */
            noldmembers = 0;
            oldmembers = NULL;
@@ -2196,6 +2206,11 @@ ExecGrant_Database(InternalGrant *istmt)
                            old_acl, ownerId,
                            &grantorId, &avail_goptions);
 
+       nameDatum = SysCacheGetAttr(cacheid, tuple,
+                                   get_object_attnum_name(classid),
+                                   &isNull);
+       Assert(!isNull);
+
        /*
         * Restrict the privileges to what we can actually grant, and emit the
         * standards-mandated warning and error messages.
@@ -2203,8 +2218,8 @@ ExecGrant_Database(InternalGrant *istmt)
        this_privileges =
            restrict_and_check_grant(istmt->is_grant, avail_goptions,
                                     istmt->all_privs, istmt->privileges,
-                                    datId, grantorId, OBJECT_DATABASE,
-                                    NameStr(pg_database_tuple->datname),
+                                    objectid, grantorId, get_object_type(classid, objectid),
+                                    NameStr(*DatumGetName(nameDatum)),
                                     0, NULL);
 
        /*
@@ -2222,16 +2237,20 @@ ExecGrant_Database(InternalGrant *istmt)
        nnewmembers = aclmembers(new_acl, &newmembers);
 
        /* finished building new ACL value, now insert it */
-       replaces[Anum_pg_database_datacl - 1] = true;
-       values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
+       replaces[get_object_attnum_acl(classid) - 1] = true;
+       values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
 
        newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
                                     nulls, replaces);
 
        CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
 
+       /* Update initial privileges for extensions */
+       recordExtensionInitPriv(objectid, classid, 0, new_acl);
+
        /* Update the shared dependency ACL info */
-       updateAclDependencies(DatabaseRelationId, pg_database_tuple->oid, 0,
+       updateAclDependencies(classid,
+                             objectid, 0,
                              ownerId,
                              noldmembers, oldmembers,
                              nnewmembers, newmembers);
@@ -2248,143 +2267,38 @@ ExecGrant_Database(InternalGrant *istmt)
 }
 
 static void
-ExecGrant_Fdw(InternalGrant *istmt)
+ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
 {
-   Relation    relation;
-   ListCell   *cell;
-
-   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
-       istmt->privileges = ACL_ALL_RIGHTS_FDW;
-
-   relation = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
-
-   foreach(cell, istmt->objects)
-   {
-       Oid         fdwid = lfirst_oid(cell);
-       Form_pg_foreign_data_wrapper pg_fdw_tuple;
-       Datum       aclDatum;
-       bool        isNull;
-       AclMode     avail_goptions;
-       AclMode     this_privileges;
-       Acl        *old_acl;
-       Acl        *new_acl;
-       Oid         grantorId;
-       Oid         ownerId;
-       HeapTuple   tuple;
-       HeapTuple   newtuple;
-       Datum       values[Natts_pg_foreign_data_wrapper] = {0};
-       bool        nulls[Natts_pg_foreign_data_wrapper] = {0};
-       bool        replaces[Natts_pg_foreign_data_wrapper] = {0};
-       int         noldmembers;
-       int         nnewmembers;
-       Oid        *oldmembers;
-       Oid        *newmembers;
-
-       tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
-                               ObjectIdGetDatum(fdwid));
-       if (!HeapTupleIsValid(tuple))
-           elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
-
-       pg_fdw_tuple = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
-
-       /*
-        * Get owner ID and working copy of existing ACL. If there's no ACL,
-        * substitute the proper default.
-        */
-       ownerId = pg_fdw_tuple->fdwowner;
-       aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
-                                  Anum_pg_foreign_data_wrapper_fdwacl,
-                                  &isNull);
-       if (isNull)
-       {
-           old_acl = acldefault(OBJECT_FDW, ownerId);
-           /* There are no old member roles according to the catalogs */
-           noldmembers = 0;
-           oldmembers = NULL;
-       }
-       else
-       {
-           old_acl = DatumGetAclPCopy(aclDatum);
-           /* Get the roles mentioned in the existing ACL */
-           noldmembers = aclmembers(old_acl, &oldmembers);
-       }
-
-       /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), istmt->privileges,
-                           old_acl, ownerId,
-                           &grantorId, &avail_goptions);
-
-       /*
-        * Restrict the privileges to what we can actually grant, and emit the
-        * standards-mandated warning and error messages.
-        */
-       this_privileges =
-           restrict_and_check_grant(istmt->is_grant, avail_goptions,
-                                    istmt->all_privs, istmt->privileges,
-                                    fdwid, grantorId, OBJECT_FDW,
-                                    NameStr(pg_fdw_tuple->fdwname),
-                                    0, NULL);
-
-       /*
-        * Generate new ACL.
-        */
-       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
-                                      istmt->grant_option, istmt->behavior,
-                                      istmt->grantees, this_privileges,
-                                      grantorId, ownerId);
-
-       /*
-        * We need the members of both old and new ACLs so we can correct the
-        * shared dependency information.
-        */
-       nnewmembers = aclmembers(new_acl, &newmembers);
-
-       /* finished building new ACL value, now insert it */
-       replaces[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
-       values[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(new_acl);
+   Form_pg_language pg_language_tuple;
 
-       newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
-                                    nulls, replaces);
-
-       CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
-
-       /* Update initial privileges for extensions */
-       recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0,
-                               new_acl);
-
-       /* Update the shared dependency ACL info */
-       updateAclDependencies(ForeignDataWrapperRelationId,
-                             pg_fdw_tuple->oid, 0,
-                             ownerId,
-                             noldmembers, oldmembers,
-                             nnewmembers, newmembers);
-
-       ReleaseSysCache(tuple);
-
-       pfree(new_acl);
+   pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
 
-       /* prevent error when processing duplicate objects */
-       CommandCounterIncrement();
-   }
-
-   table_close(relation, RowExclusiveLock);
+   if (!pg_language_tuple->lanpltrusted)
+       ereport(ERROR,
+               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                errmsg("language \"%s\" is not trusted",
+                       NameStr(pg_language_tuple->lanname)),
+                errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
+                          "because only superusers can use untrusted languages.")));
 }
 
 static void
-ExecGrant_ForeignServer(InternalGrant *istmt)
+ExecGrant_Largeobject(InternalGrant *istmt)
 {
    Relation    relation;
    ListCell   *cell;
 
    if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
-       istmt->privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
+       istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
 
-   relation = table_open(ForeignServerRelationId, RowExclusiveLock);
+   relation = table_open(LargeObjectMetadataRelationId,
+                         RowExclusiveLock);
 
    foreach(cell, istmt->objects)
    {
-       Oid         srvid = lfirst_oid(cell);
-       Form_pg_foreign_server pg_server_tuple;
+       Oid         loid = lfirst_oid(cell);
+       Form_pg_largeobject_metadata form_lo_meta;
+       char        loname[NAMEDATALEN];
        Datum       aclDatum;
        bool        isNull;
        AclMode     avail_goptions;
@@ -2393,33 +2307,45 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
        Acl        *new_acl;
        Oid         grantorId;
        Oid         ownerId;
-       HeapTuple   tuple;
        HeapTuple   newtuple;
-       Datum       values[Natts_pg_foreign_server] = {0};
-       bool        nulls[Natts_pg_foreign_server] = {0};
-       bool        replaces[Natts_pg_foreign_server] = {0};
+       Datum       values[Natts_pg_largeobject_metadata] = {0};
+       bool        nulls[Natts_pg_largeobject_metadata] = {0};
+       bool        replaces[Natts_pg_largeobject_metadata] = {0};
        int         noldmembers;
        int         nnewmembers;
        Oid        *oldmembers;
        Oid        *newmembers;
+       ScanKeyData entry[1];
+       SysScanDesc scan;
+       HeapTuple   tuple;
+
+       /* There's no syscache for pg_largeobject_metadata */
+       ScanKeyInit(&entry[0],
+                   Anum_pg_largeobject_metadata_oid,
+                   BTEqualStrategyNumber, F_OIDEQ,
+                   ObjectIdGetDatum(loid));
+
+       scan = systable_beginscan(relation,
+                                 LargeObjectMetadataOidIndexId, true,
+                                 NULL, 1, entry);
 
-       tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvid));
+       tuple = systable_getnext(scan);
        if (!HeapTupleIsValid(tuple))
-           elog(ERROR, "cache lookup failed for foreign server %u", srvid);
+           elog(ERROR, "could not find tuple for large object %u", loid);
 
-       pg_server_tuple = (Form_pg_foreign_server) GETSTRUCT(tuple);
+       form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
 
        /*
         * Get owner ID and working copy of existing ACL. If there's no ACL,
         * substitute the proper default.
         */
-       ownerId = pg_server_tuple->srvowner;
-       aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
-                                  Anum_pg_foreign_server_srvacl,
-                                  &isNull);
+       ownerId = form_lo_meta->lomowner;
+       aclDatum = heap_getattr(tuple,
+                               Anum_pg_largeobject_metadata_lomacl,
+                               RelationGetDescr(relation), &isNull);
        if (isNull)
        {
-           old_acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId);
+           old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
            /* There are no old member roles according to the catalogs */
            noldmembers = 0;
            oldmembers = NULL;
@@ -2440,12 +2366,12 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
         * Restrict the privileges to what we can actually grant, and emit the
         * standards-mandated warning and error messages.
         */
+       snprintf(loname, sizeof(loname), "large object %u", loid);
        this_privileges =
            restrict_and_check_grant(istmt->is_grant, avail_goptions,
                                     istmt->all_privs, istmt->privileges,
-                                    srvid, grantorId, OBJECT_FOREIGN_SERVER,
-                                    NameStr(pg_server_tuple->srvname),
-                                    0, NULL);
+                                    loid, grantorId, OBJECT_LARGEOBJECT,
+                                    loname, 0, NULL);
 
        /*
         * Generate new ACL.
@@ -2462,25 +2388,26 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
        nnewmembers = aclmembers(new_acl, &newmembers);
 
        /* finished building new ACL value, now insert it */
-       replaces[Anum_pg_foreign_server_srvacl - 1] = true;
-       values[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(new_acl);
+       replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
+       values[Anum_pg_largeobject_metadata_lomacl - 1]
+           = PointerGetDatum(new_acl);
 
-       newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
-                                    nulls, replaces);
+       newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
+                                    values, nulls, replaces);
 
        CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
 
        /* Update initial privileges for extensions */
-       recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl);
+       recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
 
        /* Update the shared dependency ACL info */
-       updateAclDependencies(ForeignServerRelationId,
-                             pg_server_tuple->oid, 0,
+       updateAclDependencies(LargeObjectRelationId,
+                             form_lo_meta->oid, 0,
                              ownerId,
                              noldmembers, oldmembers,
                              nnewmembers, newmembers);
 
-       ReleaseSysCache(tuple);
+       systable_endscan(scan);
 
        pfree(new_acl);
 
@@ -2492,754 +2419,25 @@ ExecGrant_ForeignServer(InternalGrant *istmt)
 }
 
 static void
-ExecGrant_Function(InternalGrant *istmt)
+ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
 {
-   Relation    relation;
-   ListCell   *cell;
-
-   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
-       istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
-
-   relation = table_open(ProcedureRelationId, RowExclusiveLock);
-
-   foreach(cell, istmt->objects)
-   {
-       Oid         funcId = lfirst_oid(cell);
-       Form_pg_proc pg_proc_tuple;
-       Datum       aclDatum;
-       bool        isNull;
-       AclMode     avail_goptions;
-       AclMode     this_privileges;
-       Acl        *old_acl;
-       Acl        *new_acl;
-       Oid         grantorId;
-       Oid         ownerId;
-       HeapTuple   tuple;
-       HeapTuple   newtuple;
-       Datum       values[Natts_pg_proc] = {0};
-       bool        nulls[Natts_pg_proc] = {0};
-       bool        replaces[Natts_pg_proc] = {0};
-       int         noldmembers;
-       int         nnewmembers;
-       Oid        *oldmembers;
-       Oid        *newmembers;
-
-       tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcId));
-       if (!HeapTupleIsValid(tuple))
-           elog(ERROR, "cache lookup failed for function %u", funcId);
-
-       pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
-
-       /*
-        * Get owner ID and working copy of existing ACL. If there's no ACL,
-        * substitute the proper default.
-        */
-       ownerId = pg_proc_tuple->proowner;
-       aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
-                                  &isNull);
-       if (isNull)
-       {
-           old_acl = acldefault(OBJECT_FUNCTION, ownerId);
-           /* There are no old member roles according to the catalogs */
-           noldmembers = 0;
-           oldmembers = NULL;
-       }
-       else
-       {
-           old_acl = DatumGetAclPCopy(aclDatum);
-           /* Get the roles mentioned in the existing ACL */
-           noldmembers = aclmembers(old_acl, &oldmembers);
-       }
-
-       /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), istmt->privileges,
-                           old_acl, ownerId,
-                           &grantorId, &avail_goptions);
-
-       /*
-        * Restrict the privileges to what we can actually grant, and emit the
-        * standards-mandated warning and error messages.
-        */
-       this_privileges =
-           restrict_and_check_grant(istmt->is_grant, avail_goptions,
-                                    istmt->all_privs, istmt->privileges,
-                                    funcId, grantorId, OBJECT_FUNCTION,
-                                    NameStr(pg_proc_tuple->proname),
-                                    0, NULL);
-
-       /*
-        * Generate new ACL.
-        */
-       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
-                                      istmt->grant_option, istmt->behavior,
-                                      istmt->grantees, this_privileges,
-                                      grantorId, ownerId);
-
-       /*
-        * We need the members of both old and new ACLs so we can correct the
-        * shared dependency information.
-        */
-       nnewmembers = aclmembers(new_acl, &newmembers);
-
-       /* finished building new ACL value, now insert it */
-       replaces[Anum_pg_proc_proacl - 1] = true;
-       values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
-
-       newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
-                                    nulls, replaces);
-
-       CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
+   Form_pg_type pg_type_tuple;
 
-       /* Update initial privileges for extensions */
-       recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl);
-
-       /* Update the shared dependency ACL info */
-       updateAclDependencies(ProcedureRelationId, funcId, 0,
-                             ownerId,
-                             noldmembers, oldmembers,
-                             nnewmembers, newmembers);
+   pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
 
-       ReleaseSysCache(tuple);
+   if (IsTrueArrayType(pg_type_tuple))
+       ereport(ERROR,
+               (errcode(ERRCODE_INVALID_GRANT_OPERATION),
+                errmsg("cannot set privileges of array types"),
+                errhint("Set the privileges of the element type instead.")));
 
-       pfree(new_acl);
-
-       /* prevent error when processing duplicate objects */
-       CommandCounterIncrement();
-   }
-
-   table_close(relation, RowExclusiveLock);
-}
-
-static void
-ExecGrant_Language(InternalGrant *istmt)
-{
-   Relation    relation;
-   ListCell   *cell;
-
-   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
-       istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
-
-   relation = table_open(LanguageRelationId, RowExclusiveLock);
-
-   foreach(cell, istmt->objects)
-   {
-       Oid         langId = lfirst_oid(cell);
-       Form_pg_language pg_language_tuple;
-       Datum       aclDatum;
-       bool        isNull;
-       AclMode     avail_goptions;
-       AclMode     this_privileges;
-       Acl        *old_acl;
-       Acl        *new_acl;
-       Oid         grantorId;
-       Oid         ownerId;
-       HeapTuple   tuple;
-       HeapTuple   newtuple;
-       Datum       values[Natts_pg_language] = {0};
-       bool        nulls[Natts_pg_language] = {0};
-       bool        replaces[Natts_pg_language] = {0};
-       int         noldmembers;
-       int         nnewmembers;
-       Oid        *oldmembers;
-       Oid        *newmembers;
-
-       tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(langId));
-       if (!HeapTupleIsValid(tuple))
-           elog(ERROR, "cache lookup failed for language %u", langId);
-
-       pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
-
-       if (!pg_language_tuple->lanpltrusted)
-           ereport(ERROR,
-                   (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                    errmsg("language \"%s\" is not trusted",
-                           NameStr(pg_language_tuple->lanname)),
-                    errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
-                              "because only superusers can use untrusted languages.")));
-
-       /*
-        * Get owner ID and working copy of existing ACL. If there's no ACL,
-        * substitute the proper default.
-        */
-       ownerId = pg_language_tuple->lanowner;
-       aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
-                                  &isNull);
-       if (isNull)
-       {
-           old_acl = acldefault(OBJECT_LANGUAGE, ownerId);
-           /* There are no old member roles according to the catalogs */
-           noldmembers = 0;
-           oldmembers = NULL;
-       }
-       else
-       {
-           old_acl = DatumGetAclPCopy(aclDatum);
-           /* Get the roles mentioned in the existing ACL */
-           noldmembers = aclmembers(old_acl, &oldmembers);
-       }
-
-       /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), istmt->privileges,
-                           old_acl, ownerId,
-                           &grantorId, &avail_goptions);
-
-       /*
-        * Restrict the privileges to what we can actually grant, and emit the
-        * standards-mandated warning and error messages.
-        */
-       this_privileges =
-           restrict_and_check_grant(istmt->is_grant, avail_goptions,
-                                    istmt->all_privs, istmt->privileges,
-                                    langId, grantorId, OBJECT_LANGUAGE,
-                                    NameStr(pg_language_tuple->lanname),
-                                    0, NULL);
-
-       /*
-        * Generate new ACL.
-        */
-       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
-                                      istmt->grant_option, istmt->behavior,
-                                      istmt->grantees, this_privileges,
-                                      grantorId, ownerId);
-
-       /*
-        * We need the members of both old and new ACLs so we can correct the
-        * shared dependency information.
-        */
-       nnewmembers = aclmembers(new_acl, &newmembers);
-
-       /* finished building new ACL value, now insert it */
-       replaces[Anum_pg_language_lanacl - 1] = true;
-       values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
-
-       newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
-                                    nulls, replaces);
-
-       CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
-
-       /* Update initial privileges for extensions */
-       recordExtensionInitPriv(langId, LanguageRelationId, 0, new_acl);
-
-       /* Update the shared dependency ACL info */
-       updateAclDependencies(LanguageRelationId, pg_language_tuple->oid, 0,
-                             ownerId,
-                             noldmembers, oldmembers,
-                             nnewmembers, newmembers);
-
-       ReleaseSysCache(tuple);
-
-       pfree(new_acl);
-
-       /* prevent error when processing duplicate objects */
-       CommandCounterIncrement();
-   }
-
-   table_close(relation, RowExclusiveLock);
-}
-
-static void
-ExecGrant_Largeobject(InternalGrant *istmt)
-{
-   Relation    relation;
-   ListCell   *cell;
-
-   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
-       istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
-
-   relation = table_open(LargeObjectMetadataRelationId,
-                         RowExclusiveLock);
-
-   foreach(cell, istmt->objects)
-   {
-       Oid         loid = lfirst_oid(cell);
-       Form_pg_largeobject_metadata form_lo_meta;
-       char        loname[NAMEDATALEN];
-       Datum       aclDatum;
-       bool        isNull;
-       AclMode     avail_goptions;
-       AclMode     this_privileges;
-       Acl        *old_acl;
-       Acl        *new_acl;
-       Oid         grantorId;
-       Oid         ownerId;
-       HeapTuple   newtuple;
-       Datum       values[Natts_pg_largeobject_metadata] = {0};
-       bool        nulls[Natts_pg_largeobject_metadata] = {0};
-       bool        replaces[Natts_pg_largeobject_metadata] = {0};
-       int         noldmembers;
-       int         nnewmembers;
-       Oid        *oldmembers;
-       Oid        *newmembers;
-       ScanKeyData entry[1];
-       SysScanDesc scan;
-       HeapTuple   tuple;
-
-       /* There's no syscache for pg_largeobject_metadata */
-       ScanKeyInit(&entry[0],
-                   Anum_pg_largeobject_metadata_oid,
-                   BTEqualStrategyNumber, F_OIDEQ,
-                   ObjectIdGetDatum(loid));
-
-       scan = systable_beginscan(relation,
-                                 LargeObjectMetadataOidIndexId, true,
-                                 NULL, 1, entry);
-
-       tuple = systable_getnext(scan);
-       if (!HeapTupleIsValid(tuple))
-           elog(ERROR, "could not find tuple for large object %u", loid);
-
-       form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
-
-       /*
-        * Get owner ID and working copy of existing ACL. If there's no ACL,
-        * substitute the proper default.
-        */
-       ownerId = form_lo_meta->lomowner;
-       aclDatum = heap_getattr(tuple,
-                               Anum_pg_largeobject_metadata_lomacl,
-                               RelationGetDescr(relation), &isNull);
-       if (isNull)
-       {
-           old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
-           /* There are no old member roles according to the catalogs */
-           noldmembers = 0;
-           oldmembers = NULL;
-       }
-       else
-       {
-           old_acl = DatumGetAclPCopy(aclDatum);
-           /* Get the roles mentioned in the existing ACL */
-           noldmembers = aclmembers(old_acl, &oldmembers);
-       }
-
-       /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), istmt->privileges,
-                           old_acl, ownerId,
-                           &grantorId, &avail_goptions);
-
-       /*
-        * Restrict the privileges to what we can actually grant, and emit the
-        * standards-mandated warning and error messages.
-        */
-       snprintf(loname, sizeof(loname), "large object %u", loid);
-       this_privileges =
-           restrict_and_check_grant(istmt->is_grant, avail_goptions,
-                                    istmt->all_privs, istmt->privileges,
-                                    loid, grantorId, OBJECT_LARGEOBJECT,
-                                    loname, 0, NULL);
-
-       /*
-        * Generate new ACL.
-        */
-       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
-                                      istmt->grant_option, istmt->behavior,
-                                      istmt->grantees, this_privileges,
-                                      grantorId, ownerId);
-
-       /*
-        * We need the members of both old and new ACLs so we can correct the
-        * shared dependency information.
-        */
-       nnewmembers = aclmembers(new_acl, &newmembers);
-
-       /* finished building new ACL value, now insert it */
-       replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
-       values[Anum_pg_largeobject_metadata_lomacl - 1]
-           = PointerGetDatum(new_acl);
-
-       newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
-                                    values, nulls, replaces);
-
-       CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
-
-       /* Update initial privileges for extensions */
-       recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
-
-       /* Update the shared dependency ACL info */
-       updateAclDependencies(LargeObjectRelationId,
-                             form_lo_meta->oid, 0,
-                             ownerId,
-                             noldmembers, oldmembers,
-                             nnewmembers, newmembers);
-
-       systable_endscan(scan);
-
-       pfree(new_acl);
-
-       /* prevent error when processing duplicate objects */
-       CommandCounterIncrement();
-   }
-
-   table_close(relation, RowExclusiveLock);
-}
-
-static void
-ExecGrant_Namespace(InternalGrant *istmt)
-{
-   Relation    relation;
-   ListCell   *cell;
-
-   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
-       istmt->privileges = ACL_ALL_RIGHTS_SCHEMA;
-
-   relation = table_open(NamespaceRelationId, RowExclusiveLock);
-
-   foreach(cell, istmt->objects)
-   {
-       Oid         nspid = lfirst_oid(cell);
-       Form_pg_namespace pg_namespace_tuple;
-       Datum       aclDatum;
-       bool        isNull;
-       AclMode     avail_goptions;
-       AclMode     this_privileges;
-       Acl        *old_acl;
-       Acl        *new_acl;
-       Oid         grantorId;
-       Oid         ownerId;
-       HeapTuple   tuple;
-       HeapTuple   newtuple;
-       Datum       values[Natts_pg_namespace] = {0};
-       bool        nulls[Natts_pg_namespace] = {0};
-       bool        replaces[Natts_pg_namespace] = {0};
-       int         noldmembers;
-       int         nnewmembers;
-       Oid        *oldmembers;
-       Oid        *newmembers;
-
-       tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
-       if (!HeapTupleIsValid(tuple))
-           elog(ERROR, "cache lookup failed for namespace %u", nspid);
-
-       pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
-
-       /*
-        * Get owner ID and working copy of existing ACL. If there's no ACL,
-        * substitute the proper default.
-        */
-       ownerId = pg_namespace_tuple->nspowner;
-       aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
-                                  Anum_pg_namespace_nspacl,
-                                  &isNull);
-       if (isNull)
-       {
-           old_acl = acldefault(OBJECT_SCHEMA, ownerId);
-           /* There are no old member roles according to the catalogs */
-           noldmembers = 0;
-           oldmembers = NULL;
-       }
-       else
-       {
-           old_acl = DatumGetAclPCopy(aclDatum);
-           /* Get the roles mentioned in the existing ACL */
-           noldmembers = aclmembers(old_acl, &oldmembers);
-       }
-
-       /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), istmt->privileges,
-                           old_acl, ownerId,
-                           &grantorId, &avail_goptions);
-
-       /*
-        * Restrict the privileges to what we can actually grant, and emit the
-        * standards-mandated warning and error messages.
-        */
-       this_privileges =
-           restrict_and_check_grant(istmt->is_grant, avail_goptions,
-                                    istmt->all_privs, istmt->privileges,
-                                    nspid, grantorId, OBJECT_SCHEMA,
-                                    NameStr(pg_namespace_tuple->nspname),
-                                    0, NULL);
-
-       /*
-        * Generate new ACL.
-        */
-       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
-                                      istmt->grant_option, istmt->behavior,
-                                      istmt->grantees, this_privileges,
-                                      grantorId, ownerId);
-
-       /*
-        * We need the members of both old and new ACLs so we can correct the
-        * shared dependency information.
-        */
-       nnewmembers = aclmembers(new_acl, &newmembers);
-
-       /* finished building new ACL value, now insert it */
-       replaces[Anum_pg_namespace_nspacl - 1] = true;
-       values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
-
-       newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
-                                    nulls, replaces);
-
-       CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
-
-       /* Update initial privileges for extensions */
-       recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl);
-
-       /* Update the shared dependency ACL info */
-       updateAclDependencies(NamespaceRelationId, pg_namespace_tuple->oid, 0,
-                             ownerId,
-                             noldmembers, oldmembers,
-                             nnewmembers, newmembers);
-
-       ReleaseSysCache(tuple);
-
-       pfree(new_acl);
-
-       /* prevent error when processing duplicate objects */
-       CommandCounterIncrement();
-   }
-
-   table_close(relation, RowExclusiveLock);
-}
-
-static void
-ExecGrant_Tablespace(InternalGrant *istmt)
-{
-   Relation    relation;
-   ListCell   *cell;
-
-   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
-       istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
-
-   relation = table_open(TableSpaceRelationId, RowExclusiveLock);
-
-   foreach(cell, istmt->objects)
-   {
-       Oid         tblId = lfirst_oid(cell);
-       Form_pg_tablespace pg_tablespace_tuple;
-       Datum       aclDatum;
-       bool        isNull;
-       AclMode     avail_goptions;
-       AclMode     this_privileges;
-       Acl        *old_acl;
-       Acl        *new_acl;
-       Oid         grantorId;
-       Oid         ownerId;
-       HeapTuple   newtuple;
-       Datum       values[Natts_pg_tablespace] = {0};
-       bool        nulls[Natts_pg_tablespace] = {0};
-       bool        replaces[Natts_pg_tablespace] = {0};
-       int         noldmembers;
-       int         nnewmembers;
-       Oid        *oldmembers;
-       Oid        *newmembers;
-       HeapTuple   tuple;
-
-       /* Search syscache for pg_tablespace */
-       tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tblId));
-       if (!HeapTupleIsValid(tuple))
-           elog(ERROR, "cache lookup failed for tablespace %u", tblId);
-
-       pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
-
-       /*
-        * Get owner ID and working copy of existing ACL. If there's no ACL,
-        * substitute the proper default.
-        */
-       ownerId = pg_tablespace_tuple->spcowner;
-       aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
-                               RelationGetDescr(relation), &isNull);
-       if (isNull)
-       {
-           old_acl = acldefault(OBJECT_TABLESPACE, ownerId);
-           /* There are no old member roles according to the catalogs */
-           noldmembers = 0;
-           oldmembers = NULL;
-       }
-       else
-       {
-           old_acl = DatumGetAclPCopy(aclDatum);
-           /* Get the roles mentioned in the existing ACL */
-           noldmembers = aclmembers(old_acl, &oldmembers);
-       }
-
-       /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), istmt->privileges,
-                           old_acl, ownerId,
-                           &grantorId, &avail_goptions);
-
-       /*
-        * Restrict the privileges to what we can actually grant, and emit the
-        * standards-mandated warning and error messages.
-        */
-       this_privileges =
-           restrict_and_check_grant(istmt->is_grant, avail_goptions,
-                                    istmt->all_privs, istmt->privileges,
-                                    tblId, grantorId, OBJECT_TABLESPACE,
-                                    NameStr(pg_tablespace_tuple->spcname),
-                                    0, NULL);
-
-       /*
-        * Generate new ACL.
-        */
-       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
-                                      istmt->grant_option, istmt->behavior,
-                                      istmt->grantees, this_privileges,
-                                      grantorId, ownerId);
-
-       /*
-        * We need the members of both old and new ACLs so we can correct the
-        * shared dependency information.
-        */
-       nnewmembers = aclmembers(new_acl, &newmembers);
-
-       /* finished building new ACL value, now insert it */
-       replaces[Anum_pg_tablespace_spcacl - 1] = true;
-       values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
-
-       newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
-                                    nulls, replaces);
-
-       CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
-
-       /* Update the shared dependency ACL info */
-       updateAclDependencies(TableSpaceRelationId, tblId, 0,
-                             ownerId,
-                             noldmembers, oldmembers,
-                             nnewmembers, newmembers);
-
-       ReleaseSysCache(tuple);
-       pfree(new_acl);
-
-       /* prevent error when processing duplicate objects */
-       CommandCounterIncrement();
-   }
-
-   table_close(relation, RowExclusiveLock);
-}
-
-static void
-ExecGrant_Type(InternalGrant *istmt)
-{
-   Relation    relation;
-   ListCell   *cell;
-
-   if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
-       istmt->privileges = ACL_ALL_RIGHTS_TYPE;
-
-   relation = table_open(TypeRelationId, RowExclusiveLock);
-
-   foreach(cell, istmt->objects)
-   {
-       Oid         typId = lfirst_oid(cell);
-       Form_pg_type pg_type_tuple;
-       Datum       aclDatum;
-       bool        isNull;
-       AclMode     avail_goptions;
-       AclMode     this_privileges;
-       Acl        *old_acl;
-       Acl        *new_acl;
-       Oid         grantorId;
-       Oid         ownerId;
-       HeapTuple   newtuple;
-       Datum       values[Natts_pg_type] = {0};
-       bool        nulls[Natts_pg_type] = {0};
-       bool        replaces[Natts_pg_type] = {0};
-       int         noldmembers;
-       int         nnewmembers;
-       Oid        *oldmembers;
-       Oid        *newmembers;
-       HeapTuple   tuple;
-
-       /* Search syscache for pg_type */
-       tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typId));
-       if (!HeapTupleIsValid(tuple))
-           elog(ERROR, "cache lookup failed for type %u", typId);
-
-       pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
-
-       if (IsTrueArrayType(pg_type_tuple))
-           ereport(ERROR,
-                   (errcode(ERRCODE_INVALID_GRANT_OPERATION),
-                    errmsg("cannot set privileges of array types"),
-                    errhint("Set the privileges of the element type instead.")));
-
-       /* Used GRANT DOMAIN on a non-domain? */
-       if (istmt->objtype == OBJECT_DOMAIN &&
-           pg_type_tuple->typtype != TYPTYPE_DOMAIN)
-           ereport(ERROR,
-                   (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                    errmsg("\"%s\" is not a domain",
-                           NameStr(pg_type_tuple->typname))));
-
-       /*
-        * Get owner ID and working copy of existing ACL. If there's no ACL,
-        * substitute the proper default.
-        */
-       ownerId = pg_type_tuple->typowner;
-       aclDatum = heap_getattr(tuple, Anum_pg_type_typacl,
-                               RelationGetDescr(relation), &isNull);
-       if (isNull)
-       {
-           old_acl = acldefault(istmt->objtype, ownerId);
-           /* There are no old member roles according to the catalogs */
-           noldmembers = 0;
-           oldmembers = NULL;
-       }
-       else
-       {
-           old_acl = DatumGetAclPCopy(aclDatum);
-           /* Get the roles mentioned in the existing ACL */
-           noldmembers = aclmembers(old_acl, &oldmembers);
-       }
-
-       /* Determine ID to do the grant as, and available grant options */
-       select_best_grantor(GetUserId(), istmt->privileges,
-                           old_acl, ownerId,
-                           &grantorId, &avail_goptions);
-
-       /*
-        * Restrict the privileges to what we can actually grant, and emit the
-        * standards-mandated warning and error messages.
-        */
-       this_privileges =
-           restrict_and_check_grant(istmt->is_grant, avail_goptions,
-                                    istmt->all_privs, istmt->privileges,
-                                    typId, grantorId, OBJECT_TYPE,
-                                    NameStr(pg_type_tuple->typname),
-                                    0, NULL);
-
-       /*
-        * Generate new ACL.
-        */
-       new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
-                                      istmt->grant_option, istmt->behavior,
-                                      istmt->grantees, this_privileges,
-                                      grantorId, ownerId);
-
-       /*
-        * We need the members of both old and new ACLs so we can correct the
-        * shared dependency information.
-        */
-       nnewmembers = aclmembers(new_acl, &newmembers);
-
-       /* finished building new ACL value, now insert it */
-       replaces[Anum_pg_type_typacl - 1] = true;
-       values[Anum_pg_type_typacl - 1] = PointerGetDatum(new_acl);
-
-       newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
-                                    nulls, replaces);
-
-       CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
-
-       /* Update initial privileges for extensions */
-       recordExtensionInitPriv(typId, TypeRelationId, 0, new_acl);
-
-       /* Update the shared dependency ACL info */
-       updateAclDependencies(TypeRelationId, typId, 0,
-                             ownerId,
-                             noldmembers, oldmembers,
-                             nnewmembers, newmembers);
-
-       ReleaseSysCache(tuple);
-       pfree(new_acl);
-
-       /* prevent error when processing duplicate objects */
-       CommandCounterIncrement();
-   }
-
-   table_close(relation, RowExclusiveLock);
+   /* Used GRANT DOMAIN on a non-domain? */
+   if (istmt->objtype == OBJECT_DOMAIN &&
+       pg_type_tuple->typtype != TYPTYPE_DOMAIN)
+       ereport(ERROR,
+               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                errmsg("\"%s\" is not a domain",
+                       NameStr(pg_type_tuple->typname))));
 }
 
 static void