Hi!
>  * What are the most important use cases here? Are we just trying to
> avoid the unnecessary use of superuser, or is there a real use case for
> subscribing to a subset of a publication?

For instance in target database we do not have permission on some table used in 
publication,
but we still CREATE SUBSCRIPTION for owned tables.

>  * What are all the reasons CREATE SUBSCRIPTION currently requires
> superuser?
I'm not sure, but it seems like only superuser have rights on all tables. I 
can't find any restrictions.

>  * Is the original idea of a special role still viable?
yes, i wrote simple patch. Role create externally, but it can be system role. 
-------- 
Efimkin Evgeny
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 9021463a4c..31b5b9af8c 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -322,6 +322,7 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
    char        originname[NAMEDATALEN];
    bool        create_slot;
    List       *publications;
+   Oid         role;

    /*
     * Parse and check options.
@@ -341,11 +342,13 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
     */
    if (create_slot)
        PreventInTransactionBlock(isTopLevel, "CREATE SUBSCRIPTION ... WITH (create_slot = true)");
-
-   if (!superuser())
+   role = get_role_oid("pg_subsciption_users", true);
+   if (!is_member_of_role(GetUserId(), role))
+   {
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                (errmsg("must be superuser to create subscriptions"))));
+                (errmsg("must be pg_subsciption_users to create subscriptions"))));
+   }

    rel = heap_open(SubscriptionRelationId, RowExclusiveLock);

@@ -1023,6 +1026,7 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
 static void
 AlterSubscriptionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 {
+   Oid role;
    Form_pg_subscription form;

    form = (Form_pg_subscription) GETSTRUCT(tup);
@@ -1034,13 +1038,16 @@ AlterSubscriptionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
        aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SUBSCRIPTION,
                       NameStr(form->subname));

+   role = get_role_oid("pg_subsciption_users", true);
    /* New owner must be a superuser */
-   if (!superuser_arg(newOwnerId))
+   if (!is_member_of_role(GetUserId(), role))
+   {
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("permission denied to change owner of subscription \"%s\"",
                        NameStr(form->subname)),
-                errhint("The owner of a subscription must be a superuser.")));
+                errhint("The owner of a subscription must be a pg_subsciption_users.")));
+   }

    form->subowner = newOwnerId;
    CatalogTupleUpdate(rel, &tup->t_self, tup);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index 38ae1b9ab8..fa5d343993 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -754,6 +754,8 @@ copy_table(Relation rel)
    CopyState   cstate;
    List       *attnamelist;
    ParseState *pstate;
+   AclResult   aclresult;
+   AclMode         aclmask;

    /* Get the publisher relation info. */
    fetch_remote_table_info(get_namespace_name(RelationGetNamespace(rel)),
@@ -770,6 +772,13 @@ copy_table(Relation rel)
    initStringInfo(&cmd);
    appendStringInfo(&cmd, "COPY %s TO STDOUT",
                     quote_qualified_identifier(lrel.nspname, lrel.relname));
+   aclmask = ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE;
+   aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
+                                 aclmask);
+   if (aclresult != ACLCHECK_OK)
+       aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
+                      RelationGetRelationName(rel));
+
    res = walrcv_exec(wrconn, cmd.data, 0, NULL);
    pfree(cmd.data);
    if (res->status != WALRCV_OK_COPY_OUT)

Reply via email to