From b82f60ca9cc79b4f6d0b0c059d1885f23b636ca9 Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilipkumarb@google.com>
Date: Mon, 13 Jul 2026 16:19:00 +0530
Subject: [PATCH v1] Do not reassign subscriptions belonging to other databases
 in REASSIGN OWNED.

Subscription objects are fundamentally database-local in scope. Subscription
DDL commands already operate on a per-database basis: CREATE SUBSCRIPTION
stores subdbid = MyDatabaseId, and ALTER/DROP SUBSCRIPTION commands (including
ALTER SUBSCRIPTION ... OWNER TO) look subscriptions up by (MyDatabaseId, subname)
via the unique index on (subdbid, subname), acting strictly on subscriptions in
the current database. Furthermore, subscription fields like subserver (commit
8185bb5) and subconflictlogrelid (commit a5918fd) reference database-local
objects (!relisshared) in that database.

However, because pg_subscription is stored as a shared catalog table
(relisshared == true), shared dependency entries for subscriptions in
pg_shdepend have dbid = InvalidOid. As a result, REASSIGN OWNED attempted to
reassign subscriptions belonging to any database in the cluster. When
executed in a database other than subdbid, this caused
AlterSubscriptionOwner_internal() to resolve database-local references (such as
subserver and subconflictlogrelid) against the current database (MyDatabaseId),
resulting in errors or wrongly altering unrelated objects.

Fix this by skipping subscription ownership reassignment in
AlterSubscriptionOwner_internal() if form->subdbid != MyDatabaseId. Like other
database-local objects, subscriptions will now be reassigned when REASSIGN
OWNED is executed in the database to which they belong.
---
 doc/src/sgml/ref/reassign_owned.sgml    | 5 ++++-
 doc/src/sgml/user-manag.sgml            | 4 +++-
 src/backend/commands/subscriptioncmds.c | 9 +++++++++
 3 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/doc/src/sgml/ref/reassign_owned.sgml b/doc/src/sgml/ref/reassign_owned.sgml
index ab692bd0690..5fca2329de2 100644
--- a/doc/src/sgml/ref/reassign_owned.sgml
+++ b/doc/src/sgml/ref/reassign_owned.sgml
@@ -48,7 +48,10 @@ REASSIGN OWNED BY { <replaceable class="parameter">old_role</replaceable> | CURR
       The name of a role. The ownership of all the objects within the
       current database, and of all shared objects (databases, tablespaces),
       owned by this role will be reassigned to
-      <replaceable class="parameter">new_role</replaceable>.
+      <replaceable class="parameter">new_role</replaceable>. Subscriptions,
+      although stored in a shared catalog, belong to a specific database
+      and are reassigned only when <command>REASSIGN OWNED</command> is executed
+      in that database.
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml
index 0ec32700bd4..c7e0b11706e 100644
--- a/doc/src/sgml/user-manag.sgml
+++ b/doc/src/sgml/user-manag.sgml
@@ -530,7 +530,9 @@ ALTER TABLE bobs_table OWNER TO alice;
    that contains objects owned by the role.  (Note that the first
    such <command>REASSIGN OWNED</command> will change the ownership of any
    shared-across-databases objects, that is databases or tablespaces, that
-   are owned by the role-to-be-dropped.)
+   are owned by the role-to-be-dropped. Subscriptions, while stored in a
+   shared catalog, belong to a specific database and are reassigned when
+   <command>REASSIGN OWNED</command> is executed in that database.)
   </para>
 
   <para>
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 4292e7fb8f4..cd37885222a 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -2868,6 +2868,15 @@ AlterSubscriptionOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 
 	form = (Form_pg_subscription) GETSTRUCT(tup);
 
+	/*
+	 * Don't process subscriptions belonging to other databases. While
+	 * pg_subscription is a shared catalog, subscriptions refer to db-local
+	 * objects like subserver and subconflictlogrelid which exist only in the
+	 * database identified by subdbid.
+	 */
+	if (form->subdbid != MyDatabaseId)
+		return;
+
 	if (form->subowner == newOwnerId)
 		return;
 
-- 
2.49.0

