diff --git a/src/backend/replication/logical/conflict.c b/src/backend/replication/logical/conflict.c index 527ee2b27a5..d5146d21bc4 100644 --- a/src/backend/replication/logical/conflict.c +++ b/src/backend/replication/logical/conflict.c @@ -131,7 +131,8 @@ static const char *const ConflictTypeNames[] = { [CT_MULTIPLE_UNIQUE_CONFLICTS] = "multiple_unique_conflicts" }; -static Relation get_conflictlog_dest_and_table(ConflictLogDest *log_dest); +static Relation get_conflictlog_dest_and_table(int elevel, + ConflictLogDest *log_dest); static int errcode_apply_conflict(ConflictType type); static void errdetail_apply_conflict(EState *estate, ResultRelInfo *relinfo, @@ -335,25 +336,13 @@ ReportApplyConflict(EState *estate, ResultRelInfo *relinfo, int elevel, TupleTableSlot *remoteslot, List *conflicttuples) { Relation localrel = relinfo->ri_RelationDesc; - ConflictLogDest dest = CONFLICT_LOG_DEST_LOG; - Relation conflictlogrel = NULL; - bool log_dest_table; - bool log_dest_logfile; + ConflictLogDest dest; + Relation conflictlogrel; StringInfoData err_detail; pgstat_report_subscription_conflict(MySubscription->oid, type); - /* - * Only LOG-level conflicts (i.e. resolved conflicts where the transaction - * continues) are recorded in the conflict log table. ERROR-level - * conflicts halt replication and abort the transaction, so they are - * always reported exclusively to the server log. - */ - if (elevel < ERROR) - conflictlogrel = get_conflictlog_dest_and_table(&dest); - - log_dest_table = CONFLICTS_LOGGED_TO_TABLE(dest); - log_dest_logfile = CONFLICTS_LOGGED_TO_LOG(dest); + conflictlogrel = get_conflictlog_dest_and_table(elevel, &dest); initStringInfo(&err_detail); @@ -363,7 +352,7 @@ ReportApplyConflict(EState *estate, ResultRelInfo *relinfo, int elevel, * Otherwise (table-only for LOG-level conflicts), emit a shorter message * noting that the details are captured in the conflict log table. */ - if (log_dest_logfile) + if (CONFLICTS_LOGGED_TO_LOG(dest)) { /* Form errdetail message by combining conflicting tuples information. */ if (conflicttuples != NIL) @@ -388,7 +377,7 @@ ReportApplyConflict(EState *estate, ResultRelInfo *relinfo, int elevel, &err_detail); } } - else if (log_dest_table) + else { appendStringInfo(&err_detail, _("Conflict details are logged to the conflict log table: %s.%s"), @@ -408,11 +397,8 @@ ReportApplyConflict(EState *estate, ResultRelInfo *relinfo, int elevel, * Insert into the conflict log table for LOG-level conflicts if * requested. */ - if (log_dest_table) + if (conflictlogrel) { - Assert(conflictlogrel != NULL); - Assert(elevel < ERROR); - insert_conflict_log_tuple(estate, relinfo->ri_RelationDesc, conflictlogrel, @@ -457,22 +443,28 @@ InitConflictIndexes(ResultRelInfo *relInfo) /* * get_conflictlog_dest_and_table * - * Fetches conflict logging metadata from the cached MySubscription pointer. - * Sets the destination enum in *log_dest and, if a table is one of the - * destinations, opens and returns the relation handle for the conflict log - * table. + * Decides where a conflict of the given elevel is to be reported, based on + * the subscription's conflict_log_destination. Sets *log_dest to the + * effective destination and, if that includes the conflict log table, returns + * the table opened for insertion. Otherwise returns NULL. * - * The table is opened with try_table_open(), so NULL is returned if the - * conflict log table has been dropped concurrently (e.g. by an ALTER - * SUBSCRIPTION that changed conflict_log_destination). In that case - * *log_dest falls back to server-log reporting. + * Only LOG-level conflicts (i.e. resolved conflicts where the transaction + * continues) are recorded in the conflict log table. ERROR-level conflicts + * halt replication and abort the transaction, so they are always reported + * exclusively to the server log. */ static Relation -get_conflictlog_dest_and_table(ConflictLogDest *log_dest) +get_conflictlog_dest_and_table(int elevel, ConflictLogDest *log_dest) { Relation conflictlogrel; Oid conflictlogrelid; + if (elevel >= ERROR) + { + *log_dest = CONFLICT_LOG_DEST_LOG; + return NULL; + } + /* * Convert the text log destination to the internal enum. MySubscription * already contains the data from pg_subscription. @@ -488,10 +480,10 @@ get_conflictlog_dest_and_table(ConflictLogDest *log_dest) Assert(OidIsValid(conflictlogrelid)); /* - * Use try_table_open(): the table may have been dropped concurrently by an - * ALTER SUBSCRIPTION that changed conflict_log_destination. Returning - * NULL and tell the caller to fall back to the server log instead of - * failing. + * Use try_table_open() because the table may have been dropped + * concurrently by an ALTER SUBSCRIPTION that changed + * conflict_log_destination. In that case, fall back to the server log + * instead of failing. */ conflictlogrel = try_table_open(conflictlogrelid, RowExclusiveLock);