From 6dd5cb5ff078e03944f180bac57e9432e880700e Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <lic@highgo.com>
Date: Mon, 12 Jan 2026 16:56:58 +0800
Subject: [PATCH v3] Add notice when ALTER TABLE REPLICA IDENTITY does not
 recurse

ALTER TABLE ... REPLICA IDENTITY accepts a recursive form on
partitioned tables, but the change is applied only to the partitioned
table itself and does not propagate to child partitions.

Previously this case was silently accepted, which could mislead users
into assuming that the setting would recurse. Add a notice when
recursion is requested on a partitioned table to make the behavior
explicit and avoid confusion.

This change does not alter semantics; it only provides user-visible
feedback. Similar notices may be added for other ALTER TABLE
sub-commands with non-recursive behavior in follow-up commits.

Author: Chao Li <lic@highgo.com>
Reviewed-by: David G. Johnston <david.g.johnston@gmail.com>
Reviewed-by: Greg Sabino Mullane <htamfids@gmail.com>
Discussion: https://postgr.es/m/CAEoWx2=SLga-xH09Cq_PAvsHhQHrBK+V0vF821JKgzS=Bm0haA@mail.gmail.com
---
 src/backend/commands/tablecmds.c | 33 +++++++++++++++++++++++++++-----
 1 file changed, 28 insertions(+), 5 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f976c0e5c7e..31ae0b9e827 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -693,7 +693,7 @@ static void drop_parent_dependency(Oid relid, Oid refclassid, Oid refobjid,
 								   DependencyType deptype);
 static ObjectAddress ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode);
 static void ATExecDropOf(Relation rel, LOCKMODE lockmode);
-static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode);
+static void ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, bool recurse, LOCKMODE lockmode);
 static void ATExecGenericOptions(Relation rel, List *options);
 static void ATExecSetRowSecurity(Relation rel, bool rls);
 static void ATExecForceNoForceRowSecurity(Relation rel, bool force_rls);
@@ -5227,8 +5227,15 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
 			ATSimplePermissions(cmd->subtype, rel,
 								ATT_TABLE | ATT_PARTITIONED_TABLE | ATT_MATVIEW);
 			pass = AT_PASS_MISC;
-			/* This command never recurses */
-			/* No command-specific prep needed */
+
+			/*
+			 * This command now doesn't recurse, but we want to notify user if
+			 * recurse is set
+			 *
+			 * No command-specific prep needed
+			 */
+			if (recurse)
+				cmd->recurse = true;
 			break;
 		case AT_EnableTrig:		/* ENABLE TRIGGER variants */
 		case AT_EnableAlwaysTrig:
@@ -5643,7 +5650,8 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab,
 			ATExecDropOf(rel, lockmode);
 			break;
 		case AT_ReplicaIdentity:
-			ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def, lockmode);
+			ATExecReplicaIdentity(rel, (ReplicaIdentityStmt *) cmd->def,
+								  cmd->recurse, lockmode);
 			break;
 		case AT_EnableRowSecurity:
 			ATExecSetRowSecurity(rel, true);
@@ -18515,12 +18523,27 @@ relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
  * ALTER TABLE <name> REPLICA IDENTITY ...
  */
 static void
-ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode)
+ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, bool recurse, LOCKMODE lockmode)
 {
 	Oid			indexOid;
 	Relation	indexRel;
 	int			key;
 
+	if (recurse && rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	{
+		PartitionDesc pd = RelationGetPartitionDesc(rel, true);
+		int			nparts = pd->nparts;
+
+		/*
+		 * The recurse flag is set, but this command does not actually
+		 * recurse. Emit a NOTICE to make this behavior explicit to the user.
+		 */
+		if (nparts > 0)
+			ereport(NOTICE,
+					(errmsg("present partitions not affected")),
+					errhint("partitions may be modified individually using separate commands"));
+	}
+
 	if (stmt->identity_type == REPLICA_IDENTITY_DEFAULT)
 	{
 		relation_mark_replica_identity(rel, stmt->identity_type, InvalidOid, true);
-- 
2.39.5 (Apple Git-154)

