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
- {
- Datum repl_val[Natts_pg_type];
- bool repl_null[Natts_pg_type];
- bool repl_repl[Natts_pg_type];
- Acl *newAcl;
- Datum aclDatum;
- bool isNull;
-
- 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 */
- changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
-
- InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
-
- /* 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);
}
/*
- * AlterTypeOwnerInternal - change type owner unconditionally
+ * AlterTypeOwner_oid - change type owner unconditionally
+ *
+ * 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).
*
- * 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 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
+AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
+{
+ Relation rel;
+ HeapTuple tup;
+ Form_pg_type typTup;
+
+ rel = heap_open(TypeRelationId, RowExclusiveLock);
+
+ tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for type %u", typeOid);
+ typTup = (Form_pg_type) GETSTRUCT(tup);
+
+ /*
+ * 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
+ 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.
*
- * 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).
- * is_primary_ops should be TRUE if this function is invoked with user's
- * direct operation (e.g, shdepReassignOwned). Elsewhere,
+ * 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,
- bool hasDependEntry)
+AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
{
Relation rel;
HeapTuple 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);
-
- InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+ AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
/* Clean up */
heap_close(rel, RowExclusiveLock);
\d deptest
-- Test REASSIGN OWNED
GRANT ALL ON deptest1 TO regression_user1;
+GRANT CREATE ON DATABASE regression TO regression_user1;
SET SESSION AUTHORIZATION regression_user1;
+CREATE SCHEMA deptest;
CREATE TABLE deptest (a serial primary key, b text);
+ALTER DEFAULT PRIVILEGES FOR ROLE regression_user1 IN SCHEMA deptest
+ GRANT ALL ON TABLES TO regression_user2;
+CREATE FUNCTION deptest_func() RETURNS void LANGUAGE plpgsql
+ AS $$ BEGIN END; $$;
+CREATE TYPE deptest_enum AS ENUM ('red');
+CREATE TYPE deptest_range AS RANGE (SUBTYPE = int4);
CREATE TABLE deptest2 (f1 int);
-- make a serial column the hard way
CREATE SEQUENCE ss1;
ALTER TABLE deptest2 ALTER f1 SET DEFAULT nextval('ss1');
ALTER SEQUENCE ss1 OWNED BY deptest2.f1;
+-- When reassigning ownership of a composite type, its pg_class entry
+-- should match
+CREATE TYPE deptest_t AS (a int);
+SELECT typowner = relowner
+FROM pg_type JOIN pg_class c ON typrelid = c.oid WHERE typname = 'deptest_t';
+ ?column?
+----------
+ t
+(1 row)
+
RESET SESSION AUTHORIZATION;
REASSIGN OWNED BY regression_user1 TO regression_user2;
\dt deptest
public | deptest | table | regression_user2
(1 row)
+SELECT typowner = relowner
+FROM pg_type JOIN pg_class c ON typrelid = c.oid WHERE typname = 'deptest_t';
+ ?column?
+----------
+ t
+(1 row)
+
-- doesn't work: grant still exists
DROP USER regression_user1;
ERROR: role "regression_user1" cannot be dropped because some objects depend on it
-DETAIL: privileges for table deptest1
+DETAIL: owner of default privileges on new relations belonging to role regression_user1 in schema deptest
+privileges for database regression
+privileges for table deptest1
DROP OWNED BY regression_user1;
DROP USER regression_user1;
\set VERBOSITY terse
-- Test REASSIGN OWNED
GRANT ALL ON deptest1 TO regression_user1;
+GRANT CREATE ON DATABASE regression TO regression_user1;
SET SESSION AUTHORIZATION regression_user1;
+CREATE SCHEMA deptest;
CREATE TABLE deptest (a serial primary key, b text);
+ALTER DEFAULT PRIVILEGES FOR ROLE regression_user1 IN SCHEMA deptest
+ GRANT ALL ON TABLES TO regression_user2;
+CREATE FUNCTION deptest_func() RETURNS void LANGUAGE plpgsql
+ AS $$ BEGIN END; $$;
+CREATE TYPE deptest_enum AS ENUM ('red');
+CREATE TYPE deptest_range AS RANGE (SUBTYPE = int4);
CREATE TABLE deptest2 (f1 int);
-- make a serial column the hard way
CREATE SEQUENCE ss1;
ALTER TABLE deptest2 ALTER f1 SET DEFAULT nextval('ss1');
ALTER SEQUENCE ss1 OWNED BY deptest2.f1;
-RESET SESSION AUTHORIZATION;
+-- When reassigning ownership of a composite type, its pg_class entry
+-- should match
+CREATE TYPE deptest_t AS (a int);
+SELECT typowner = relowner
+FROM pg_type JOIN pg_class c ON typrelid = c.oid WHERE typname = 'deptest_t';
+
+RESET SESSION AUTHORIZATION;
REASSIGN OWNED BY regression_user1 TO regression_user2;
\dt deptest
+SELECT typowner = relowner
+FROM pg_type JOIN pg_class c ON typrelid = c.oid WHERE typname = 'deptest_t';
+
-- doesn't work: grant still exists
DROP USER regression_user1;
DROP OWNED BY regression_user1;