From 8433e52ba2952f776ed85919b5956168d094470c Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.b.smith@fujitsu.com>
Date: Wed, 2 Dec 2020 20:41:20 +1100
Subject: [PATCH v29] Support-2PC-documentation.

Add documentation about two-phase commit support in Logical Decoding.
---
 doc/src/sgml/logicaldecoding.sgml | 97 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 96 insertions(+), 1 deletion(-)

diff --git a/doc/src/sgml/logicaldecoding.sgml b/doc/src/sgml/logicaldecoding.sgml
index 73673a0..fcc43fd 100644
--- a/doc/src/sgml/logicaldecoding.sgml
+++ b/doc/src/sgml/logicaldecoding.sgml
@@ -165,7 +165,57 @@ COMMIT 693
 <keycombo action="simul"><keycap>Control</keycap><keycap>C</keycap></keycombo>
 $ pg_recvlogical -d postgres --slot=test --drop-slot
 </programlisting>
-  </sect1>
+
+  <para>
+  The following example shows how logical decoding can be used to handle transactions
+  that use a two-phase commit. Before you use two-phase commit commands, you must set
+  <varname>max_prepared_transactions</varname> to at least 1. You must also set the 
+  option 'two-phase-commit' to 1 while calling <function>pg_logical_slot_get_changes</function>.
+  </para>
+<programlisting>
+postgres=# BEGIN;
+postgres=*# INSERT INTO data(data) VALUES('5');
+postgres=*# PREPARE TRANSACTION 'test_prepared1';
+
+postgres=# SELECT * FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1');
+    lsn    | xid |                          data                           
+-----------+-----+---------------------------------------------------------
+ 0/1689DC0 | 529 | BEGIN 529
+ 0/1689DC0 | 529 | table public.data: INSERT: id[integer]:3 data[text]:'5'
+ 0/1689FC0 | 529 | PREPARE TRANSACTION 'test_prepared1', txid 529
+(3 rows)
+
+postgres=# COMMIT PREPARED 'test_prepared1';
+COMMIT PREPARED
+postgres=# select * from pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1');
+    lsn    | xid |                    data                    
+-----------+-----+--------------------------------------------
+ 0/168A060 | 529 | COMMIT PREPARED 'test_prepared1', txid 529
+(1 row)
+
+postgres=#-- you can also rollback a prepared transaction
+postgres=# BEGIN;
+BEGIN
+postgres=*# INSERT INTO data(data) VALUES('6');INSERT 0 1
+postgres=*# PREPARE TRANSACTION 'test_prepared2';PREPARE TRANSACTION
+postgres=# select * from pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1');
+    lsn    | xid |                          data                           
+-----------+-----+---------------------------------------------------------
+ 0/168A180 | 530 | BEGIN 530
+ 0/168A1E8 | 530 | table public.data: INSERT: id[integer]:4 data[text]:'6'
+ 0/168A430 | 530 | PREPARE TRANSACTION 'test_prepared2', txid 530
+(3 rows)
+
+postgres=# ROLLBACK PREPARED 'test_prepared1';ERROR:  prepared transaction with identifier "test_prepared1" does not exist
+postgres=# ROLLBACK PREPARED 'test_prepared2';
+ROLLBACK PREPARED
+postgres=# select * from pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'two-phase-commit', '1');
+    lsn    | xid |                     data                     
+-----------+-----+----------------------------------------------
+ 0/168A4B8 | 530 | ROLLBACK PREPARED 'test_prepared2', txid 530
+(1 row)
+</programlisting>
+</sect1>
 
   <sect1 id="logicaldecoding-explanation">
    <title>Logical Decoding Concepts</title>
@@ -1103,4 +1153,49 @@ stream_commit_cb(...);  &lt;-- commit of the streamed transaction
    </para>
 
   </sect1>
+
+  <sect1 id="logicaldecoding-two-phase-commits">
+   <title>Two-phase commit support for Logical Decoding</title>
+
+   <para>
+   With the basic output plugin callbacks (eg., <function>begin_cb</function>,
+   <function>change_cb</function>, <function>commit_cb</function> and
+   <function>message_cb</function>) two-phase commit commands like
+   <command>PREPARE TRANSACTION</command>, <command>COMMIT PREPARED</command>
+   and <command>ROLLBACK PREPARED</command> are not decoded correctly.
+   While the <command>PREPARE TRANSACTION</command> ignored, 
+   <command>COMMIT PREPARED</command> is decoded as a <command>COMMIT</command> and 
+   <command>ROLLBACK PREPARED</command> is decoded as a <command>ROLLBACK</command>.
+   </para>
+
+   <para>
+   An output plugin may provide additional callbacks to support two-phase commit commands.
+   There are multiple two-phase commit callbacks that are required,
+   (<function>prepare_cb</function>, <function>commit_prepared_cb</function>, 
+   <function>rollback_prepared_cb</function> and <function>stream_prepare_cb</function>)
+   and an optional callback (<function>filter_prepare_cb</function>).
+   </para>
+
+   <para>
+   If the output plugin callbacks for decoding two-phase commit commands are provided,
+   then on <command>PREPARE TRANSACTION</command>, the changes of that transaction are
+   decoded, passed to the output plugin and the <function>prepare_cb</function>
+   callback is invoked. This differs from the basic decoding setup where changes are
+   only passed to the output plugin when a transaction is committed.
+   </para>
+
+   <para>
+   When a prepared transaction is rollbacked using the <command>ROLLBACK PREPARED</command>,
+   then the <function>rollback_prepared_cb</function> is invoked and when the
+   prepared transaction is committed using <command>COMMIT PREPARED</command>,
+   then the <function>commit_prepared_cb</function> callback is invoked.
+   </para>
+
+   <para>
+   Optionally the output plugin can specify a name pattern in the 
+   <function>filter_prepare_cb</function> and transactions with gid containing
+   that name pattern will not be decoded as a two-phase commit transaction. 
+   </para>
+
+  </sect1>
  </chapter>
-- 
1.8.3.1

