From a8e1329bb58436b44d4f0daadc5240daebd39bae Mon Sep 17 00:00:00 2001 From: Dilip Kumar Date: Sat, 30 May 2026 05:33:21 +0530 Subject: [PATCH v42] 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 15b0ef7f3ca..0f077b28678 100644 --- a/src/backend/replication/logical/conflict.c +++ b/src/backend/replication/logical/conflict.c @@ -175,6 +175,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); @@ -218,6 +220,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