Thread

  1. Re: Proposal: Conflict log history table for Logical Replication

    vignesh C <vignesh21@gmail.com> — 2026-05-26T05:53:51Z

    On Mon, 25 May 2026 at 07:07, Peter Smith <smithpb2250@gmail.com> wrote:
    >
    > Hi Vignesh,
    >
    > Some review comments for v38-0001/0002 combined.
    >
    > ======
    > src/backend/commands/subscriptioncmds.c
    >
    > AlterSubscriptionConflictLogDestination:
    >
    > 1.
    >  * Update the conflict log table associated with a subscription when its
    >  * conflict log destination is changed.
    >
    > Somehow, that 'its' sounded awkward to me.
    >
    > SUGGESTION.
    > When the subscription's 'conflict_log_destination' is changed, update
    > the conflict log table if required.
    >
    > ~~~
    >
    > 2.
    > + * If the new destination requires a conflict log table and none was previously
    > + * required, this function validates an existing conflict log table identified
    > + * by the subscription specific naming convention or creates a new one.
    >
    > What does this mean: "validates an existing conflict log table". How
    > is there an "existing" CLT when you already said "none was previously
    > required". Maybe this needs more explanation. If it is talking about
    > "not already associated with another subscription", then it should
    > just say that.
    >
    > Anyway, it seems validation that the comment claims this function is
    > doing is not done here at all, but is really done by
    > 'create_conflict_log_table'.
    >
    > ~~~
    >
    > 3.
    > +static bool
    > +AlterSubscriptionConflictLogDestination(Subscription *sub,
    > + ConflictLogDest logdest,
    > + Oid *conflicttablerelid)
    >
    > 3a.
    > There was no forward declaration of this static function, but there
    > was for all the others.
    >
    > ~
    >
    > 3b.
    > Static functions should use snake-case names.
    >
    > ~~~
    >
    > 4.
    > Personally, I think it is more natural to read LEFT-TO-RIGHT,
    > OLD-THEN-NEW, etc., so I felt that the has_oldtable check should
    > always come before want_table.
    >
    > Also, the 'ifs' seemed tricky because it's not obvious what
    > has/need_table combinations are missing. e.g. The following seems
    > easier to me. And probably lots of comments could be moved to here in
    > the code as well, instead of in the function comment.
    >
    > SUGGESTION
    > if (has_old_table)
    > {
    >   /* There is a CLT already. */
    >
    >   if (!want_table)
    >   {
    >     /* Remove it. */
    >     drop_subscription_dependencies(sub->oid, sub->name, sub->conflictlogrelid);
    >     update_relid = true;
    >   }
    > }
    > else
    > {
    >   /* There was no previous CLT. */
    >
    >   if (want_table)
    >   {
    >     /* Create one. */
    >     relid = create_conflict_log_table(sub->oid, sub->name, sub->owner);
    >     update_relid = true;
    >   }
    > }
    >
    > ~~~
    >
    > 5.
    > +static void
    > +drop_subscription_dependencies(Oid subid, char *subname,
    > +    Oid subconflictlogrelid)
    > +{
    > + ObjectAddress object;
    > + char *conflictrelname;
    > +
    > + conflictrelname = get_rel_name(subconflictlogrelid);
    > +
    > + /*
    > + * By using PERFORM_DELETION_SKIP_ORIGINAL, we ensure that only the
    > + * conflict log table is deleted while the subscription remains.
    > + */
    > + ObjectAddressSet(object, SubscriptionRelationId, subid);
    > + performDeletion(&object, DROP_CASCADE,
    > + PERFORM_DELETION_INTERNAL |
    > + PERFORM_DELETION_SKIP_ORIGINAL);
    > +
    > + ereport(NOTICE,
    > + errmsg("dropped conflict log table \"%s\" for subscription \"%s\"",
    > + get_qualified_objname(PG_CONFLICT_NAMESPACE, conflictrelname),
    > + subname));
    > +}
    > +
    >
    > One day, this function might do more than just remove the CLT, so IMO
    > all this function body should be within a check:
    >
    > if (OidIsValid(subconflictlogrelid))
    > {
    >   /* Drop any dependent CLT */
    >   ...
    > }
    >
    > ~~~
    >
    > DropSubscription
    >
    > 6.
    > + if (OidIsValid(subconflictlogrelid))
    > + drop_subscription_dependencies(subid, subname, subconflictlogrelid);
    >
    > Make it unconditional. Instead, add the condition inside the
    > 'drop_subscription_dependencies', per the previous review comment #5.
    >
    > ======
    > src/test/regress/sql/subscription.sql
    >
    > 7.
    > +--
    > +-- PUBLICATION: Verify conflict log tables are not publishable
    > +--
    > +-- pg_relation_is_publishable should return false for internal conflict log
    > +-- tables to prevent them from being accidentally included in publications
    > +--
    >
    > Everywhere else, you had removed the word "internal", but this one
    > (maybe others?) was missed.
    
    Thanks for the comments, these are addressed in the v40 version patch attached.
    
    Regards,
    Vignesh