From 4853cdb5d6c773cc40a755ce32d7f6d3617eef74 Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilipkumarb@google.com>
Date: Sat, 30 May 2026 05:33:21 +0530
Subject: [PATCH v43 5/5] Create conflict log table after inserting
 subscription row

---
 src/backend/commands/subscriptioncmds.c    | 73 ++++++++++------------
 src/backend/replication/logical/conflict.c | 17 +++++
 2 files changed, 49 insertions(+), 41 deletions(-)

diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 88f22bbb286..67311a65e29 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -651,7 +651,6 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
 	uint32		supported_opts;
 	SubOpts		opts = {0};
 	AclResult	aclresult;
-	Oid			logrelid = InvalidOid;
 
 	/*
 	 * Parse and check options.
@@ -844,22 +843,45 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
 	values[Anum_pg_subscription_subconflictlogdest - 1] =
 		CStringGetTextDatum(ConflictLogDestNames[opts.conflictlogdest]);
 
+	values[Anum_pg_subscription_subconflictlogrelid - 1] =
+									ObjectIdGetDatum(InvalidOid);
+
+	tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
+
+	/* Insert tuple into catalog. */
+	CatalogTupleInsert(rel, tup);
+	//heap_freetuple(tup);
+
 	/*
 	 * If logging to a table is required, physically create it now. We create
-	 * the conflict log table here so its relation OID can be stored when
-	 * inserting the pg_subscription tuple below.
+	 * the conflict log table here.  Also update the pg_subscription row
+	 * after creating the conflict log table with its reloid.
 	 */
 	if (CONFLICTS_LOGGED_TO_TABLE(opts.conflictlogdest))
-		logrelid = create_conflict_log_table(subid, stmt->subname, owner);
+	{
+		bool		replaces[Natts_pg_subscription];
+		Oid			logrelid =
+				create_conflict_log_table(subid, stmt->subname, owner);
 
-	/* Store table OID in the catalog. */
-	values[Anum_pg_subscription_subconflictlogrelid - 1] =
-						ObjectIdGetDatum(logrelid);
+		/* Form a new tuple. */
+		memset(values, 0, sizeof(values));
+		memset(nulls, false, sizeof(nulls));
+		memset(replaces, false, sizeof(replaces));
 
-	tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
+		values[Anum_pg_subscription_subconflictlogrelid - 1] =
+									ObjectIdGetDatum(logrelid);
+		replaces[Anum_pg_subscription_subconflictlogrelid - 1] =
+									true;
+
+		/* Make subscription tuple visible before updating it. */
+		CommandCounterIncrement();
+
+		tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls,
+								replaces);
+
+		CatalogTupleUpdate(rel, &tup->t_self, tup);
+	}
 
-	/* Insert tuple into catalog. */
-	CatalogTupleInsert(rel, tup);
 	heap_freetuple(tup);
 
 	recordDependencyOnOwner(SubscriptionRelationId, subid, owner);
@@ -876,25 +898,6 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 	}
 
-	/*
-	 * If conflicts are logs to table establish an internal dependency
-	 * between the conflict log table and the subscription.
-	 *
-	 * We use DEPENDENCY_INTERNAL to signify that the table's lifecycle is
-	 * strictly tied to the subscription, similar to how a TOAST table relates
-	 * to its main table or a sequence relates to an identity column.
-	 *
-	 * This ensures the conflict log table is automatically reaped during a
-	 * DROP SUBSCRIPTION via performDeletion().
-	 */
-	if (CONFLICTS_LOGGED_TO_TABLE(opts.conflictlogdest))
-	{
-		ObjectAddress clt;
-
-		ObjectAddressSet(clt, RelationRelationId, logrelid);
-		recordDependencyOn(&clt, &myself, DEPENDENCY_INTERNAL);
-	}
-
 	/*
 	 * A replication origin is currently created for all subscriptions,
 	 * including those that only contain sequences or are otherwise empty.
@@ -1507,20 +1510,8 @@ alter_sub_conflictlogdestination(Subscription *sub, ConflictLogDest logdest,
 		/* There was no previous conflict log table. */
 		if (want_table)
 		{
-			ObjectAddress clt;
-			ObjectAddress subobj;
-
 			relid = create_conflict_log_table(sub->oid, sub->name, sub->owner);
 			update_relid = true;
-
-			/*
-			 * Establish an internal dependency between the conflict log table
-			 * and the subscription.  For details refer comments in
-			 * CreateSubscription function.
-			 */
-			ObjectAddressSet(clt, RelationRelationId, relid);
-			ObjectAddressSet(subobj, SubscriptionRelationId, sub->oid);
-			recordDependencyOn(&clt, &subobj, DEPENDENCY_INTERNAL);
 		}
 	}
 
diff --git a/src/backend/replication/logical/conflict.c b/src/backend/replication/logical/conflict.c
index 46989907b1e..27830ccb0cc 100644
--- a/src/backend/replication/logical/conflict.c
+++ b/src/backend/replication/logical/conflict.c
@@ -176,6 +176,8 @@ create_conflict_log_table(Oid subid, char *subname, Oid subowner)
 {
 	TupleDesc	tupdesc;
 	Oid			relid;
+	ObjectAddress	myself;
+	ObjectAddress	subaddr;
 	char    	relname[NAMEDATALEN];
 
 	snprintf(relname, NAMEDATALEN, "pg_conflict_log_for_subid_%u", subid);
@@ -219,6 +221,21 @@ create_conflict_log_table(Oid subid, char *subname, Oid subowner)
 									 NULL); /* typaddress */
 	Assert(OidIsValid(relid));
 
+	/*
+	 * Establish an internal dependency between the conflict log table and
+	 * the subscription.
+	 *
+	 * We use DEPENDENCY_INTERNAL to signify that the table's lifecycle is
+	 * strictly tied to the subscription, similar to how a TOAST table relates
+	 * to its main table or a sequence relates to an identity column.
+	 *
+	 * This ensures the conflict log table is automatically reaped during a
+	 * DROP SUBSCRIPTION via performDeletion().
+	 */
+	ObjectAddressSet(myself, RelationRelationId, relid);
+	ObjectAddressSet(subaddr, SubscriptionRelationId, subid);
+	recordDependencyOn(&myself, &subaddr, DEPENDENCY_INTERNAL);
+
 	/* Release tuple descriptor memory. */
 	FreeTupleDesc(tupdesc);
 
-- 
2.49.0

