v37-0009-Review-comment-fixes-for-Documentation-patch.patch
application/octet-stream
Filename: v37-0009-Review-comment-fixes-for-Documentation-patch.patch
Type: application/octet-stream
Part: 9
From b6fa6312603a23eec84c45295a65f51b3fb3890b Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Mon, 18 May 2026 09:00:17 +0000
Subject: [PATCH v37 09/10] Review comment fixes for Documentation patch.
Review comment fixes for Documentation patch.
---
doc/src/sgml/logical-replication.sgml | 740 +++++++++++-----------
doc/src/sgml/ref/create_subscription.sgml | 16 +-
2 files changed, 388 insertions(+), 368 deletions(-)
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
index 572e0d45383..71b7bd291dd 100644
--- a/doc/src/sgml/logical-replication.sgml
+++ b/doc/src/sgml/logical-replication.sgml
@@ -301,9 +301,10 @@
<literal>conflict_log_destination</literal></link> option to record detailed
conflict information in a structured, queryable format. When this parameter
is set to <literal>table</literal> or <literal>all</literal>, the system
- automatically manages a dedicated conflict log table, which is created and
- dropped along with the subscription. This significantly improves post-mortem
- analysis and operational visibility of the replication setup.
+ automatically manages a dedicated <firstterm>conflict log table</firstterm>,
+ which is created an dropped along with the subscription. This significantly
+ improves post-mortem analysis and operational visibility of the replication
+ setup.
</para>
<sect2 id="logical-replication-subscription-slot">
@@ -2022,212 +2023,223 @@ Included in publications:
operations will simply be skipped.
</para>
- <para>
- Additional logging is triggered, and the conflict statistics are collected (displayed in the
- <link linkend="monitoring-pg-stat-subscription-stats"><structname>pg_stat_subscription_stats</structname></link> view)
- in the following <firstterm>conflict</firstterm> cases:
- <variablelist>
- <varlistentry id="conflict-insert-exists" xreflabel="insert_exists">
- <term><literal>insert_exists</literal></term>
- <listitem>
- <para>
- Inserting a row that violates a <literal>NOT DEFERRABLE</literal>
- unique constraint. Note that to log the origin and commit
- timestamp details of the conflicting key,
- <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
- should be enabled on the subscriber. In this case, an error will be
- raised until the conflict is resolved manually.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="conflict-update-origin-differs" xreflabel="update_origin_differs">
- <term><literal>update_origin_differs</literal></term>
- <listitem>
- <para>
- Updating a row that was previously modified by another origin.
- Note that this conflict can only be detected when
- <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
- is enabled on the subscriber. Currently, the update is always applied
- regardless of the origin of the local row.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="conflict-update-exists" xreflabel="update_exists">
- <term><literal>update_exists</literal></term>
- <listitem>
- <para>
- The updated value of a row violates a <literal>NOT DEFERRABLE</literal>
- unique constraint. Note that to log the origin and commit
- timestamp details of the conflicting key,
- <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
- should be enabled on the subscriber. In this case, an error will be
- raised until the conflict is resolved manually. Note that when updating a
- partitioned table, if the updated row value satisfies another partition
- constraint resulting in the row being inserted into a new partition, the
- <literal>insert_exists</literal> conflict may arise if the new row
- violates a <literal>NOT DEFERRABLE</literal> unique constraint.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="conflict-update-deleted" xreflabel="update_deleted">
- <term><literal>update_deleted</literal></term>
- <listitem>
- <para>
- The tuple to be updated was concurrently deleted by another origin. The
- update will simply be skipped in this scenario. Note that this conflict
- can only be detected when
- <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
- and <link linkend="sql-createsubscription-params-with-retain-dead-tuples"><literal>retain_dead_tuples</literal></link>
- are enabled. Note that if a tuple cannot be found due to the table being
- truncated, only a <literal>update_missing</literal> conflict will
- arise. Additionally, if the tuple was deleted by the same origin, an
- <literal>update_missing</literal> conflict will arise.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="conflict-update-missing" xreflabel="update_missing">
- <term><literal>update_missing</literal></term>
- <listitem>
- <para>
- The row to be updated was not found. The update will simply be
- skipped in this scenario.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="conflict-delete-origin-differs" xreflabel="delete_origin_differs">
- <term><literal>delete_origin_differs</literal></term>
- <listitem>
- <para>
- Deleting a row that was previously modified by another origin. Note that
- this conflict can only be detected when
- <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
- is enabled on the subscriber. Currently, the delete is always applied
- regardless of the origin of the local row.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="conflict-delete-missing" xreflabel="delete_missing">
- <term><literal>delete_missing</literal></term>
- <listitem>
- <para>
- The row to be deleted was not found. The delete will simply be
- skipped in this scenario.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="conflict-multiple-unique-conflicts" xreflabel="multiple_unique_conflicts">
- <term><literal>multiple_unique_conflicts</literal></term>
- <listitem>
- <para>
- Inserting or updating a row violates multiple
- <literal>NOT DEFERRABLE</literal> unique constraints. Note that to log
- the origin and commit timestamp details of conflicting keys, ensure
- that <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
- is enabled on the subscriber. In this case, an error will be raised until
- the conflict is resolved manually.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- Note that there are other conflict scenarios, such as exclusion constraint
- violations. Currently, we do not provide additional details for them in the
- log.
- </para>
+ <sect2 id="logical-replication-conflict-logging">
+ <title>Conflict logging</title>
+ <para>
+ Additional logging is triggered, and the conflict statistics are collected (displayed in the
+ <link linkend="monitoring-pg-stat-subscription-stats"><structname>pg_stat_subscription_stats</structname></link> view)
+ in the following <firstterm>conflict</firstterm> cases:
+ <variablelist>
+ <varlistentry id="conflict-insert-exists" xreflabel="insert_exists">
+ <term><literal>insert_exists</literal></term>
+ <listitem>
+ <para>
+ Inserting a row that violates a <literal>NOT DEFERRABLE</literal>
+ unique constraint. Note that to log the origin and commit
+ timestamp details of the conflicting key,
+ <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
+ should be enabled on the subscriber. In this case, an error will be
+ raised until the conflict is resolved manually.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="conflict-update-origin-differs" xreflabel="update_origin_differs">
+ <term><literal>update_origin_differs</literal></term>
+ <listitem>
+ <para>
+ Updating a row that was previously modified by another origin.
+ Note that this conflict can only be detected when
+ <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
+ is enabled on the subscriber. Currently, the update is always applied
+ regardless of the origin of the local row.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="conflict-update-exists" xreflabel="update_exists">
+ <term><literal>update_exists</literal></term>
+ <listitem>
+ <para>
+ The updated value of a row violates a <literal>NOT DEFERRABLE</literal>
+ unique constraint. Note that to log the origin and commit
+ timestamp details of the conflicting key,
+ <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
+ should be enabled on the subscriber. In this case, an error will be
+ raised until the conflict is resolved manually. Note that when updating a
+ partitioned table, if the updated row value satisfies another partition
+ constraint resulting in the row being inserted into a new partition, the
+ <literal>insert_exists</literal> conflict may arise if the new row
+ violates a <literal>NOT DEFERRABLE</literal> unique constraint.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="conflict-update-deleted" xreflabel="update_deleted">
+ <term><literal>update_deleted</literal></term>
+ <listitem>
+ <para>
+ The tuple to be updated was concurrently deleted by another origin. The
+ update will simply be skipped in this scenario. Note that this conflict
+ can only be detected when
+ <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
+ and <link linkend="sql-createsubscription-params-with-retain-dead-tuples"><literal>retain_dead_tuples</literal></link>
+ are enabled. Note that if a tuple cannot be found due to the table being
+ truncated, only a <literal>update_missing</literal> conflict will
+ arise. Additionally, if the tuple was deleted by the same origin, an
+ <literal>update_missing</literal> conflict will arise.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="conflict-update-missing" xreflabel="update_missing">
+ <term><literal>update_missing</literal></term>
+ <listitem>
+ <para>
+ The row to be updated was not found. The update will simply be
+ skipped in this scenario.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="conflict-delete-origin-differs" xreflabel="delete_origin_differs">
+ <term><literal>delete_origin_differs</literal></term>
+ <listitem>
+ <para>
+ Deleting a row that was previously modified by another origin. Note that
+ this conflict can only be detected when
+ <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
+ is enabled on the subscriber. Currently, the delete is always applied
+ regardless of the origin of the local row.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="conflict-delete-missing" xreflabel="delete_missing">
+ <term><literal>delete_missing</literal></term>
+ <listitem>
+ <para>
+ The row to be deleted was not found. The delete will simply be
+ skipped in this scenario.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry id="conflict-multiple-unique-conflicts" xreflabel="multiple_unique_conflicts">
+ <term><literal>multiple_unique_conflicts</literal></term>
+ <listitem>
+ <para>
+ Inserting or updating a row violates multiple
+ <literal>NOT DEFERRABLE</literal> unique constraints. Note that to log
+ the origin and commit timestamp details of conflicting keys, ensure
+ that <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
+ is enabled on the subscriber. In this case, an error will be raised until
+ the conflict is resolved manually.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ Note that there are other conflict scenarios, such as exclusion constraint
+ violations. Currently, we do not provide additional details for them in the
+ log.
+ </para>
+ </sect2>
- <para>
- The <link linkend="sql-createsubscription-params-with-conflict-log-destination"><literal>conflict_log_destination</literal></link>
- parameter automatically creates a dedicated conflict log table. This table is created in the dedicated
- <literal>pg_conflict</literal> namespace. The name of the conflict log table
- is <literal>pg_conflict_log_<subid></literal>. The predefined schema of this table is
- detailed in
- <xref linkend="logical-replication-conflict-log-schema"/>.
- </para>
+ <sect2 id="logical-replication-conflict-table-based-logging">
+ <title>Table-based logging</title>
+ <para>
+ If <link linkend="sql-createsubscription-params-with-conflict-log-destination"><literal>conflict_log_destination</literal></link>
+ parameter is set to <literal>table</literal> or <literal>all</literal> then
+ a dedicated conflict log table will be automatically created. This table is
+ created in the <literal>pg_conflict</literal> namespace. The name of the
+ conflict log table is
+ <literal>pg_conflict_log_for_subid_<subid></literal>. The predefined
+ schema of this table is detailed in
+ <xref linkend="logical-replication-conflict-log-schema"/>.
+ </para>
- <table id="logical-replication-conflict-log-schema">
- <title>Conflict Log Table Schema</title>
- <tgroup cols="3">
- <thead>
- <row>
- <entry>Column</entry>
- <entry>Type</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><literal>relid</literal></entry>
- <entry><type>oid</type></entry>
- <entry>The OID of the local table where the conflict occurred.</entry>
- </row>
- <row>
- <entry><literal>schemaname</literal></entry>
- <entry><type>text</type></entry>
- <entry>The schema name of the conflicting table.</entry>
- </row>
- <row>
- <entry><literal>relname</literal></entry>
- <entry><type>text</type></entry>
- <entry>The name of the conflicting table.</entry>
- </row>
- <row>
- <entry><literal>conflict_type</literal></entry>
- <entry><type>text</type></entry>
- <entry>The type of conflict that occurred (e.g., <literal>insert_exists</literal>).</entry>
- </row>
- <row>
- <entry><literal>remote_xid</literal></entry>
- <entry><type>xid</type></entry>
- <entry>The remote transaction ID that caused the conflict.</entry>
- </row>
- <row>
- <entry><literal>remote_commit_lsn</literal></entry>
- <entry><type>pg_lsn</type></entry>
- <entry>The final LSN of the remote transaction.</entry>
- </row>
- <row>
- <entry><literal>remote_commit_ts</literal></entry>
- <entry><type>timestamptz</type></entry>
- <entry>The remote commit timestamp of the remote transaction.</entry>
- </row>
- <row>
- <entry><literal>remote_origin</literal></entry>
- <entry><type>text</type></entry>
- <entry>The origin of the remote transaction.</entry>
- </row>
- <row>
- <entry><literal>replica_identity</literal></entry>
- <entry><type>json</type></entry>
- <entry>The JSON representation of the replica identity.</entry>
- </row>
- <row>
- <entry><literal>remote_tuple</literal></entry>
- <entry><type>json</type></entry>
- <entry>The JSON representation of the incoming remote row that caused the conflict.</entry>
- </row>
- <row>
- <entry><literal>local_conflicts</literal></entry>
- <entry><type>json[]</type></entry>
- <entry>
- An array of JSON objects representing the local state for each conflict attempt.
- Each object includes the local transaction ID (<literal>xid</literal>), commit
- timestamp (<literal>commit_ts</literal>), origin (<literal>origin</literal>),
- conflicting key data (<literal>key</literal>), and the full local row
- image (<literal>tuple</literal>).
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
+ <table id="logical-replication-conflict-log-schema">
+ <title>Conflict Log Table Schema</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Column</entry>
+ <entry>Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>relid</literal></entry>
+ <entry><type>oid</type></entry>
+ <entry>The OID of the local table where the conflict occurred.</entry>
+ </row>
+ <row>
+ <entry><literal>schemaname</literal></entry>
+ <entry><type>text</type></entry>
+ <entry>The schema name of the conflicting table.</entry>
+ </row>
+ <row>
+ <entry><literal>relname</literal></entry>
+ <entry><type>text</type></entry>
+ <entry>The name of the conflicting table.</entry>
+ </row>
+ <row>
+ <entry><literal>conflict_type</literal></entry>
+ <entry><type>text</type></entry>
+ <entry>The type of conflict that occurred (e.g., <literal>insert_exists</literal>).</entry>
+ </row>
+ <row>
+ <entry><literal>remote_xid</literal></entry>
+ <entry><type>xid</type></entry>
+ <entry>The remote transaction ID that caused the conflict.</entry>
+ </row>
+ <row>
+ <entry><literal>remote_commit_lsn</literal></entry>
+ <entry><type>pg_lsn</type></entry>
+ <entry>The final LSN of the remote transaction.</entry>
+ </row>
+ <row>
+ <entry><literal>remote_commit_ts</literal></entry>
+ <entry><type>timestamptz</type></entry>
+ <entry>The remote commit timestamp of the remote transaction.</entry>
+ </row>
+ <row>
+ <entry><literal>remote_origin</literal></entry>
+ <entry><type>text</type></entry>
+ <entry>The origin of the remote transaction.</entry>
+ </row>
+ <row>
+ <entry><literal>replica_identity</literal></entry>
+ <entry><type>json</type></entry>
+ <entry>The JSON representation of the replica identity.</entry>
+ </row>
+ <row>
+ <entry><literal>remote_tuple</literal></entry>
+ <entry><type>json</type></entry>
+ <entry>The JSON representation of the incoming remote row that caused the conflict.</entry>
+ </row>
+ <row>
+ <entry><literal>local_conflicts</literal></entry>
+ <entry><type>json[]</type></entry>
+ <entry>
+ An array of JSON objects representing the local state for each conflict attempt.
+ Each object includes the local transaction ID (<literal>xid</literal>), commit
+ timestamp (<literal>commit_ts</literal>), origin (<literal>origin</literal>),
+ conflicting key data (<literal>key</literal>), and the full local row
+ image (<literal>tuple</literal>).
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
- <para>
- The conflicting row data, including the incoming remote row (<literal>remote_tuple</literal>)
- and the associated local conflict details (<literal>local_conflicts</literal>), is stored in
- <type>JSON</type> formats, for flexible querying and analysis.
- </para>
+ <para>
+ The conflicting row data, including the incoming remote row (<literal>remote_tuple</literal>)
+ and the associated local conflict details (<literal>local_conflicts</literal>), is stored in
+ <type>JSON</type> formats for flexible querying and analysis.
+ </para>
+ </sect2>
- <para>
- If <link linkend="sql-createsubscription-params-with-conflict-log-destination"><literal>conflict_log_destination</literal></link>
- is set to log conflicts to the server log, the following format is used:
+ <sect2 id="logical-replication-conflict-file-based-logging">
+ <title>File-based logging</title>
+ <para>
+ If <link linkend="sql-createsubscription-params-with-conflict-log-destination"><literal>conflict_log_destination</literal></link>
+ is set to <literal>log</literal> or <literal>all</literal> then conflicts
+ are logged to the server using the following format:
<synopsis>
LOG: conflict detected on relation "<replaceable>schemaname</replaceable>.<replaceable>tablename</replaceable>": conflict=<replaceable>conflict_type</replaceable>
DETAIL: <replaceable class="parameter">detailed_explanation</replaceable>[: <replaceable class="parameter">detail_values</replaceable> [, ... ]].
@@ -2240,182 +2252,185 @@ DETAIL: <replaceable class="parameter">detailed_explanation</replaceable>[: <re
<literal>replica identity</literal> {(<replaceable>column_name</replaceable> <optional>, ...</optional>)=(<replaceable>column_value</replaceable> <optional>, ...</optional>) | full <optional>(<replaceable>column_name</replaceable> <optional>, ...</optional>)=</optional>(<replaceable>column_value</replaceable> <optional>, ...</optional>)}
</synopsis>
- The log provides the following information:
- <variablelist>
- <varlistentry>
- <term><literal>LOG</literal></term>
- <listitem>
+ The log provides the following information:
+ <variablelist>
+ <varlistentry>
+ <term><literal>LOG</literal></term>
+ <listitem>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <replaceable>schemaname</replaceable>.<replaceable>tablename</replaceable>
+ identifies the local relation involved in the conflict.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <replaceable>conflict_type</replaceable> is the type of conflict that occurred
+ (e.g., <literal>insert_exists</literal>, <literal>update_exists</literal>).
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>DETAIL</literal></term>
+ <listitem>
<itemizedlist>
<listitem>
<para>
- <replaceable>schemaname</replaceable>.<replaceable>tablename</replaceable>
- identifies the local relation involved in the conflict.
+ <replaceable class="parameter">detailed_explanation</replaceable> includes
+ the origin, transaction ID, and commit timestamp of the transaction that
+ modified the local row, if available.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>key</literal> section includes the key values of the local
+ row that violated a unique constraint for
+ <literal>insert_exists</literal>, <literal>update_exists</literal> or
+ <literal>multiple_unique_conflicts</literal> conflicts.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>local row</literal> section includes the local row if its
+ origin differs from the remote row for
+ <literal>update_origin_differs</literal> or <literal>delete_origin_differs</literal>
+ conflicts, or if the key value conflicts with the remote row for
+ <literal>insert_exists</literal>, <literal>update_exists</literal> or
+ <literal>multiple_unique_conflicts</literal> conflicts.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>remote row</literal> section includes the new row from
+ the remote insert or update operation that caused the conflict. Note that
+ for an update operation, the column value of the new row will be null
+ if the value is unchanged and toasted.
</para>
</listitem>
<listitem>
<para>
- <replaceable>conflict_type</replaceable> is the type of conflict that occurred
- (e.g., <literal>insert_exists</literal>, <literal>update_exists</literal>).
+ The <literal>replica identity</literal> section includes the replica
+ identity key values that were used to search for the existing local
+ row to be updated or deleted. This may include the full row value
+ if the local relation is marked with
+ <link linkend="sql-altertable-replica-identity-full"><literal>REPLICA IDENTITY FULL</literal></link>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <replaceable class="parameter">column_name</replaceable> is the column name.
+ For <literal>local row</literal>, <literal>remote row</literal>, and
+ <literal>replica identity full</literal> cases, column names are
+ logged only if the user lacks the privilege to access all columns of
+ the table. If column names are present, they appear in the same order
+ as the corresponding column values.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <replaceable class="parameter">column_value</replaceable> is the column value.
+ The large column values are truncated to 64 bytes.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Note that in case of <literal>multiple_unique_conflicts</literal> conflict,
+ multiple <replaceable class="parameter">detailed_explanation</replaceable>
+ and <replaceable class="parameter">detail_values</replaceable> lines
+ will be generated, each detailing the conflict information associated
+ with distinct unique constraints.
</para>
</listitem>
</itemizedlist>
</listitem>
- </varlistentry>
-
- <varlistentry>
- <term><literal>DETAIL</literal></term>
- <listitem>
- <itemizedlist>
- <listitem>
- <para>
- <replaceable class="parameter">detailed_explanation</replaceable> includes
- the origin, transaction ID, and commit timestamp of the transaction that
- modified the local row, if available.
- </para>
- </listitem>
- <listitem>
- <para>
- The <literal>key</literal> section includes the key values of the local
- row that violated a unique constraint for
- <literal>insert_exists</literal>, <literal>update_exists</literal> or
- <literal>multiple_unique_conflicts</literal> conflicts.
- </para>
- </listitem>
- <listitem>
- <para>
- The <literal>local row</literal> section includes the local row if its
- origin differs from the remote row for
- <literal>update_origin_differs</literal> or <literal>delete_origin_differs</literal>
- conflicts, or if the key value conflicts with the remote row for
- <literal>insert_exists</literal>, <literal>update_exists</literal> or
- <literal>multiple_unique_conflicts</literal> conflicts.
- </para>
- </listitem>
- <listitem>
- <para>
- The <literal>remote row</literal> section includes the new row from
- the remote insert or update operation that caused the conflict. Note that
- for an update operation, the column value of the new row will be null
- if the value is unchanged and toasted.
- </para>
- </listitem>
- <listitem>
- <para>
- The <literal>replica identity</literal> section includes the replica
- identity key values that were used to search for the existing local
- row to be updated or deleted. This may include the full row value
- if the local relation is marked with
- <link linkend="sql-altertable-replica-identity-full"><literal>REPLICA IDENTITY FULL</literal></link>.
- </para>
- </listitem>
- <listitem>
- <para>
- <replaceable class="parameter">column_name</replaceable> is the column name.
- For <literal>local row</literal>, <literal>remote row</literal>, and
- <literal>replica identity full</literal> cases, column names are
- logged only if the user lacks the privilege to access all columns of
- the table. If column names are present, they appear in the same order
- as the corresponding column values.
- </para>
- </listitem>
- <listitem>
- <para>
- <replaceable class="parameter">column_value</replaceable> is the column value.
- The large column values are truncated to 64 bytes.
- </para>
- </listitem>
- <listitem>
- <para>
- Note that in case of <literal>multiple_unique_conflicts</literal> conflict,
- multiple <replaceable class="parameter">detailed_explanation</replaceable>
- and <replaceable class="parameter">detail_values</replaceable> lines
- will be generated, each detailing the conflict information associated
- with distinct unique
- constraints.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </varlistentry>
- </variablelist>
- </para>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </sect2>
- <para>
- Logical replication operations are performed with the privileges of the role
- which owns the subscription. Permissions failures on target tables will
- cause replication conflicts, as will enabled
- <link linkend="ddl-rowsecurity">row-level security</link> on target tables
- that the subscription owner is subject to, without regard to whether any
- policy would ordinarily reject the <command>INSERT</command>,
- <command>UPDATE</command>, <command>DELETE</command> or
- <command>TRUNCATE</command> which is being replicated. This restriction on
- row-level security may be lifted in a future version of
- <productname>PostgreSQL</productname>.
- </para>
+ <sect2 id="logical-replication-conflict-notes">
+ <title>Notes</title>
+ <para>
+ Logical replication operations are performed with the privileges of the role
+ which owns the subscription. Permissions failures on target tables will
+ cause replication conflicts, as will enabled
+ <link linkend="ddl-rowsecurity">row-level security</link> on target tables
+ that the subscription owner is subject to, without regard to whether any
+ policy would ordinarily reject the <command>INSERT</command>,
+ <command>UPDATE</command>, <command>DELETE</command> or
+ <command>TRUNCATE</command> which is being replicated. This restriction on
+ row-level security may be lifted in a future version of
+ <productname>PostgreSQL</productname>.
+ </para>
- <para>
- A conflict that produces an error will stop the replication; it must be
- resolved manually by the user. Details about the conflict can be found in
- the subscriber's server log.
- </para>
+ <para>
+ A conflict that produces an error will stop the replication; it must be
+ resolved manually by the user. Details about the conflict can be found in
+ the subscriber's server log.
+ </para>
- <para>
- The resolution can be done either by changing data or permissions on the subscriber so
- that it does not conflict with the incoming change or by skipping the
- transaction that conflicts with the existing data. When a conflict produces
- an error, the replication won't proceed, and the logical replication worker will
- emit the following kind of message to the subscriber's server log:
+ <para>
+ The resolution can be done either by changing data or permissions on the subscriber so
+ that it does not conflict with the incoming change or by skipping the
+ transaction that conflicts with the existing data. When a conflict produces
+ an error, the replication won't proceed, and the logical replication worker will
+ emit the following kind of message to the subscriber's server log:
<screen>
ERROR: conflict detected on relation "public.test": conflict=insert_exists
DETAIL: Could not apply remote change: remote row (1, 'remote').
Key already exists in unique index "test_pkey", modified locally in transaction 800 at 2026-01-16 18:15:25.652759+09: key (c)=(1), local row (1, 'local').
CONTEXT: processing remote data for replication origin "pg_16395" during "INSERT" for replication target relation "public.test" in transaction 725 finished at 0/014C0378
</screen>
- The LSN of the transaction that contains the change violating the constraint and
- the replication origin name can be found from the server log (LSN 0/014C0378 and
- replication origin <literal>pg_16395</literal> in the above case). The
- transaction that produced the conflict can be skipped by using
- <link linkend="sql-altersubscription-params-skip"><command>ALTER SUBSCRIPTION ... SKIP</command></link>
- with the finish LSN
- (i.e., LSN 0/014C0378). The finish LSN could be an LSN at which the transaction
- is committed or prepared on the publisher. Alternatively, the transaction can
- also be skipped by calling the <link linkend="pg-replication-origin-advance">
- <function>pg_replication_origin_advance()</function></link> function.
- Before using this function, the subscription needs to be disabled temporarily
- either by <link linkend="sql-altersubscription-params-disable">
- <command>ALTER SUBSCRIPTION ... DISABLE</command></link> or, the
- subscription can be used with the
- <link linkend="sql-createsubscription-params-with-disable-on-error"><literal>disable_on_error</literal></link>
- option. Then, you can use <function>pg_replication_origin_advance()</function>
- function with the <parameter>node_name</parameter> (i.e., <literal>pg_16395</literal>)
- and the next LSN of the finish LSN (i.e., 0/014C0379). The current position of
- origins can be seen in the <link linkend="view-pg-replication-origin-status">
- <structname>pg_replication_origin_status</structname></link> system view.
- Please note that skipping the whole transaction includes skipping changes that
- might not violate any constraint. This can easily make the subscriber
- inconsistent.
- The additional details regarding conflicting rows, such as their origin and
- commit timestamp can be seen in the <literal>DETAIL</literal> line of the
- log. But note that this information is only available when
- <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
- is enabled on the subscriber. Users can use this information to decide
- whether to retain the local change or adopt the remote alteration. For
- instance, the <literal>DETAIL</literal> line in the above log indicates that
- the existing row was modified locally. Users can manually perform a
- remote-change-win.
- </para>
-
- <para>
- When the
- <link linkend="sql-createsubscription-params-with-streaming"><literal>streaming</literal></link>
- mode is <literal>parallel</literal>, the finish LSN of failed transactions
- may not be logged. In that case, it may be necessary to change the streaming
- mode to <literal>on</literal> or <literal>off</literal> and cause the same
- conflicts again so the finish LSN of the failed transaction will be written
- to the server log. For the usage of finish LSN, please refer to <link
- linkend="sql-altersubscription"><command>ALTER SUBSCRIPTION ...
- SKIP</command></link>.
- </para>
+ The LSN of the transaction that contains the change violating the constraint and
+ the replication origin name can be found from the server log (LSN 0/014C0378 and
+ replication origin <literal>pg_16395</literal> in the above case). The
+ transaction that produced the conflict can be skipped by using
+ <link linkend="sql-altersubscription-params-skip"><command>ALTER SUBSCRIPTION ... SKIP</command></link>
+ with the finish LSN
+ (i.e., LSN 0/014C0378). The finish LSN could be an LSN at which the transaction
+ is committed or prepared on the publisher. Alternatively, the transaction can
+ also be skipped by calling the <link linkend="pg-replication-origin-advance">
+ <function>pg_replication_origin_advance()</function></link> function.
+ Before using this function, the subscription needs to be disabled temporarily
+ either by <link linkend="sql-altersubscription-params-disable">
+ <command>ALTER SUBSCRIPTION ... DISABLE</command></link> or, the
+ subscription can be used with the
+ <link linkend="sql-createsubscription-params-with-disable-on-error"><literal>disable_on_error</literal></link>
+ option. Then, you can use <function>pg_replication_origin_advance()</function>
+ function with the <parameter>node_name</parameter> (i.e., <literal>pg_16395</literal>)
+ and the next LSN of the finish LSN (i.e., 0/014C0379). The current position of
+ origins can be seen in the <link linkend="view-pg-replication-origin-status">
+ <structname>pg_replication_origin_status</structname></link> system view.
+ Please note that skipping the whole transaction includes skipping changes that
+ might not violate any constraint. This can easily make the subscriber
+ inconsistent.
+ The additional details regarding conflicting rows, such as their origin and
+ commit timestamp can be seen in the <literal>DETAIL</literal> line of the
+ log. But note that this information is only available when
+ <link linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
+ is enabled on the subscriber. Users can use this information to decide
+ whether to retain the local change or adopt the remote alteration. For
+ instance, the <literal>DETAIL</literal> line in the above log indicates that
+ the existing row was modified locally. Users can manually perform a
+ remote-change-win.
+ </para>
+
+ <para>
+ When the
+ <link linkend="sql-createsubscription-params-with-streaming"><literal>streaming</literal></link>
+ mode is <literal>parallel</literal>, the finish LSN of failed transactions
+ may not be logged. In that case, it may be necessary to change the streaming
+ mode to <literal>on</literal> or <literal>off</literal> and cause the same
+ conflicts again so the finish LSN of the failed transaction will be written
+ to the server log. For the usage of finish LSN, please refer to <link
+ linkend="sql-altersubscription"><command>ALTER SUBSCRIPTION ...
+ SKIP</command></link>.
+ </para>
+ </sect2>
</sect1>
<sect1 id="logical-replication-restrictions">
@@ -2524,7 +2539,8 @@ CONTEXT: processing remote data for replication origin "pg_16395" during "INSER
<listitem>
<para>
Conflict log tables (see <link linkend="sql-createsubscription-params-with-conflict-log-destination"><literal>conflict_log_destination</literal></link> parameter)
- are never published, even when using FOR ALL TABLES in a publication.
+ are never published, even when using <literal>FOR ALL TABLES</literal> in a
+ publication.
</para>
</listitem>
</itemizedlist>
diff --git a/doc/src/sgml/ref/create_subscription.sgml b/doc/src/sgml/ref/create_subscription.sgml
index 7fb11f31b21..693b2f4e1c3 100644
--- a/doc/src/sgml/ref/create_subscription.sgml
+++ b/doc/src/sgml/ref/create_subscription.sgml
@@ -273,15 +273,19 @@ CREATE SUBSCRIPTION <replaceable class="parameter">subscription_name</replaceabl
<listitem>
<para>
<literal>log</literal>: Conflict details are recorded in the server log.
- This is the default behavior.
+ This is the default behavior. See
+ <xref linkend="logical-replication-conflict-file-based-logging"/>
+ for details.
</para>
</listitem>
<listitem>
<para>
<literal>table</literal>: The system automatically creates a structured table
- named <literal>pg_conflict_log_<subid></literal> in the
- <literal>pg_conflict</literal> schema. This allows for easy querying and
- analysis of conflicts.
+ named <literal>pg_conflict_log_for_subid_<subid></literal>
+ in the <literal>pg_conflict</literal> schema. This allows for easy
+ querying and analysis of conflicts. See
+ <xref linkend="logical-replication-conflict-table-based-logging"/>
+ for details.
</para>
<caution>
<para>
@@ -292,8 +296,8 @@ CREATE SUBSCRIPTION <replaceable class="parameter">subscription_name</replaceabl
<emphasis>permanently deleted</emphasis>.
</para>
<para>
- If post-mortem analysis may be needed, back up the conflict log table before
- removing the subscription.
+ If conflict history may be needed later, back up the conflict log
+ table before it gets removed.
</para>
</caution>
</listitem>
--
2.53.0