diff options
-rw-r--r-- | src/backend/catalog/pg_publication.c | 30 | ||||
-rw-r--r-- | src/backend/commands/publicationcmds.c | 7 | ||||
-rw-r--r-- | src/include/catalog/pg_publication.h | 1 | ||||
-rw-r--r-- | src/test/regress/expected/publication.out | 15 | ||||
-rw-r--r-- | src/test/regress/sql/publication.sql | 15 |
5 files changed, 68 insertions, 0 deletions
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index b40293fcb31..65db07f6024 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -193,6 +193,36 @@ is_publishable_relation(Relation rel) return is_publishable_class(RelationGetRelid(rel), rel->rd_rel); } +/* + * Returns true if any schema is associated with the publication, false if no + * schema is associated with the publication. + */ +bool +is_schema_publication(Oid pubid) +{ + Relation pubschsrel; + ScanKeyData scankey; + SysScanDesc scan; + HeapTuple tup; + bool result = false; + + pubschsrel = table_open(PublicationNamespaceRelationId, AccessShareLock); + ScanKeyInit(&scankey, + Anum_pg_publication_namespace_pnpubid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(pubid)); + + scan = systable_beginscan(pubschsrel, + PublicationNamespacePnnspidPnpubidIndexId, + true, NULL, 1, &scankey); + tup = systable_getnext(scan); + result = HeapTupleIsValid(tup); + + systable_endscan(scan); + table_close(pubschsrel, AccessShareLock); + + return result; +} /* * SQL-callable variant of the above diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index 7d4a0e95f6c..404bb5d0c87 100644 --- a/src/backend/commands/publicationcmds.c +++ b/src/backend/commands/publicationcmds.c @@ -1192,6 +1192,13 @@ AlterPublicationOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) errmsg("permission denied to change owner of publication \"%s\"", NameStr(form->pubname)), errhint("The owner of a FOR ALL TABLES publication must be a superuser."))); + + if (!superuser_arg(newOwnerId) && is_schema_publication(form->oid)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to change owner of publication \"%s\"", + NameStr(form->pubname)), + errhint("The owner of a FOR ALL TABLES IN SCHEMA publication must be a superuser."))); } form->pubowner = newOwnerId; diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h index 1ae439e6f36..902f2f2f0da 100644 --- a/src/include/catalog/pg_publication.h +++ b/src/include/catalog/pg_publication.h @@ -122,6 +122,7 @@ extern List *GetPubPartitionOptionRelations(List *result, Oid relid); extern bool is_publishable_relation(Relation rel); +extern bool is_schema_publication(Oid pubid); extern ObjectAddress publication_add_relation(Oid pubid, PublicationRelInfo *targetrel, bool if_not_exists); extern ObjectAddress publication_add_schema(Oid pubid, Oid schemaid, diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out index a2115c1c606..c096fbdac58 100644 --- a/src/test/regress/expected/publication.out +++ b/src/test/regress/expected/publication.out @@ -373,6 +373,21 @@ ALTER PUBLICATION testpub2 ADD TABLE testpub_tbl1; -- ok DROP PUBLICATION testpub2; DROP PUBLICATION testpub3; SET ROLE regress_publication_user; +CREATE ROLE regress_publication_user3; +GRANT regress_publication_user2 TO regress_publication_user3; +SET client_min_messages = 'ERROR'; +CREATE PUBLICATION testpub4 FOR ALL TABLES IN SCHEMA pub_test; +RESET client_min_messages; +ALTER PUBLICATION testpub4 OWNER TO regress_publication_user3; +SET ROLE regress_publication_user3; +-- fail - new owner must be superuser +ALTER PUBLICATION testpub4 owner to regress_publication_user2; -- fail +ERROR: permission denied to change owner of publication "testpub4" +HINT: The owner of a FOR ALL TABLES IN SCHEMA publication must be a superuser. +ALTER PUBLICATION testpub4 owner to regress_publication_user; -- ok +SET ROLE regress_publication_user; +DROP PUBLICATION testpub4; +DROP ROLE regress_publication_user3; REVOKE CREATE ON DATABASE regression FROM regress_publication_user2; DROP TABLE testpub_parted; DROP TABLE testpub_tbl1; diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql index 2fe41b07ae2..06628825444 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -218,6 +218,21 @@ DROP PUBLICATION testpub2; DROP PUBLICATION testpub3; SET ROLE regress_publication_user; +CREATE ROLE regress_publication_user3; +GRANT regress_publication_user2 TO regress_publication_user3; +SET client_min_messages = 'ERROR'; +CREATE PUBLICATION testpub4 FOR ALL TABLES IN SCHEMA pub_test; +RESET client_min_messages; +ALTER PUBLICATION testpub4 OWNER TO regress_publication_user3; +SET ROLE regress_publication_user3; +-- fail - new owner must be superuser +ALTER PUBLICATION testpub4 owner to regress_publication_user2; -- fail +ALTER PUBLICATION testpub4 owner to regress_publication_user; -- ok + +SET ROLE regress_publication_user; +DROP PUBLICATION testpub4; +DROP ROLE regress_publication_user3; + REVOKE CREATE ON DATABASE regression FROM regress_publication_user2; DROP TABLE testpub_parted; |