From a417f85e1da1ef241af4bf40507ca213464d7069 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Tue, 21 Feb 2012 17:58:02 -0300 Subject: [PATCH] REASSIGN OWNED: Support foreign data wrappers and servers This was overlooked when implementing those kinds of objects, in commit cae565e503c42a0942ca1771665243b4453c5770. Per report from Pawel Casperek. --- src/backend/catalog/pg_shdepend.c | 10 +++ src/backend/commands/foreigncmds.c | 134 ++++++++++++++++++++++------- src/include/commands/defrem.h | 2 + 3 files changed, 115 insertions(+), 31 deletions(-) diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 11cb9883a7..bcc663515c 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -25,6 +25,8 @@ #include "catalog/pg_conversion.h" #include "catalog/pg_database.h" #include "catalog/pg_default_acl.h" +#include "catalog/pg_foreign_data_wrapper.h" +#include "catalog/pg_foreign_server.h" #include "catalog/pg_language.h" #include "catalog/pg_largeobject.h" #include "catalog/pg_namespace.h" @@ -1382,6 +1384,14 @@ shdepReassignOwned(List *roleids, Oid newrole) AlterOpFamilyOwner_oid(sdepForm->objid, newrole); break; + case ForeignServerRelationId: + AlterForeignServerOwner_oid(sdepForm->objid, newrole); + break; + + case ForeignDataWrapperRelationId: + AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole); + break; + default: elog(ERROR, "unexpected classid %u", sdepForm->classid); break; diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index 4135e26857..990875de76 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -277,27 +277,24 @@ RenameForeignServer(const char *oldname, const char *newname) /* - * Change foreign-data wrapper owner. + * Internal workhorse for changing a data wrapper's owner. * * Allow this only for superusers; also the new owner must be a * superuser. */ -void -AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId) +static void +AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) { - HeapTuple tup; - Relation rel; - Oid fdwId; Form_pg_foreign_data_wrapper form; - rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock); + form = (Form_pg_foreign_data_wrapper) GETSTRUCT(tup); /* Must be a superuser to change a FDW owner */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to change owner of foreign-data wrapper \"%s\"", - name), + NameStr(form->fdwname)), errhint("Must be superuser to change owner of a foreign-data wrapper."))); /* New owner must also be a superuser */ @@ -305,19 +302,9 @@ AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to change owner of foreign-data wrapper \"%s\"", - name), + NameStr(form->fdwname)), errhint("The owner of a foreign-data wrapper must be a superuser."))); - tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(name)); - - if (!HeapTupleIsValid(tup)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("foreign-data wrapper \"%s\" does not exist", name))); - - fdwId = HeapTupleGetOid(tup); - form = (Form_pg_foreign_data_wrapper) GETSTRUCT(tup); - if (form->fdwowner != newOwnerId) { form->fdwowner = newOwnerId; @@ -327,38 +314,73 @@ AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId) /* Update owner dependency reference */ changeDependencyOnOwner(ForeignDataWrapperRelationId, - fdwId, + HeapTupleGetOid(tup), newOwnerId); } +} + +/* + * Change foreign-data wrapper owner -- by name + * + * Note restrictions in the "_internal" function, above. + */ +void +AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId) +{ + HeapTuple tup; + Relation rel; + + rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock); + + tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(name)); + + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("foreign-data wrapper \"%s\" does not exist", name))); + + AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId); heap_freetuple(tup); heap_close(rel, RowExclusiveLock); } - /* - * Change foreign server owner + * Change foreign-data wrapper owner -- by OID + * + * Note restrictions in the "_internal" function, above. */ void -AlterForeignServerOwner(const char *name, Oid newOwnerId) +AlterForeignDataWrapperOwner_oid(Oid fwdId, Oid newOwnerId) { HeapTuple tup; Relation rel; - Oid srvId; - AclResult aclresult; - Form_pg_foreign_server form; - rel = heap_open(ForeignServerRelationId, RowExclusiveLock); + rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock); - tup = SearchSysCacheCopy1(FOREIGNSERVERNAME, CStringGetDatum(name)); + tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fwdId)); if (!HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("server \"%s\" does not exist", name))); + errmsg("foreign-data wrapper with OID \"%u\" does not exist", fwdId))); + + AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId); + + heap_freetuple(tup); + + heap_close(rel, RowExclusiveLock); +} + +/* + * Internal workhorse for changing a foreign server's owner + */ +static void +AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) +{ + Form_pg_foreign_server form; - srvId = HeapTupleGetOid(tup); form = (Form_pg_foreign_server) GETSTRUCT(tup); if (form->srvowner != newOwnerId) @@ -366,10 +388,15 @@ AlterForeignServerOwner(const char *name, Oid newOwnerId) /* Superusers can always do it */ if (!superuser()) { + Oid srvId; + AclResult aclresult; + + srvId = HeapTupleGetOid(tup); + /* Must be owner */ if (!pg_foreign_server_ownercheck(srvId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER, - name); + NameStr(form->srvname)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); @@ -393,12 +420,57 @@ AlterForeignServerOwner(const char *name, Oid newOwnerId) changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup), newOwnerId); } +} + +/* + * Change foreign server owner -- by name + */ +void +AlterForeignServerOwner(const char *name, Oid newOwnerId) +{ + HeapTuple tup; + Relation rel; + + rel = heap_open(ForeignServerRelationId, RowExclusiveLock); + + tup = SearchSysCacheCopy1(FOREIGNSERVERNAME, CStringGetDatum(name)); + + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("server \"%s\" does not exist", name))); + + AlterForeignServerOwner_internal(rel, tup, newOwnerId); heap_freetuple(tup); heap_close(rel, RowExclusiveLock); } +/* + * Change foreign server owner -- by OID + */ +void +AlterForeignServerOwner_oid(Oid srvId, Oid newOwnerId) +{ + HeapTuple tup; + Relation rel; + + rel = heap_open(ForeignServerRelationId, RowExclusiveLock); + + tup = SearchSysCacheCopy1(FOREIGNSERVEROID, ObjectIdGetDatum(srvId)); + + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("server with OID \"%u\" does not exist", srvId))); + + AlterForeignServerOwner_internal(rel, tup, newOwnerId); + + heap_freetuple(tup); + + heap_close(rel, RowExclusiveLock); +} /* * Convert a handler function name passed from the parser to an Oid. diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 6c7c04f898..163b2ea002 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -149,7 +149,9 @@ extern List *deserialize_deflist(Datum txt); extern void RenameForeignServer(const char *oldname, const char *newname); extern void RenameForeignDataWrapper(const char *oldname, const char *newname); extern void AlterForeignServerOwner(const char *name, Oid newOwnerId); +extern void AlterForeignServerOwner_oid(Oid , Oid newOwnerId); extern void AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId); +extern void AlterForeignDataWrapperOwner_oid(Oid fwdId, Oid newOwnerId); extern void CreateForeignDataWrapper(CreateFdwStmt *stmt); extern void AlterForeignDataWrapper(AlterFdwStmt *stmt); extern void RemoveForeignDataWrapperById(Oid fdwId);