Introduce logical decoding.
authorRobert Haas
Mon, 3 Mar 2014 21:32:18 +0000 (16:32 -0500)
committerRobert Haas
Mon, 3 Mar 2014 21:32:18 +0000 (16:32 -0500)
This feature, building on previous commits, allows the write-ahead log
stream to be decoded into a series of logical changes; that is,
inserts, updates, and deletes and the transactions which contain them.
It is capable of handling decoding even across changes to the schema
of the effected tables.  The output format is controlled by a
so-called "output plugin"; an example is included.  To make use of
this in a real replication system, the output plugin will need to be
modified to produce output in the format appropriate to that system,
and to perform filtering.

Currently, information can be extracted from the logical decoding
system only via SQL; future commits will add the ability to stream
changes via walsender.

Andres Freund, with review and other contributions from many other
people, including Álvaro Herrera, Abhijit Menon-Sen, Peter Gheogegan,
Kevin Grittner, Robert Haas, Heikki Linnakangas, Fujii Masao, Abhijit
Menon-Sen, Michael Paquier, Simon Riggs, Craig Ringer, and Steve
Singer.

89 files changed:
contrib/Makefile
contrib/test_decoding/.gitignore [new file with mode: 0644]
contrib/test_decoding/Makefile [new file with mode: 0644]
contrib/test_decoding/expected/binary.out [new file with mode: 0644]
contrib/test_decoding/expected/concurrent_ddl_dml.out [new file with mode: 0644]
contrib/test_decoding/expected/ddl.out [new file with mode: 0644]
contrib/test_decoding/expected/decoding_in_xact.out [new file with mode: 0644]
contrib/test_decoding/expected/delayed_startup.out [new file with mode: 0644]
contrib/test_decoding/expected/mxact.out [new file with mode: 0644]
contrib/test_decoding/expected/permissions.out [new file with mode: 0644]
contrib/test_decoding/expected/rewrite.out [new file with mode: 0644]
contrib/test_decoding/expected/toast.out [new file with mode: 0644]
contrib/test_decoding/logical.conf [new file with mode: 0644]
contrib/test_decoding/specs/concurrent_ddl_dml.spec [new file with mode: 0644]
contrib/test_decoding/specs/delayed_startup.spec [new file with mode: 0644]
contrib/test_decoding/specs/mxact.spec [new file with mode: 0644]
contrib/test_decoding/sql/binary.sql [new file with mode: 0644]
contrib/test_decoding/sql/ddl.sql [new file with mode: 0644]
contrib/test_decoding/sql/decoding_in_xact.sql [new file with mode: 0644]
contrib/test_decoding/sql/permissions.sql [new file with mode: 0644]
contrib/test_decoding/sql/rewrite.sql [new file with mode: 0644]
contrib/test_decoding/sql/toast.sql [new file with mode: 0644]
contrib/test_decoding/test_decoding.c [new file with mode: 0644]
doc/src/sgml/contrib.sgml
doc/src/sgml/filelist.sgml
doc/src/sgml/test-decoding.sgml [new file with mode: 0644]
src/Makefile.global.in
src/backend/access/heap/heapam.c
src/backend/access/heap/pruneheap.c
src/backend/access/heap/rewriteheap.c
src/backend/access/heap/tuptoaster.c
src/backend/access/index/indexam.c
src/backend/access/rmgrdesc/heapdesc.c
src/backend/access/transam/xact.c
src/backend/access/transam/xlog.c
src/backend/catalog/index.c
src/backend/catalog/system_views.sql
src/backend/commands/analyze.c
src/backend/commands/cluster.c
src/backend/commands/dbcommands.c
src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/backend/executor/nodeBitmapHeapscan.c
src/backend/replication/Makefile
src/backend/replication/logical/Makefile [new file with mode: 0644]
src/backend/replication/logical/decode.c [new file with mode: 0644]
src/backend/replication/logical/logical.c [new file with mode: 0644]
src/backend/replication/logical/logicalfuncs.c [new file with mode: 0644]
src/backend/replication/logical/reorderbuffer.c [new file with mode: 0644]
src/backend/replication/logical/snapbuild.c [new file with mode: 0644]
src/backend/replication/slot.c
src/backend/replication/slotfuncs.c
src/backend/replication/walreceiver.c
src/backend/replication/walsender.c
src/backend/storage/ipc/procarray.c
src/backend/storage/ipc/standby.c
src/backend/storage/lmgr/proc.c
src/backend/tcop/postgres.c
src/backend/utils/cache/inval.c
src/backend/utils/cache/relcache.c
src/backend/utils/time/snapmgr.c
src/backend/utils/time/tqual.c
src/bin/initdb/initdb.c
src/include/access/heapam.h
src/include/access/heapam_xlog.h
src/include/access/rewriteheap.h
src/include/access/transam.h
src/include/access/tuptoaster.h
src/include/access/xlog.h
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/commands/vacuum.h
src/include/replication/decode.h [new file with mode: 0644]
src/include/replication/logical.h [new file with mode: 0644]
src/include/replication/logicalfuncs.h [new file with mode: 0644]
src/include/replication/output_plugin.h [new file with mode: 0644]
src/include/replication/reorderbuffer.h [new file with mode: 0644]
src/include/replication/slot.h
src/include/replication/snapbuild.h [new file with mode: 0644]
src/include/storage/itemptr.h
src/include/storage/proc.h
src/include/storage/procarray.h
src/include/storage/sinval.h
src/include/utils/inval.h
src/include/utils/snapmgr.h
src/include/utils/snapshot.h
src/include/utils/tqual.h
src/test/regress/expected/rules.out
src/tools/pgindent/typedefs.list

index c90fe29222a3d6f973f074daaf0b8066d8a68b54..8dc40f7de0033d372995390a7706ca22cf778fdc 100644 (file)
@@ -50,6 +50,7 @@ SUBDIRS = \
        spi     \
        tablefunc   \
        tcn     \
+       test_decoding   \
        test_parser \
        test_shm_mq \
        tsearch2    \
diff --git a/contrib/test_decoding/.gitignore b/contrib/test_decoding/.gitignore
new file mode 100644 (file)
index 0000000..5dcb3ff
--- /dev/null
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
diff --git a/contrib/test_decoding/Makefile b/contrib/test_decoding/Makefile
new file mode 100644 (file)
index 0000000..c193f73
--- /dev/null
@@ -0,0 +1,69 @@
+# contrib/test_decoding/Makefile
+
+MODULES = test_decoding
+OBJS = test_decoding.o
+
+# Note: because we don't tell the Makefile there are any regression tests,
+# we have to clean those result files explicitly
+EXTRA_CLEAN = -r $(pg_regress_clean_files)
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/test_decoding
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
+
+# Disabled because these tests require "wal_level=logical", which
+# typical installcheck users do not have (e.g. buildfarm clients).
+installcheck:;
+
+# But it can nonetheless be very helpful to run tests on preexisting
+# installation, allow to do so, but only if requested explicitly.
+installcheck-force: regresscheck-install-force isolationcheck-install-force
+
+check: regresscheck isolationcheck
+
+submake-regress:
+   $(MAKE) -C $(top_builddir)/src/test/regress all
+
+submake-isolation:
+   $(MAKE) -C $(top_builddir)/src/test/isolation all
+
+submake-test_decoding:
+   $(MAKE) -C $(top_builddir)/contrib/test_decoding
+
+REGRESSCHECKS=ddl rewrite toast permissions decoding_in_xact binary
+
+regresscheck: all | submake-regress submake-test_decoding
+   $(pg_regress_check) \
+       --temp-config $(top_srcdir)/contrib/test_decoding/logical.conf \
+       --temp-install=./tmp_check \
+       --extra-install=contrib/test_decoding \
+       $(REGRESSCHECKS)
+
+regresscheck-install-force: | submake-regress submake-test_decoding
+   $(pg_regress_installcheck) \
+       --extra-install=contrib/test_decoding \
+       $(REGRESSCHECKS)
+
+ISOLATIONCHECKS=mxact delayed_startup concurrent_ddl_dml
+
+isolationcheck: all | submake-isolation submake-test_decoding
+   $(pg_isolation_regress_check) \
+       --temp-config $(top_srcdir)/contrib/test_decoding/logical.conf \
+       --extra-install=contrib/test_decoding \
+       $(ISOLATIONCHECKS)
+
+isolationcheck-install-force: all | submake-isolation submake-test_decoding
+   $(pg_isolation_regress_installcheck) \
+       --extra-install=contrib/test_decoding \
+       $(ISOLATIONCHECKS)
+
+PHONY: submake-test_decoding submake-regress check \
+   regresscheck regresscheck-install-force \
+   isolationcheck isolationcheck-install-force
diff --git a/contrib/test_decoding/expected/binary.out b/contrib/test_decoding/expected/binary.out
new file mode 100644 (file)
index 0000000..3409d9d
--- /dev/null
@@ -0,0 +1,35 @@
+-- predictability
+SET synchronous_commit = on;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ ?column? 
+----------
+ init
+(1 row)
+
+-- succeeds, textual plugin, textual consumer
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '0');
+ data 
+------
+(0 rows)
+
+-- fails, binary plugin, textual consumer
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '1');
+ERROR:  output plugin cannot produce text output
+-- succeeds, textual plugin, binary consumer
+SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '0');
+ data 
+------
+(0 rows)
+
+-- succeeds, binary plugin, binary consumer
+SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '1');
+ data 
+------
+(0 rows)
+
+SELECT 'init' FROM pg_drop_replication_slot('regression_slot');
+ ?column? 
+----------
+ init
+(1 row)
+
diff --git a/contrib/test_decoding/expected/concurrent_ddl_dml.out b/contrib/test_decoding/expected/concurrent_ddl_dml.out
new file mode 100644 (file)
index 0000000..cc91656
--- /dev/null
@@ -0,0 +1,733 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s2_alter_tbl2_float s1_insert_tbl2 s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_float: ALTER TABLE tbl2 ALTER COLUMN val2 TYPE float;
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s1_commit: COMMIT;
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[double precision]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s2_alter_tbl1_float s1_insert_tbl2 s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl1_float: ALTER TABLE tbl1 ALTER COLUMN val2 TYPE float; 
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s1_commit: COMMIT;
+step s2_alter_tbl1_float: <... completed>
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+BEGIN          
+table public.pg_temp: INSERT: val1[integer]:1 val2[double precision]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s2_alter_tbl2_char s1_insert_tbl2 s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_char: ALTER TABLE tbl2 ALTER COLUMN val2 TYPE character varying;
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s1_commit: COMMIT;
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[character varying]:'1'
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s2_alter_tbl1_char s1_insert_tbl2 s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl1_char: ALTER TABLE tbl1 ALTER COLUMN val2 TYPE character varying; 
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s1_commit: COMMIT;
+step s2_alter_tbl1_char: <... completed>
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+BEGIN          
+table public.pg_temp: INSERT: val1[integer]:1 val2[character varying]:'1'
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s1_insert_tbl2 s2_alter_tbl1_float s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl1_float: ALTER TABLE tbl1 ALTER COLUMN val2 TYPE float; 
+step s1_commit: COMMIT;
+step s2_alter_tbl1_float: <... completed>
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+BEGIN          
+table public.pg_temp: INSERT: val1[integer]:1 val2[double precision]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s1_insert_tbl2 s2_alter_tbl1_char s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl1_char: ALTER TABLE tbl1 ALTER COLUMN val2 TYPE character varying; 
+step s1_commit: COMMIT;
+step s2_alter_tbl1_char: <... completed>
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+BEGIN          
+table public.pg_temp: INSERT: val1[integer]:1 val2[character varying]:'1'
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s2_alter_tbl2_float s1_insert_tbl2 s2_alter_tbl1_float s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_float: ALTER TABLE tbl2 ALTER COLUMN val2 TYPE float;
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl1_float: ALTER TABLE tbl1 ALTER COLUMN val2 TYPE float; 
+step s1_commit: COMMIT;
+step s2_alter_tbl1_float: <... completed>
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[double precision]:1
+COMMIT         
+BEGIN          
+table public.pg_temp: INSERT: val1[integer]:1 val2[double precision]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s2_alter_tbl2_char s1_insert_tbl2 s2_alter_tbl1_char s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_char: ALTER TABLE tbl2 ALTER COLUMN val2 TYPE character varying;
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl1_char: ALTER TABLE tbl1 ALTER COLUMN val2 TYPE character varying; 
+step s1_commit: COMMIT;
+step s2_alter_tbl1_char: <... completed>
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[character varying]:'1'
+COMMIT         
+BEGIN          
+table public.pg_temp: INSERT: val1[integer]:1 val2[character varying]:'1'
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s2_alter_tbl2_char s1_begin s1_insert_tbl1 s2_alter_tbl2_text s1_insert_tbl2 s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s2_alter_tbl2_char: ALTER TABLE tbl2 ALTER COLUMN val2 TYPE character varying;
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_text: ALTER TABLE tbl2 ALTER COLUMN val2 TYPE text;
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s1_commit: COMMIT;
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[text]:'1'
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s2_alter_tbl2_char s1_begin s1_insert_tbl1 s2_alter_tbl2_text s1_insert_tbl2 s2_alter_tbl1_char s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s2_alter_tbl2_char: ALTER TABLE tbl2 ALTER COLUMN val2 TYPE character varying;
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_text: ALTER TABLE tbl2 ALTER COLUMN val2 TYPE text;
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl1_char: ALTER TABLE tbl1 ALTER COLUMN val2 TYPE character varying; 
+step s1_commit: COMMIT;
+step s2_alter_tbl1_char: <... completed>
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[text]:'1'
+COMMIT         
+BEGIN          
+table public.pg_temp: INSERT: val1[integer]:1 val2[character varying]:'1'
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s2_alter_tbl2_boolean s1_insert_tbl2 s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_boolean: ALTER TABLE tbl2 ALTER COLUMN val2 TYPE boolean;
+ERROR:  column "val2" cannot be cast automatically to type boolean
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s1_commit: COMMIT;
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s2_alter_tbl2_boolean s1_insert_tbl2 s2_alter_tbl1_boolean s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_boolean: ALTER TABLE tbl2 ALTER COLUMN val2 TYPE boolean;
+ERROR:  column "val2" cannot be cast automatically to type boolean
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl1_boolean: ALTER TABLE tbl1 ALTER COLUMN val2 TYPE boolean; 
+step s1_commit: COMMIT;
+step s2_alter_tbl1_boolean: <... completed>
+error in steps s1_commit s2_alter_tbl1_boolean: ERROR:  column "val2" cannot be cast automatically to type boolean
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s2_alter_tbl2_add_int s1_insert_tbl2_3col s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_add_int: ALTER TABLE tbl2 ADD COLUMN val3 INTEGER;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s1_commit: COMMIT;
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[integer]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s1_insert_tbl2 s1_commit s1_begin s2_alter_tbl2_add_int s1_insert_tbl2_3col s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s1_commit: COMMIT;
+step s1_begin: BEGIN;
+step s2_alter_tbl2_add_int: ALTER TABLE tbl2 ADD COLUMN val3 INTEGER;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s1_commit: COMMIT;
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[integer]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s2_alter_tbl2_add_float s1_insert_tbl2_3col s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_add_float: ALTER TABLE tbl2 ADD COLUMN val3 FLOAT;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s1_commit: COMMIT;
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[double precision]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s1_insert_tbl2 s1_commit s1_begin s2_alter_tbl2_add_float s1_insert_tbl2_3col s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s1_commit: COMMIT;
+step s1_begin: BEGIN;
+step s2_alter_tbl2_add_float: ALTER TABLE tbl2 ADD COLUMN val3 FLOAT;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s1_commit: COMMIT;
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[double precision]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s2_alter_tbl2_add_char s1_insert_tbl2_3col s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_add_char: ALTER TABLE tbl2 ADD COLUMN val3 character varying;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s1_commit: COMMIT;
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[character varying]:'1'
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s1_begin s1_insert_tbl1 s1_insert_tbl2 s1_commit s1_begin s2_alter_tbl2_add_char s1_insert_tbl2_3col s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s1_commit: COMMIT;
+step s1_begin: BEGIN;
+step s2_alter_tbl2_add_char: ALTER TABLE tbl2 ADD COLUMN val3 character varying;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s1_commit: COMMIT;
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[character varying]:'1'
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s2_alter_tbl2_add_int s1_begin s1_insert_tbl2_3col s2_alter_tbl2_drop_3rd_col s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s2_alter_tbl2_add_int: ALTER TABLE tbl2 ADD COLUMN val3 INTEGER;
+step s1_begin: BEGIN;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s2_alter_tbl2_drop_3rd_col: ALTER TABLE tbl2 DROP COLUMN val3; 
+step s1_commit: COMMIT;
+step s2_alter_tbl2_drop_3rd_col: <... completed>
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[integer]:1
+COMMIT         
+BEGIN          
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s2_alter_tbl2_add_int s1_begin s1_insert_tbl2_3col s2_alter_tbl2_drop_3rd_col s1_insert_tbl2 s1_commit s1_insert_tbl2 s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s2_alter_tbl2_add_int: ALTER TABLE tbl2 ADD COLUMN val3 INTEGER;
+step s1_begin: BEGIN;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s2_alter_tbl2_drop_3rd_col: ALTER TABLE tbl2 DROP COLUMN val3; 
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s1_commit: COMMIT;
+step s2_alter_tbl2_drop_3rd_col: <... completed>
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[integer]:null
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s2_alter_tbl2_add_int s1_begin s1_insert_tbl2_3col s2_alter_tbl2_drop_3rd_col s1_commit s2_get_changes s2_alter_tbl2_add_text s1_begin s1_insert_tbl2_3col s2_alter_tbl2_3rd_char s1_insert_tbl2_3col s1_commit s2_get_changes s2_alter_tbl2_3rd_int s1_insert_tbl2_3col s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s2_alter_tbl2_add_int: ALTER TABLE tbl2 ADD COLUMN val3 INTEGER;
+step s1_begin: BEGIN;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s2_alter_tbl2_drop_3rd_col: ALTER TABLE tbl2 DROP COLUMN val3; 
+step s1_commit: COMMIT;
+step s2_alter_tbl2_drop_3rd_col: <... completed>
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[integer]:1
+COMMIT         
+BEGIN          
+COMMIT         
+step s2_alter_tbl2_add_text: ALTER TABLE tbl2 ADD COLUMN val3 TEXT;
+step s1_begin: BEGIN;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s2_alter_tbl2_3rd_char: ALTER TABLE tbl2 ALTER COLUMN val3 TYPE character varying; 
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s1_commit: COMMIT;
+step s2_alter_tbl2_3rd_char: <... completed>
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[text]:'1'
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[text]:'1'
+COMMIT         
+BEGIN          
+COMMIT         
+step s2_alter_tbl2_3rd_int: ALTER TABLE tbl2 ALTER COLUMN val3 TYPE int USING val3::integer;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+table public.pg_temp: INSERT: val1[integer]:1 val2[integer]:1 val3[integer]:null
+table public.pg_temp: INSERT: val1[integer]:1 val2[integer]:1 val3[integer]:1
+table public.pg_temp: INSERT: val1[integer]:1 val2[integer]:1 val3[integer]:1
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[integer]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s2_alter_tbl2_add_char s1_begin s1_insert_tbl1 s1_insert_tbl2_3col s2_alter_tbl2_3rd_text s1_insert_tbl2_3col s1_commit s1_insert_tbl2_3col s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s2_alter_tbl2_add_char: ALTER TABLE tbl2 ADD COLUMN val3 character varying;
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s2_alter_tbl2_3rd_text: ALTER TABLE tbl2 ALTER COLUMN val3 TYPE text; 
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s1_commit: COMMIT;
+step s2_alter_tbl2_3rd_text: <... completed>
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[character varying]:'1'
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[character varying]:'1'
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[text]:'1'
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s2_alter_tbl2_add_text s1_begin s1_insert_tbl1 s1_insert_tbl2_3col s2_alter_tbl2_3rd_char s1_insert_tbl2_3col s1_commit s1_insert_tbl2_3col s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s2_alter_tbl2_add_text: ALTER TABLE tbl2 ADD COLUMN val3 TEXT;
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s2_alter_tbl2_3rd_char: ALTER TABLE tbl2 ALTER COLUMN val3 TYPE character varying; 
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s1_commit: COMMIT;
+step s2_alter_tbl2_3rd_char: <... completed>
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[text]:'1'
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[text]:'1'
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[character varying]:'1'
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s2_alter_tbl2_add_char s1_begin s1_insert_tbl1 s2_alter_tbl2_3rd_text s1_insert_tbl2_3col s1_commit s2_alter_tbl2_drop_3rd_col s1_insert_tbl2 s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s2_alter_tbl2_add_char: ALTER TABLE tbl2 ADD COLUMN val3 character varying;
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_3rd_text: ALTER TABLE tbl2 ALTER COLUMN val3 TYPE text;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s1_commit: COMMIT;
+step s2_alter_tbl2_drop_3rd_col: ALTER TABLE tbl2 DROP COLUMN val3;
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[text]:'1'
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s2_alter_tbl2_add_text s1_begin s1_insert_tbl1 s2_alter_tbl2_3rd_char s1_insert_tbl2_3col s1_commit s2_alter_tbl2_drop_3rd_col s1_insert_tbl2 s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s2_alter_tbl2_add_text: ALTER TABLE tbl2 ADD COLUMN val3 TEXT;
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_3rd_char: ALTER TABLE tbl2 ALTER COLUMN val3 TYPE character varying;
+step s1_insert_tbl2_3col: INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1);
+step s1_commit: COMMIT;
+step s2_alter_tbl2_drop_3rd_col: ALTER TABLE tbl2 DROP COLUMN val3;
+step s1_insert_tbl2: INSERT INTO tbl2 (val1, val2) VALUES (1, 1);
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1 val3[character varying]:'1'
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl2: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+?column?       
+
+stop           
+
+starting permutation: s1_init s2_alter_tbl2_add_char s1_begin s1_insert_tbl1 s2_alter_tbl2_drop_3rd_col s1_insert_tbl1 s1_commit s2_get_changes
+step s1_init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s2_alter_tbl2_add_char: ALTER TABLE tbl2 ADD COLUMN val3 character varying;
+step s1_begin: BEGIN;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s2_alter_tbl2_drop_3rd_col: ALTER TABLE tbl2 DROP COLUMN val3;
+step s1_insert_tbl1: INSERT INTO tbl1 (val1, val2) VALUES (1, 1);
+step s1_commit: COMMIT;
+step s2_get_changes: SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+COMMIT         
+BEGIN          
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+table public.tbl1: INSERT: val1[integer]:1 val2[integer]:1
+COMMIT         
+?column?       
+
+stop           
diff --git a/contrib/test_decoding/expected/ddl.out b/contrib/test_decoding/expected/ddl.out
new file mode 100644 (file)
index 0000000..986f504
--- /dev/null
@@ -0,0 +1,651 @@
+-- predictability
+SET synchronous_commit = on;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ ?column? 
+----------
+ init
+(1 row)
+
+-- fail because of an already existing slot
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ERROR:  replication slot "regression_slot" already exists
+-- fail because of an invalid name
+SELECT 'init' FROM pg_create_logical_replication_slot('Invalid Name', 'test_decoding');
+ERROR:  replication slot name "Invalid Name" contains invalid character
+HINT:  Replication slot names may only contain letters, numbers and the underscore character.
+-- fail twice because of an invalid parameter values
+SELECT 'init' FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', 'frakbar');
+ERROR:  could not parse value "frakbar" for parameter "include-xids"
+CONTEXT:  slot "regression_slot", output plugin "test_decoding", in the startup callback
+SELECT 'init' FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'nonexistant-option', 'frakbar');
+ERROR:  option "nonexistant-option" = "frakbar" is unknown
+CONTEXT:  slot "regression_slot", output plugin "test_decoding", in the startup callback
+SELECT 'init' FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', 'frakbar');
+ERROR:  could not parse value "frakbar" for parameter "include-xids"
+CONTEXT:  slot "regression_slot", output plugin "test_decoding", in the startup callback
+-- succeed once
+SELECT pg_drop_replication_slot('regression_slot');
+ pg_drop_replication_slot 
+--------------------------
+(1 row)
+
+-- fail
+SELECT pg_drop_replication_slot('regression_slot');
+ERROR:  replication slot "regression_slot" does not exist
+-- check that we're detecting a streaming rep slot used for logical decoding 
+SELECT 'init' FROM pg_create_physical_replication_slot('repl');
+ ?column? 
+----------
+ init
+(1 row)
+
+SELECT data FROM pg_logical_slot_get_changes('repl', NULL, NULL, 'include-xids', '0');
+ERROR:  cannot use physical replication slot for logical decoding
+SELECT pg_drop_replication_slot('repl');
+ pg_drop_replication_slot 
+--------------------------
+(1 row)
+
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ ?column? 
+----------
+ init
+(1 row)
+
+/* check whether status function reports us, only reproduceable columns */
+SELECT slot_name, plugin, slot_type, active,
+    NOT catalog_xmin IS NULL AS catalog_xmin_set,
+    xmin IS NULl  AS data_xmin_not_set,
+    pg_xlog_location_diff(restart_lsn, '0/01000000') > 0 AS some_wal
+FROM pg_replication_slots;
+    slot_name    |    plugin     | slot_type | active | catalog_xmin_set | data_xmin_not_set | some_wal 
+-----------------+---------------+-----------+--------+------------------+-------------------+----------
+ regression_slot | test_decoding | logical   | f      | t                | t                 | t
+(1 row)
+
+/*
+ * Check that changes are handled correctly when interleaved with ddl
+ */
+CREATE TABLE replication_example(id SERIAL PRIMARY KEY, somedata int, text varchar(120));
+BEGIN;
+INSERT INTO replication_example(somedata, text) VALUES (1, 1);
+INSERT INTO replication_example(somedata, text) VALUES (1, 2);
+COMMIT;
+ALTER TABLE replication_example ADD COLUMN bar int;
+INSERT INTO replication_example(somedata, text, bar) VALUES (2, 1, 4);
+BEGIN;
+INSERT INTO replication_example(somedata, text, bar) VALUES (2, 2, 4);
+INSERT INTO replication_example(somedata, text, bar) VALUES (2, 3, 4);
+INSERT INTO replication_example(somedata, text, bar) VALUES (2, 4, NULL);
+COMMIT;
+ALTER TABLE replication_example DROP COLUMN bar;
+INSERT INTO replication_example(somedata, text) VALUES (3, 1);
+BEGIN;
+INSERT INTO replication_example(somedata, text) VALUES (3, 2);
+INSERT INTO replication_example(somedata, text) VALUES (3, 3);
+COMMIT;
+ALTER TABLE replication_example RENAME COLUMN text TO somenum;
+INSERT INTO replication_example(somedata, somenum) VALUES (4, 1);
+-- collect all changes
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                                           data                                                            
+---------------------------------------------------------------------------------------------------------------------------
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:1 somedata[integer]:1 text[character varying]:'1'
+ table public.replication_example: INSERT: id[integer]:2 somedata[integer]:1 text[character varying]:'2'
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:3 somedata[integer]:2 text[character varying]:'1' bar[integer]:4
+ COMMIT
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:4 somedata[integer]:2 text[character varying]:'2' bar[integer]:4
+ table public.replication_example: INSERT: id[integer]:5 somedata[integer]:2 text[character varying]:'3' bar[integer]:4
+ table public.replication_example: INSERT: id[integer]:6 somedata[integer]:2 text[character varying]:'4' bar[integer]:null
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:7 somedata[integer]:3 text[character varying]:'1'
+ COMMIT
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:8 somedata[integer]:3 text[character varying]:'2'
+ table public.replication_example: INSERT: id[integer]:9 somedata[integer]:3 text[character varying]:'3'
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:10 somedata[integer]:4 somenum[character varying]:'1'
+ COMMIT
+(30 rows)
+
+ALTER TABLE replication_example ALTER COLUMN somenum TYPE int4 USING (somenum::int4);
+-- throw away changes, they contain oids
+SELECT count(data) FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+ count 
+-------
+    12
+(1 row)
+
+INSERT INTO replication_example(somedata, somenum) VALUES (5, 1);
+BEGIN;
+INSERT INTO replication_example(somedata, somenum) VALUES (6, 1);
+ALTER TABLE replication_example ADD COLUMN zaphod1 int;
+INSERT INTO replication_example(somedata, somenum, zaphod1) VALUES (6, 2, 1);
+ALTER TABLE replication_example ADD COLUMN zaphod2 int;
+INSERT INTO replication_example(somedata, somenum, zaphod2) VALUES (6, 3, 1);
+INSERT INTO replication_example(somedata, somenum, zaphod1) VALUES (6, 4, 2);
+COMMIT;
+-- show changes
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                                                   data                                                                   
+------------------------------------------------------------------------------------------------------------------------------------------
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:11 somedata[integer]:5 somenum[integer]:1
+ COMMIT
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:12 somedata[integer]:6 somenum[integer]:1
+ table public.replication_example: INSERT: id[integer]:13 somedata[integer]:6 somenum[integer]:2 zaphod1[integer]:1
+ table public.replication_example: INSERT: id[integer]:14 somedata[integer]:6 somenum[integer]:3 zaphod1[integer]:null zaphod2[integer]:1
+ table public.replication_example: INSERT: id[integer]:15 somedata[integer]:6 somenum[integer]:4 zaphod1[integer]:2 zaphod2[integer]:null
+ COMMIT
+(9 rows)
+
+-- hide changes bc of oid visible in full table rewrites
+CREATE TABLE tr_unique(id2 serial unique NOT NULL, data int);
+INSERT INTO tr_unique(data) VALUES(10);
+ALTER TABLE tr_unique RENAME TO tr_pkey;
+ALTER TABLE tr_pkey ADD COLUMN id serial primary key;
+SELECT count(data) FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+ count 
+-------
+    10
+(1 row)
+
+INSERT INTO tr_pkey(data) VALUES(1);
+--show deletion with primary key
+DELETE FROM tr_pkey;
+/* display results */
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                    data                                    
+----------------------------------------------------------------------------
+ BEGIN
+ table public.tr_pkey: INSERT: id2[integer]:2 data[integer]:1 id[integer]:2
+ COMMIT
+ BEGIN
+ table public.tr_pkey: DELETE: id[integer]:1
+ table public.tr_pkey: DELETE: id[integer]:2
+ COMMIT
+(7 rows)
+
+/*
+ * check that disk spooling works
+ */
+BEGIN;
+CREATE TABLE tr_etoomuch (id serial primary key, data int);
+INSERT INTO tr_etoomuch(data) SELECT g.i FROM generate_series(1, 10234) g(i);
+DELETE FROM tr_etoomuch WHERE id < 5000;
+UPDATE tr_etoomuch SET data = - data WHERE id > 5000;
+COMMIT;
+/* display results, but hide most of the output */
+SELECT count(*), min(data), max(data)
+FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0')
+GROUP BY substring(data, 1, 24)
+ORDER BY 1;
+ count |                       min                       |                                  max                                   
+-------+-------------------------------------------------+------------------------------------------------------------------------
+     1 | COMMIT                                          | COMMIT
+     1 | BEGIN                                           | BEGIN
+ 20467 | table public.tr_etoomuch: DELETE: id[integer]:1 | table public.tr_etoomuch: UPDATE: id[integer]:9999 data[integer]:-9999
+(3 rows)
+
+/*
+ * check whether we decode subtransactions correctly in relation with each
+ * other
+ */
+CREATE TABLE tr_sub (id serial primary key, path text);
+-- toplevel, subtxn, toplevel, subtxn, subtxn
+BEGIN;
+INSERT INTO tr_sub(path) VALUES ('1-top-#1');
+SAVEPOINT a;
+INSERT INTO tr_sub(path) VALUES ('1-top-1-#1');
+INSERT INTO tr_sub(path) VALUES ('1-top-1-#2');
+RELEASE SAVEPOINT a;
+SAVEPOINT b;
+SAVEPOINT c;
+INSERT INTO tr_sub(path) VALUES ('1-top-2-1-#1');
+INSERT INTO tr_sub(path) VALUES ('1-top-2-1-#2');
+RELEASE SAVEPOINT c;
+INSERT INTO tr_sub(path) VALUES ('1-top-2-#1');
+RELEASE SAVEPOINT b;
+COMMIT;
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                 data                                 
+----------------------------------------------------------------------
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.tr_sub: INSERT: id[integer]:1 path[text]:'1-top-#1'
+ table public.tr_sub: INSERT: id[integer]:2 path[text]:'1-top-1-#1'
+ table public.tr_sub: INSERT: id[integer]:3 path[text]:'1-top-1-#2'
+ table public.tr_sub: INSERT: id[integer]:4 path[text]:'1-top-2-1-#1'
+ table public.tr_sub: INSERT: id[integer]:5 path[text]:'1-top-2-1-#2'
+ table public.tr_sub: INSERT: id[integer]:6 path[text]:'1-top-2-#1'
+ COMMIT
+(10 rows)
+
+-- check that we handle xlog assignments correctly
+BEGIN;
+-- nest 80 subtxns
+SAVEPOINT subtop;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+-- assign xid by inserting
+INSERT INTO tr_sub(path) VALUES ('2-top-1...--#1');
+INSERT INTO tr_sub(path) VALUES ('2-top-1...--#2');
+INSERT INTO tr_sub(path) VALUES ('2-top-1...--#3');
+RELEASE SAVEPOINT subtop;
+INSERT INTO tr_sub(path) VALUES ('2-top-#1');
+COMMIT;
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                  data                                  
+------------------------------------------------------------------------
+ BEGIN
+ table public.tr_sub: INSERT: id[integer]:7 path[text]:'2-top-1...--#1'
+ table public.tr_sub: INSERT: id[integer]:8 path[text]:'2-top-1...--#2'
+ table public.tr_sub: INSERT: id[integer]:9 path[text]:'2-top-1...--#3'
+ table public.tr_sub: INSERT: id[integer]:10 path[text]:'2-top-#1'
+ COMMIT
+(6 rows)
+
+-- make sure rollbacked subtransactions aren't decoded
+BEGIN;
+INSERT INTO tr_sub(path) VALUES ('3-top-2-#1');
+SAVEPOINT a;
+INSERT INTO tr_sub(path) VALUES ('3-top-2-1-#1');
+SAVEPOINT b;
+INSERT INTO tr_sub(path) VALUES ('3-top-2-2-#1');
+ROLLBACK TO SAVEPOINT b;
+INSERT INTO tr_sub(path) VALUES ('3-top-2-#2');
+COMMIT;
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                 data                                  
+-----------------------------------------------------------------------
+ BEGIN
+ table public.tr_sub: INSERT: id[integer]:11 path[text]:'3-top-2-#1'
+ table public.tr_sub: INSERT: id[integer]:12 path[text]:'3-top-2-1-#1'
+ table public.tr_sub: INSERT: id[integer]:14 path[text]:'3-top-2-#2'
+ COMMIT
+(5 rows)
+
+-- test whether a known, but not yet logged toplevel xact, followed by a
+-- subxact commit is handled correctly
+BEGIN;
+SELECT txid_current() != 0; -- so no fixed xid apears in the outfile
+ ?column? 
+----------
+ t
+(1 row)
+
+SAVEPOINT a;
+INSERT INTO tr_sub(path) VALUES ('4-top-1-#1');
+RELEASE SAVEPOINT a;
+COMMIT;
+-- test whether a change in a subtransaction, in an unknown toplevel
+-- xact is handled correctly.
+BEGIN;
+SAVEPOINT a;
+INSERT INTO tr_sub(path) VALUES ('5-top-1-#1');
+COMMIT;
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                data                                 
+---------------------------------------------------------------------
+ BEGIN
+ table public.tr_sub: INSERT: id[integer]:15 path[text]:'4-top-1-#1'
+ COMMIT
+ BEGIN
+ table public.tr_sub: INSERT: id[integer]:16 path[text]:'5-top-1-#1'
+ COMMIT
+(6 rows)
+
+/*
+ * Check whether treating a table as a catalog table works somewhat
+ */
+CREATE TABLE replication_metadata (
+    id serial primary key,
+    relation name NOT NULL,
+    options text[]
+)
+WITH (user_catalog_table = true)
+;
+\d+ replication_metadata
+                                              Table "public.replication_metadata"
+  Column  |  Type   |                             Modifiers                             | Storage  | Stats target | Description 
+----------+---------+-------------------------------------------------------------------+----------+--------------+-------------
+ id       | integer | not null default nextval('replication_metadata_id_seq'::regclass) | plain    |              | 
+ relation | name    | not null                                                          | plain    |              | 
+ options  | text[]  |                                                                   | extended |              | 
+Indexes:
+    "replication_metadata_pkey" PRIMARY KEY, btree (id)
+Has OIDs: no
+Options: user_catalog_table=true
+
+INSERT INTO replication_metadata(relation, options)
+VALUES ('foo', ARRAY['a', 'b']);
+ALTER TABLE replication_metadata RESET (user_catalog_table);
+\d+ replication_metadata
+                                              Table "public.replication_metadata"
+  Column  |  Type   |                             Modifiers                             | Storage  | Stats target | Description 
+----------+---------+-------------------------------------------------------------------+----------+--------------+-------------
+ id       | integer | not null default nextval('replication_metadata_id_seq'::regclass) | plain    |              | 
+ relation | name    | not null                                                          | plain    |              | 
+ options  | text[]  |                                                                   | extended |              | 
+Indexes:
+    "replication_metadata_pkey" PRIMARY KEY, btree (id)
+Has OIDs: no
+
+INSERT INTO replication_metadata(relation, options)
+VALUES ('bar', ARRAY['a', 'b']);
+ALTER TABLE replication_metadata SET (user_catalog_table = true);
+\d+ replication_metadata
+                                              Table "public.replication_metadata"
+  Column  |  Type   |                             Modifiers                             | Storage  | Stats target | Description 
+----------+---------+-------------------------------------------------------------------+----------+--------------+-------------
+ id       | integer | not null default nextval('replication_metadata_id_seq'::regclass) | plain    |              | 
+ relation | name    | not null                                                          | plain    |              | 
+ options  | text[]  |                                                                   | extended |              | 
+Indexes:
+    "replication_metadata_pkey" PRIMARY KEY, btree (id)
+Has OIDs: no
+Options: user_catalog_table=true
+
+INSERT INTO replication_metadata(relation, options)
+VALUES ('blub', NULL);
+-- make sure rewrites don't work
+ALTER TABLE replication_metadata ADD COLUMN rewritemeornot int;
+ALTER TABLE replication_metadata ALTER COLUMN rewritemeornot TYPE text;
+ERROR:  cannot rewrite table "replication_metadata" used as a catalog table
+ALTER TABLE replication_metadata SET (user_catalog_table = false);
+\d+ replication_metadata
+                                                 Table "public.replication_metadata"
+     Column     |  Type   |                             Modifiers                             | Storage  | Stats target | Description 
+----------------+---------+-------------------------------------------------------------------+----------+--------------+-------------
+ id             | integer | not null default nextval('replication_metadata_id_seq'::regclass) | plain    |              | 
+ relation       | name    | not null                                                          | plain    |              | 
+ options        | text[]  |                                                                   | extended |              | 
+ rewritemeornot | integer |                                                                   | plain    |              | 
+Indexes:
+    "replication_metadata_pkey" PRIMARY KEY, btree (id)
+Has OIDs: no
+Options: user_catalog_table=false
+
+INSERT INTO replication_metadata(relation, options)
+VALUES ('zaphod', NULL);
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                                                data                                                                
+------------------------------------------------------------------------------------------------------------------------------------
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.replication_metadata: INSERT: id[integer]:1 relation[name]:'foo' options[text[]]:'{a,b}'
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.replication_metadata: INSERT: id[integer]:2 relation[name]:'bar' options[text[]]:'{a,b}'
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.replication_metadata: INSERT: id[integer]:3 relation[name]:'blub' options[text[]]:null
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.replication_metadata: INSERT: id[integer]:4 relation[name]:'zaphod' options[text[]]:null rewritemeornot[integer]:null
+ COMMIT
+(22 rows)
+
+/*
+ * check whether we handle updates/deletes correct with & without a pkey
+ */
+/* we should handle the case without a key at all more gracefully */
+CREATE TABLE table_without_key(id serial, data int);
+INSERT INTO table_without_key(data) VALUES(1),(2);
+DELETE FROM table_without_key WHERE data = 1;
+-- won't log old keys
+UPDATE table_without_key SET data = 3 WHERE data = 2;
+UPDATE table_without_key SET id = -id;
+UPDATE table_without_key SET id = -id;
+-- should log the full old row now
+ALTER TABLE table_without_key REPLICA IDENTITY FULL;
+UPDATE table_without_key SET data = 3 WHERE data = 2;
+UPDATE table_without_key SET id = -id;
+UPDATE table_without_key SET id = -id;
+DELETE FROM table_without_key WHERE data = 3;
+CREATE TABLE table_with_pkey(id serial primary key, data int);
+INSERT INTO table_with_pkey(data) VALUES(1), (2);
+DELETE FROM table_with_pkey WHERE data = 1;
+-- should log the old pkey
+UPDATE table_with_pkey SET data = 3 WHERE data = 2;
+UPDATE table_with_pkey SET id = -id;
+UPDATE table_with_pkey SET id = -id;
+-- check that we log nothing despite having a pkey
+ALTER TABLE table_without_key REPLICA IDENTITY NOTHING;
+UPDATE table_with_pkey SET id = -id;
+-- check that we log everything despite having a pkey
+ALTER TABLE table_without_key REPLICA IDENTITY FULL;
+UPDATE table_with_pkey SET id = -id;
+DELETE FROM table_with_pkey WHERE data = 3;
+CREATE TABLE table_with_unique_not_null(id serial unique, data int);
+ALTER TABLE table_with_unique_not_null ALTER COLUMN id SET NOT NULL; --already set
+-- won't log anything, replica identity not setup
+INSERT INTO table_with_unique_not_null(data) VALUES(1), (2);
+DELETE FROM table_with_unique_not_null WHERE data = 1;
+UPDATE table_with_unique_not_null SET data = 3 WHERE data = 2;
+UPDATE table_with_unique_not_null SET id = -id;
+UPDATE table_with_unique_not_null SET id = -id;
+DELETE FROM table_with_unique_not_null WHERE data = 3;
+-- should log old key
+ALTER TABLE table_with_unique_not_null REPLICA IDENTITY USING INDEX table_with_unique_not_null_id_key;
+INSERT INTO table_with_unique_not_null(data) VALUES(1), (2);
+DELETE FROM table_with_unique_not_null WHERE data = 1;
+UPDATE table_with_unique_not_null SET data = 3 WHERE data = 2;
+UPDATE table_with_unique_not_null SET id = -id;
+UPDATE table_with_unique_not_null SET id = -id;
+DELETE FROM table_with_unique_not_null WHERE data = 3;
+-- check toast support
+BEGIN;
+CREATE SEQUENCE toasttable_rand_seq START 79 INCREMENT 1499; -- portable "random"
+CREATE TABLE toasttable(
+       id serial primary key,
+       toasted_col1 text,
+       rand1 float8 DEFAULT nextval('toasttable_rand_seq'),
+       toasted_col2 text,
+       rand2 float8 DEFAULT nextval('toasttable_rand_seq')
+       );
+COMMIT;
+-- uncompressed external toast data
+INSERT INTO toasttable(toasted_col1) SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i);
+-- compressed external toast data
+INSERT INTO toasttable(toasted_col2) SELECT repeat(string_agg(to_char(g.i, 'FM0000'), ''), 50) FROM generate_series(1, 500) g(i);
+-- update of existing column
+UPDATE toasttable
+    SET toasted_col1 = (SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i))
+WHERE id = 1;
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          data                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.table_without_key: INSERT: id[integer]:1 data[integer]:1
+ table public.table_without_key: INSERT: id[integer]:2 data[integer]:2
+ COMMIT
+ BEGIN
+ table public.table_without_key: DELETE: (no-tuple-data)
+ COMMIT
+ BEGIN
+ table public.table_without_key: UPDATE: id[integer]:2 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_without_key: UPDATE: id[integer]:-2 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_without_key: UPDATE: id[integer]:2 data[integer]:3
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.table_without_key: UPDATE: old-key: id[integer]:2 data[integer]:3 new-tuple: id[integer]:-2 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_without_key: UPDATE: old-key: id[integer]:-2 data[integer]:3 new-tuple: id[integer]:2 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_without_key: DELETE: id[integer]:2 data[integer]:3
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.table_with_pkey: INSERT: id[integer]:1 data[integer]:1
+ table public.table_with_pkey: INSERT: id[integer]:2 data[integer]:2
+ COMMIT
+ BEGIN
+ table public.table_with_pkey: DELETE: id[integer]:1
+ COMMIT
+ BEGIN
+ table public.table_with_pkey: UPDATE: id[integer]:2 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_with_pkey: UPDATE: old-key: id[integer]:2 new-tuple: id[integer]:-2 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_with_pkey: UPDATE: old-key: id[integer]:-2 new-tuple: id[integer]:2 data[integer]:3
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.table_with_pkey: UPDATE: old-key: id[integer]:2 new-tuple: id[integer]:-2 data[integer]:3
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.table_with_pkey: UPDATE: old-key: id[integer]:-2 new-tuple: id[integer]:2 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_with_pkey: DELETE: id[integer]:2
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: INSERT: id[integer]:1 data[integer]:1
+ table public.table_with_unique_not_null: INSERT: id[integer]:2 data[integer]:2
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: DELETE: (no-tuple-data)
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: UPDATE: id[integer]:2 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: UPDATE: id[integer]:-2 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: UPDATE: id[integer]:2 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: DELETE: (no-tuple-data)
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: INSERT: id[integer]:3 data[integer]:1
+ table public.table_with_unique_not_null: INSERT: id[integer]:4 data[integer]:2
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: DELETE: id[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: UPDATE: id[integer]:4 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: UPDATE: old-key: id[integer]:4 new-tuple: id[integer]:-4 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: UPDATE: old-key: id[integer]:-4 new-tuple: id[integer]:4 data[integer]:3
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: DELETE: id[integer]:4
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.toasttable: INSERT: id[integer]:1 toasted_col1[text]:'12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000' rand1[double precision]:79 toasted_col2[text]:null rand2[double precision]:1578
+ COMMIT
+ BEGIN
+ table public.toasttable: INSERT: id[integer]:2 toasted_col1[text]:null rand1[double precision]:3077 toasted_col2[text]:'0001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500000100020003000400050006000700080009001000110012001300140015001600170018001900200021002200230024002500260027002800290030003100320033003400350036003700380039004000410042004300440045004600470048004900500051005200530054005500560057005800590060006100620063006400650066006700680069007000710072007300740075007600770078007900800081008200830084008500860087008800890090009100920093009400950096009700980099010001010102010301040105010601070108010901100111011201130114011501160117011801190120012101220123012401250126012701280129013001310132013301340135013601370138013901400141014201430144014501460147014801490150015101520153015401550156015701580159016001610162016301640165016601670168016901700171017201730174017501760177017801790180018101820183018401850186018701880189019001910192019301940195019601970198019902000201020202030204020502060207020802090210021102120213021402150216021702180219022002210222022302240225022602270228022902300231023202330234023502360237023802390240024102420243024402450246024702480249025002510252025302540255025602570258025902600261026202630264026502660267026802690270027102720273027402750276027702780279028002810282028302840285028602870288028902900291029202930294029502960297029802990300030103020303030403050306030703080309031003110312031303140315031603170318031903200321032203230324032503260327032803290330033103320333033403350336033703380339034003410342034303440345034603470348034903500351035203530354035503560357035803590360036103620363036403650366036703680369037003710372037303740375037603770378037903800381038203830384038503860387038803890390039103920393039403950396039703980399040004010402040304040405040604070408040904100411041204130414041504160417041804190420042104220423042404250426042704280429043004310432043304340435043604370438043904400441044204430444044504460447044804490450045104520453045404550456045704580459046004610462046304640465046604670468046904700471047204730474047504760477047804790480048104820483048404850486048704880489049004910492049304940495049604970498049905000001000200030004000500060007000800090010001100120013001400150016001700180019002000210022002300240025002600270028002900300031003200330034003500360037003800390040004100420043004400450046004700480049005000510052005300540055005600570058005900600061006200630064006500660067006800690070007100720073007400750076007700780079008000810082008300840085008600870088008900900091009200930094009500960097009800990100010101020103010401050106010701080109011001110112011301140115011601170118011901200121012201230124012501260127012801290130013101320133013401350136013701380139014001410142014301440145014601470148014901500151015201530154015501560157015801590160016101620163016401650166016701680169017001710172017301740175017601770178017901800181018201830184018501860187018801890190019101920193019401950196019701980199020002010202020302040205020602070208020902100211021202130214021502160217021802190220022102220223022402250226022702280229023002310232023302340235023602370238023902400241024202430244024502460247024802490250025102520253025402550256025702580259026002610262026302640265026602670268026902700271027202730274027502760277027802790280028102820283028402850286028702880289029002910292029302940295029602970298029903000301030203030304030503060307030803090310031103120313031403150316031703180319032003210322032303240325032603270328032903300331033203330334033503360337033803390340034103420343034403450346034703480349035003510352035303540355035603570358035903600361036203630364036503660367036803690370037103720373037403750376037703780379038003810382038303840385038603870388038903900391039203930394039503960397039803990400040104020403040404050406040704080409041004110412041304140415041604170418041904200421042204230424042504260427042804290430043104320433043404350436043704380439044004410442044304440445044604470448044904500451045204530454045504560457045804590460046104620463046404650466046704680469047004710472047304740475047604770478047904800481048204830484048504860487048804890490049104920493049404950496049704980499050000010002000300040005000600070008000900100011001200130014001500160017001800190020002100220023002400250026002700280029003000310032003300340035003600370038003900400041004200430044004500460047004800490050005100520053005400550056005700580059006000610062006300640065006600670068006900700071007200730074007500760077007800790080008100820083008400850086008700880089009000910092009300940095009600970098009901000101010201030104010501060107010801090110011101120113011401150116011701180119012001210122012301240125012601270128012901300131013201330134013501360137013801390140014101420143014401450146014701480149015001510152015301540155015601570158015901600161016201630164016501660167016801690170017101720173017401750176017701780179018001810182018301840185018601870188018901900191019201930194019501960197019801990200020102020203020402050206020702080209021002110212021302140215021602170218021902200221022202230224022502260227022802290230023102320233023402350236023702380239024002410242024302440245024602470248024902500251025202530254025502560257025802590260026102620263026402650266026702680269027002710272027302740275027602770278027902800281028202830284028502860287028802890290029102920293029402950296029702980299030003010302030303040305030603070308030903100311031203130314031503160317031803190320032103220323032403250326032703280329033003310332033303340335033603370338033903400341034203430344034503460347034803490350035103520353035403550356035703580359036003610362036303640365036603670368036903700371037203730374037503760377037803790380038103820383038403850386038703880389039003910392039303940395039603970398039904000401040204030404040504060407040804090410041104120413041404150416041704180419042004210422042304240425042604270428042904300431043204330434043504360437043804390440044104420443044404450446044704480449045004510452045304540455045604570458045904600461046204630464046504660467046804690470047104720473047404750476047704780479048004810482048304840485048604870488048904900491049204930494049504960497049804990500' rand2[double precision]:4576
+ COMMIT
+ BEGIN
+ table public.toasttable: UPDATE: id[integer]:1 toasted_col1[text]:'12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000' rand1[double precision]:79 toasted_col2[text]:null rand2[double precision]:1578
+ COMMIT
+(113 rows)
+
+INSERT INTO toasttable(toasted_col1) SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i);
+-- update of second column, first column unchanged
+UPDATE toasttable
+    SET toasted_col2 = (SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i))
+WHERE id = 1;
+-- make sure we decode correctly even if the toast table is gone
+DROP TABLE toasttable;
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        data                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ BEGIN
+ table public.toasttable: INSERT: id[integer]:3 toasted_col1[text]:'12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000' rand1[double precision]:6075 toasted_col2[text]:null rand2[double precision]:7574
+ COMMIT
+ BEGIN
+ table public.toasttable: UPDATE: id[integer]:1 toasted_col1[text]:unchanged-toast-datum rand1[double precision]:79 toasted_col2[text]:'12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000' rand2[double precision]:1578
+ COMMIT
+ BEGIN
+ COMMIT
+(8 rows)
+
+-- done, free logical replication slot
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+ data 
+------
+(0 rows)
+
+SELECT pg_drop_replication_slot('regression_slot');
+ pg_drop_replication_slot 
+--------------------------
+(1 row)
+
+/* check that we aren't visible anymore now */
+SELECT * FROM pg_stat_replication;
+ pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_start | backend_xmin | state | sent_location | write_location | flush_location | replay_location | sync_priority | sync_state 
+-----+----------+---------+------------------+-------------+-----------------+-------------+---------------+--------------+-------+---------------+----------------+----------------+-----------------+---------------+------------
+(0 rows)
+
diff --git a/contrib/test_decoding/expected/decoding_in_xact.out b/contrib/test_decoding/expected/decoding_in_xact.out
new file mode 100644 (file)
index 0000000..d15b0b5
--- /dev/null
@@ -0,0 +1,89 @@
+-- predictability
+SET synchronous_commit = on;
+-- fail because we're creating a slot while in an xact with xid
+BEGIN;
+SELECT txid_current() = 0;
+ ?column? 
+----------
+ f
+(1 row)
+
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ERROR:  cannot create logical replication slot in transaction that has performed writes
+ROLLBACK;
+-- fail because we're creating a slot while in an subxact whose topxact has a xid
+BEGIN;
+SELECT txid_current() = 0;
+ ?column? 
+----------
+ f
+(1 row)
+
+SAVEPOINT barf;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ERROR:  cannot create logical replication slot in transaction that has performed writes
+ROLLBACK TO SAVEPOINT barf;
+ROLLBACK;
+-- succeed, outside tx.
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ ?column? 
+----------
+ init
+(1 row)
+
+SELECT 'stop' FROM pg_drop_replication_slot('regression_slot');
+ ?column? 
+----------
+ stop
+(1 row)
+
+-- succeed, in tx without xid.
+BEGIN;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ ?column? 
+----------
+ init
+(1 row)
+
+COMMIT;
+CREATE TABLE nobarf(id serial primary key, data text);
+INSERT INTO nobarf(data) VALUES('1');
+-- decoding works in transaction with xid
+BEGIN;
+SELECT txid_current() = 0;
+ ?column? 
+----------
+ f
+(1 row)
+
+-- don't show yet, haven't committed
+INSERT INTO nobarf(data) VALUES('2');
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                           data                            
+-----------------------------------------------------------
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.nobarf: INSERT: id[integer]:1 data[text]:'1'
+ COMMIT
+(5 rows)
+
+COMMIT;
+INSERT INTO nobarf(data) VALUES('3');
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                           data                            
+-----------------------------------------------------------
+ BEGIN
+ table public.nobarf: INSERT: id[integer]:2 data[text]:'2'
+ COMMIT
+ BEGIN
+ table public.nobarf: INSERT: id[integer]:3 data[text]:'3'
+ COMMIT
+(6 rows)
+
+SELECT 'stop' FROM pg_drop_replication_slot('regression_slot');
+ ?column? 
+----------
+ stop
+(1 row)
+
diff --git a/contrib/test_decoding/expected/delayed_startup.out b/contrib/test_decoding/expected/delayed_startup.out
new file mode 100644 (file)
index 0000000..db8c525
--- /dev/null
@@ -0,0 +1,38 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1b s1w s2init s1c s2start s1b s1w s1c s2start s1b s1w s2start s1c s2start
+step s1b: BEGIN ISOLATION LEVEL SERIALIZABLE;
+step s1w: INSERT INTO do_write DEFAULT VALUES;
+step s2init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding'); 
+step s1c: COMMIT;
+step s2init: <... completed>
+?column?       
+
+init           
+step s2start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false');
+data           
+
+step s1b: BEGIN ISOLATION LEVEL SERIALIZABLE;
+step s1w: INSERT INTO do_write DEFAULT VALUES;
+step s1c: COMMIT;
+step s2start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false');
+data           
+
+BEGIN          
+table public.do_write: INSERT: id[integer]:2
+COMMIT         
+step s1b: BEGIN ISOLATION LEVEL SERIALIZABLE;
+step s1w: INSERT INTO do_write DEFAULT VALUES;
+step s2start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false');
+data           
+
+step s1c: COMMIT;
+step s2start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false');
+data           
+
+BEGIN          
+table public.do_write: INSERT: id[integer]:3
+COMMIT         
+?column?       
+
+stop           
diff --git a/contrib/test_decoding/expected/mxact.out b/contrib/test_decoding/expected/mxact.out
new file mode 100644 (file)
index 0000000..f0d96cc
--- /dev/null
@@ -0,0 +1,66 @@
+Parsed test spec with 3 sessions
+
+starting permutation: s0init s0start s1begin s1sharepgclass s2begin s2sharepgclass s0w s0start s2commit s1commit
+step s0init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s0start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false');
+data           
+
+step s1begin: BEGIN;
+step s1sharepgclass: SELECT count(*) > 1 FROM (SELECT * FROM pg_class FOR SHARE) s;
+?column?       
+
+t              
+step s2begin: BEGIN;
+step s2sharepgclass: SELECT count(*) > 1 FROM (SELECT * FROM pg_class FOR SHARE) s;
+?column?       
+
+t              
+step s0w: INSERT INTO do_write DEFAULT VALUES;
+step s0start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false');
+data           
+
+BEGIN          
+table public.do_write: INSERT: id[integer]:1
+COMMIT         
+step s2commit: COMMIT;
+step s1commit: COMMIT;
+?column?       
+
+stop           
+
+starting permutation: s0init s0start s1begin s1keysharepgclass s2begin s2keysharepgclass s0alter s0w s0start s2commit s1commit
+step s0init: SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');
+?column?       
+
+init           
+step s0start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false');
+data           
+
+step s1begin: BEGIN;
+step s1keysharepgclass: SELECT count(*) > 1 FROM (SELECT * FROM pg_class FOR KEY SHARE) s;
+?column?       
+
+t              
+step s2begin: BEGIN;
+step s2keysharepgclass: SELECT count(*) > 1 FROM (SELECT * FROM pg_class FOR KEY SHARE) s;
+?column?       
+
+t              
+step s0alter: ALTER TABLE do_write ADD column ts timestamptz;
+step s0w: INSERT INTO do_write DEFAULT VALUES;
+step s0start: SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false');
+data           
+
+BEGIN          
+COMMIT         
+BEGIN          
+table public.do_write: INSERT: id[integer]:1 ts[timestamp with time zone]:null
+COMMIT         
+step s2commit: COMMIT;
+step s1commit: COMMIT;
+?column?       
+
+stop           
diff --git a/contrib/test_decoding/expected/permissions.out b/contrib/test_decoding/expected/permissions.out
new file mode 100644 (file)
index 0000000..85b7f5d
--- /dev/null
@@ -0,0 +1,130 @@
+-- predictability
+SET synchronous_commit = on;
+-- setup
+CREATE ROLE lr_normal;
+CREATE ROLE lr_superuser SUPERUSER;
+CREATE ROLE lr_replication REPLICATION;
+CREATE TABLE lr_test(data text);
+-- superuser can control replication
+SET ROLE lr_superuser;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ ?column? 
+----------
+ init
+(1 row)
+
+INSERT INTO lr_test VALUES('lr_superuser_init');
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                             data                             
+--------------------------------------------------------------
+ BEGIN
+ table public.lr_test: INSERT: data[text]:'lr_superuser_init'
+ COMMIT
+(3 rows)
+
+SELECT pg_drop_replication_slot('regression_slot');
+ pg_drop_replication_slot 
+--------------------------
+(1 row)
+
+RESET ROLE;
+-- replication user can control replication
+SET ROLE lr_replication;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ ?column? 
+----------
+ init
+(1 row)
+
+INSERT INTO lr_test VALUES('lr_superuser_init');
+ERROR:  permission denied for relation lr_test
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+ data 
+------
+(0 rows)
+
+SELECT pg_drop_replication_slot('regression_slot');
+ pg_drop_replication_slot 
+--------------------------
+(1 row)
+
+RESET ROLE;
+-- plain user *can't* can control replication
+SET ROLE lr_normal;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ERROR:  must be superuser or replication role to use replication slots
+INSERT INTO lr_test VALUES('lr_superuser_init');
+ERROR:  permission denied for relation lr_test
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+ERROR:  must be superuser or replication role to use replication slots
+SELECT pg_drop_replication_slot('regression_slot');
+ERROR:  must be superuser or replication role to use replication slots
+RESET ROLE;
+-- replication users can drop superuser created slots
+SET ROLE lr_superuser;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ ?column? 
+----------
+ init
+(1 row)
+
+RESET ROLE;
+SET ROLE lr_replication;
+SELECT pg_drop_replication_slot('regression_slot');
+ pg_drop_replication_slot 
+--------------------------
+(1 row)
+
+RESET ROLE;
+-- normal users can't drop existing slots
+SET ROLE lr_superuser;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ ?column? 
+----------
+ init
+(1 row)
+
+RESET ROLE;
+SET ROLE lr_normal;
+SELECT pg_drop_replication_slot('regression_slot');
+ERROR:  must be superuser or replication role to use replication slots
+RESET ROLE;
+-- all users can see existing slots
+SET ROLE lr_superuser;
+SELECT slot_name, plugin FROM pg_replication_slots;
+    slot_name    |    plugin     
+-----------------+---------------
+ regression_slot | test_decoding
+(1 row)
+
+RESET ROLE;
+SET ROLE lr_replication;
+SELECT slot_name, plugin FROM pg_replication_slots;
+    slot_name    |    plugin     
+-----------------+---------------
+ regression_slot | test_decoding
+(1 row)
+
+RESET ROLE;
+SET ROLE lr_normal;
+SELECT slot_name, plugin FROM pg_replication_slots;
+    slot_name    |    plugin     
+-----------------+---------------
+ regression_slot | test_decoding
+(1 row)
+
+RESET ROLE;
+-- cleanup
+SELECT pg_drop_replication_slot('regression_slot');
+ pg_drop_replication_slot 
+--------------------------
+(1 row)
+
+DROP ROLE lr_normal;
+DROP ROLE lr_superuser;
+DROP ROLE lr_replication;
+DROP TABLE lr_test;
diff --git a/contrib/test_decoding/expected/rewrite.out b/contrib/test_decoding/expected/rewrite.out
new file mode 100644 (file)
index 0000000..ec23ab9
--- /dev/null
@@ -0,0 +1,107 @@
+-- predictability
+SET synchronous_commit = on;
+DROP TABLE IF EXISTS replication_example;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ ?column? 
+----------
+ init
+(1 row)
+
+CREATE TABLE replication_example(id SERIAL PRIMARY KEY, somedata int, text varchar(120));
+INSERT INTO replication_example(somedata) VALUES (1);
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                                   data                                                   
+----------------------------------------------------------------------------------------------------------
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:1 somedata[integer]:1 text[character varying]:null
+ COMMIT
+(5 rows)
+
+BEGIN;
+INSERT INTO replication_example(somedata) VALUES (2);
+ALTER TABLE replication_example ADD COLUMN testcolumn1 int;
+INSERT INTO replication_example(somedata, testcolumn1) VALUES (3,  1);
+COMMIT;
+BEGIN;
+INSERT INTO replication_example(somedata) VALUES (3);
+ALTER TABLE replication_example ADD COLUMN testcolumn2 int;
+INSERT INTO replication_example(somedata, testcolumn1, testcolumn2) VALUES (4,  2, 1);
+COMMIT;
+VACUUM FULL pg_am;
+VACUUM FULL pg_amop;
+VACUUM FULL pg_proc;
+VACUUM FULL pg_opclass;
+VACUUM FULL pg_type;
+VACUUM FULL pg_index;
+VACUUM FULL pg_database;
+-- repeated rewrites that fail
+BEGIN;
+CLUSTER pg_class USING pg_class_oid_index;
+CLUSTER pg_class USING pg_class_oid_index;
+ROLLBACK;
+-- repeated rewrites that succeed
+BEGIN;
+CLUSTER pg_class USING pg_class_oid_index;
+CLUSTER pg_class USING pg_class_oid_index;
+CLUSTER pg_class USING pg_class_oid_index;
+COMMIT;
+ -- repeated rewrites in different transactions
+VACUUM FULL pg_class;
+VACUUM FULL pg_class;
+INSERT INTO replication_example(somedata, testcolumn1) VALUES (5, 3);
+BEGIN;
+INSERT INTO replication_example(somedata, testcolumn1) VALUES (6, 4);
+ALTER TABLE replication_example ADD COLUMN testcolumn3 int;
+INSERT INTO replication_example(somedata, testcolumn1, testcolumn3) VALUES (7, 5, 1);
+COMMIT;
+-- make old files go away
+CHECKPOINT;
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                                                                       data                                                                                       
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:2 somedata[integer]:2 text[character varying]:null
+ table public.replication_example: INSERT: id[integer]:3 somedata[integer]:3 text[character varying]:null testcolumn1[integer]:1
+ COMMIT
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:4 somedata[integer]:3 text[character varying]:null testcolumn1[integer]:null
+ table public.replication_example: INSERT: id[integer]:5 somedata[integer]:4 text[character varying]:null testcolumn1[integer]:2 testcolumn2[integer]:1
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:6 somedata[integer]:5 text[character varying]:null testcolumn1[integer]:3 testcolumn2[integer]:null
+ COMMIT
+ BEGIN
+ table public.replication_example: INSERT: id[integer]:7 somedata[integer]:6 text[character varying]:null testcolumn1[integer]:4 testcolumn2[integer]:null
+ table public.replication_example: INSERT: id[integer]:8 somedata[integer]:7 text[character varying]:null testcolumn1[integer]:5 testcolumn2[integer]:null testcolumn3[integer]:1
+ COMMIT
+(35 rows)
+
+SELECT pg_drop_replication_slot('regression_slot');
+ pg_drop_replication_slot 
+--------------------------
+(1 row)
+
+DROP TABLE IF EXISTS replication_example;
diff --git a/contrib/test_decoding/expected/toast.out b/contrib/test_decoding/expected/toast.out
new file mode 100644 (file)
index 0000000..6adef83
--- /dev/null
@@ -0,0 +1,90 @@
+-- predictability
+SET synchronous_commit = on;
+DROP TABLE IF EXISTS xpto;
+NOTICE:  table "xpto" does not exist, skipping
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ ?column? 
+----------
+ init
+(1 row)
+
+CREATE SEQUENCE xpto_rand_seq START 79 INCREMENT 1499; -- portable "random"
+CREATE TABLE xpto (
+    id serial primary key,
+    toasted_col1 text,
+    rand1 float8 DEFAULT nextval('xpto_rand_seq'),
+    toasted_col2 text,
+    rand2 float8 DEFAULT nextval('xpto_rand_seq')
+);
+-- uncompressed external toast data
+INSERT INTO xpto (toasted_col1, toasted_col2) SELECT string_agg(g.i::text, ''), string_agg((g.i*2)::text, '') FROM generate_series(1, 2000) g(i);
+-- compressed external toast data
+INSERT INTO xpto (toasted_col2) SELECT repeat(string_agg(to_char(g.i, 'FM0000'), ''), 50) FROM generate_series(1, 500) g(i);
+-- update of existing column
+UPDATE xpto SET toasted_col1 = (SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i)) WHERE id = 1;
+UPDATE xpto SET rand1 = 123.456 WHERE id = 1;
+DELETE FROM xpto WHERE id = 1;
+DROP TABLE IF EXISTS toasted_key;
+NOTICE:  table "toasted_key" does not exist, skipping
+CREATE TABLE toasted_key (
+    id serial,
+    toasted_key text PRIMARY KEY,
+    toasted_col1 text,
+    toasted_col2 text
+);
+ALTER TABLE toasted_key ALTER COLUMN toasted_key SET STORAGE EXTERNAL;
+ALTER TABLE toasted_key ALTER COLUMN toasted_col1 SET STORAGE EXTERNAL;
+INSERT INTO toasted_key(toasted_key, toasted_col1) VALUES(repeat('1234567890', 200), repeat('9876543210', 200));
+-- test update of a toasted key without changing it
+UPDATE toasted_key SET toasted_col2 = toasted_col1;
+-- test update of a toasted key, changing it
+UPDATE toasted_key SET toasted_key = toasted_key || '1';
+DELETE FROM toasted_key;
+SELECT substr(data, 1, 200) FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+                                                                                                  substr                                                                                                  
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.xpto: INSERT: id[integer]:1 toasted_col1[text]:'1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
+ COMMIT
+ BEGIN
+ table public.xpto: INSERT: id[integer]:2 toasted_col1[text]:null rand1[double precision]:3077 toasted_col2[text]:'00010002000300040005000600070008000900100011001200130014001500160017001800190020002100
+ COMMIT
+ BEGIN
+ table public.xpto: UPDATE: id[integer]:1 toasted_col1[text]:'1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
+ COMMIT
+ BEGIN
+ table public.xpto: UPDATE: id[integer]:1 toasted_col1[text]:unchanged-toast-datum rand1[double precision]:123.456 toasted_col2[text]:unchanged-toast-datum rand2[double precision]:1578
+ COMMIT
+ BEGIN
+ table public.xpto: DELETE: id[integer]:1
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ COMMIT
+ BEGIN
+ table public.toasted_key: INSERT: id[integer]:1 toasted_key[text]:'1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123
+ COMMIT
+ BEGIN
+ table public.toasted_key: UPDATE: id[integer]:1 toasted_key[text]:unchanged-toast-datum toasted_col1[text]:unchanged-toast-datum toasted_col2[text]:'987654321098765432109876543210987654321098765432109
+ COMMIT
+ BEGIN
+ table public.toasted_key: UPDATE: old-key: toasted_key[text]:'123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
+ COMMIT
+ BEGIN
+ table public.toasted_key: DELETE: toasted_key[text]:'123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567
+ COMMIT
+(37 rows)
+
+SELECT pg_drop_replication_slot('regression_slot');
+ pg_drop_replication_slot 
+--------------------------
+(1 row)
+
diff --git a/contrib/test_decoding/logical.conf b/contrib/test_decoding/logical.conf
new file mode 100644 (file)
index 0000000..367f706
--- /dev/null
@@ -0,0 +1,2 @@
+wal_level = logical
+max_replication_slots = 4
diff --git a/contrib/test_decoding/specs/concurrent_ddl_dml.spec b/contrib/test_decoding/specs/concurrent_ddl_dml.spec
new file mode 100644 (file)
index 0000000..7c8a7c7
--- /dev/null
@@ -0,0 +1,94 @@
+setup
+{
+    DROP TABLE IF EXISTS tbl1;
+    DROP TABLE IF EXISTS tbl2;
+    CREATE TABLE tbl1(val1 integer, val2 integer);
+    CREATE TABLE tbl2(val1 integer, val2 integer);
+}
+
+teardown
+{
+    DROP TABLE tbl1;
+    DROP TABLE tbl2;
+    SELECT 'stop' FROM pg_drop_replication_slot('isolation_slot');
+}
+
+session "s1"
+step "s1_init" { SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding'); }
+step "s1_begin" { BEGIN; }
+step "s1_insert_tbl1" { INSERT INTO tbl1 (val1, val2) VALUES (1, 1); }
+step "s1_insert_tbl1_3col" { INSERT INTO tbl1 (val1, val2, val3) VALUES (1, 1, 1); }
+step "s1_insert_tbl2" { INSERT INTO tbl2 (val1, val2) VALUES (1, 1); }
+step "s1_insert_tbl2_3col" { INSERT INTO tbl2 (val1, val2, val3) VALUES (1, 1, 1); }
+step "s1_commit" { COMMIT; }
+
+session "s2"
+step "s2_alter_tbl1_float" { ALTER TABLE tbl1 ALTER COLUMN val2 TYPE float; }
+step "s2_alter_tbl1_char" { ALTER TABLE tbl1 ALTER COLUMN val2 TYPE character varying; }
+step "s2_alter_tbl1_text" { ALTER TABLE tbl1 ALTER COLUMN val2 TYPE text; }
+step "s2_alter_tbl1_boolean" { ALTER TABLE tbl1 ALTER COLUMN val2 TYPE boolean; }
+
+step "s2_alter_tbl1_add_int" { ALTER TABLE tbl1 ADD COLUMN val3 INTEGER; }
+step "s2_alter_tbl1_add_float" { ALTER TABLE tbl1 ADD COLUMN val3 FLOAT; }
+step "s2_alter_tbl1_add_char" { ALTER TABLE tbl1 ADD COLUMN val3 character varying; }
+step "s2_alter_tbl1_add_boolean" { ALTER TABLE tbl1 ADD COLUMN val3 BOOLEAN; }
+step "s2_alter_tbl1_add_text" { ALTER TABLE tbl1 ADD COLUMN val3 TEXT; }
+
+step "s2_alter_tbl2_float" { ALTER TABLE tbl2 ALTER COLUMN val2 TYPE float; }
+step "s2_alter_tbl2_char" { ALTER TABLE tbl2 ALTER COLUMN val2 TYPE character varying; }
+step "s2_alter_tbl2_text" { ALTER TABLE tbl2 ALTER COLUMN val2 TYPE text; }
+step "s2_alter_tbl2_boolean" { ALTER TABLE tbl2 ALTER COLUMN val2 TYPE boolean; }
+step "s2_alter_tbl2_text" { ALTER TABLE tbl2 ALTER COLUMN val2 TYPE boolean; }
+
+step "s2_alter_tbl2_add_int" { ALTER TABLE tbl2 ADD COLUMN val3 INTEGER; }
+step "s2_alter_tbl2_add_float" { ALTER TABLE tbl2 ADD COLUMN val3 FLOAT; }
+step "s2_alter_tbl2_add_char" { ALTER TABLE tbl2 ADD COLUMN val3 character varying; }
+step "s2_alter_tbl2_add_boolean" { ALTER TABLE tbl2 ADD COLUMN val3 BOOLEAN; }
+step "s2_alter_tbl2_add_text" { ALTER TABLE tbl2 ADD COLUMN val3 TEXT; }
+step "s2_alter_tbl2_drop_3rd_col" { ALTER TABLE tbl2 DROP COLUMN val3; }
+step "s2_alter_tbl2_3rd_char" { ALTER TABLE tbl2 ALTER COLUMN val3 TYPE character varying; }
+step "s2_alter_tbl2_3rd_text" { ALTER TABLE tbl2 ALTER COLUMN val3 TYPE text; }
+step "s2_alter_tbl2_3rd_int" { ALTER TABLE tbl2 ALTER COLUMN val3 TYPE int USING val3::integer; }
+
+step "s2_get_changes" { SELECT regexp_replace(data, 'temp_\d+', 'temp') AS data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', '0'); }
+
+
+
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_float" "s1_insert_tbl2" "s1_commit" "s2_get_changes"
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl1_float" "s1_insert_tbl2" "s1_commit" "s2_get_changes"
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_char" "s1_insert_tbl2" "s1_commit" "s2_get_changes"
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl1_char" "s1_insert_tbl2" "s1_commit" "s2_get_changes"
+
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s1_insert_tbl2" "s2_alter_tbl1_float" "s1_commit" "s2_get_changes"
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s1_insert_tbl2" "s2_alter_tbl1_char" "s1_commit" "s2_get_changes"
+
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_float" "s1_insert_tbl2" "s2_alter_tbl1_float" "s1_commit" "s2_get_changes"
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_char" "s1_insert_tbl2" "s2_alter_tbl1_char" "s1_commit" "s2_get_changes"
+
+permutation "s1_init" "s2_alter_tbl2_char" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_text" "s1_insert_tbl2" "s1_commit" "s2_get_changes"
+permutation "s1_init" "s2_alter_tbl2_char" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_text" "s1_insert_tbl2" "s2_alter_tbl1_char" "s1_commit" "s2_get_changes"
+
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_boolean" "s1_insert_tbl2" "s1_commit" "s2_get_changes"
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_boolean" "s1_insert_tbl2" "s2_alter_tbl1_boolean" "s1_commit" "s2_get_changes"
+
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_add_int" "s1_insert_tbl2_3col" "s1_commit" "s2_get_changes"
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s1_insert_tbl2" "s1_commit" "s1_begin" "s2_alter_tbl2_add_int" "s1_insert_tbl2_3col" "s1_commit" "s2_get_changes"
+
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_add_float" "s1_insert_tbl2_3col" "s1_commit" "s2_get_changes"
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s1_insert_tbl2" "s1_commit" "s1_begin" "s2_alter_tbl2_add_float" "s1_insert_tbl2_3col" "s1_commit" "s2_get_changes"
+
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_add_char" "s1_insert_tbl2_3col" "s1_commit" "s2_get_changes"
+permutation "s1_init" "s1_begin" "s1_insert_tbl1" "s1_insert_tbl2" "s1_commit" "s1_begin" "s2_alter_tbl2_add_char" "s1_insert_tbl2_3col" "s1_commit" "s2_get_changes"
+
+permutation "s1_init" "s2_alter_tbl2_add_int" "s1_begin" "s1_insert_tbl2_3col" "s2_alter_tbl2_drop_3rd_col" "s1_commit" "s2_get_changes"
+permutation "s1_init" "s2_alter_tbl2_add_int" "s1_begin" "s1_insert_tbl2_3col" "s2_alter_tbl2_drop_3rd_col" "s1_insert_tbl2" "s1_commit" "s1_insert_tbl2" "s2_get_changes"
+
+permutation "s1_init" "s2_alter_tbl2_add_int" "s1_begin" "s1_insert_tbl2_3col" "s2_alter_tbl2_drop_3rd_col" "s1_commit" "s2_get_changes" "s2_alter_tbl2_add_text" "s1_begin" "s1_insert_tbl2_3col" "s2_alter_tbl2_3rd_char" "s1_insert_tbl2_3col" "s1_commit" "s2_get_changes" "s2_alter_tbl2_3rd_int" "s1_insert_tbl2_3col" "s2_get_changes"
+
+permutation "s1_init" "s2_alter_tbl2_add_char" "s1_begin" "s1_insert_tbl1" "s1_insert_tbl2_3col" "s2_alter_tbl2_3rd_text" "s1_insert_tbl2_3col" "s1_commit" "s1_insert_tbl2_3col" "s2_get_changes"
+permutation "s1_init" "s2_alter_tbl2_add_text" "s1_begin" "s1_insert_tbl1" "s1_insert_tbl2_3col" "s2_alter_tbl2_3rd_char" "s1_insert_tbl2_3col" "s1_commit" "s1_insert_tbl2_3col" "s2_get_changes"
+
+permutation "s1_init" "s2_alter_tbl2_add_char" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_3rd_text" "s1_insert_tbl2_3col" "s1_commit" "s2_alter_tbl2_drop_3rd_col" "s1_insert_tbl2" "s2_get_changes"
+permutation "s1_init" "s2_alter_tbl2_add_text" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_3rd_char" "s1_insert_tbl2_3col" "s1_commit" "s2_alter_tbl2_drop_3rd_col" "s1_insert_tbl2" "s2_get_changes"
+
+permutation "s1_init" "s2_alter_tbl2_add_char" "s1_begin" "s1_insert_tbl1" "s2_alter_tbl2_drop_3rd_col" "s1_insert_tbl1" "s1_commit" "s2_get_changes"
diff --git a/contrib/test_decoding/specs/delayed_startup.spec b/contrib/test_decoding/specs/delayed_startup.spec
new file mode 100644 (file)
index 0000000..b7fe814
--- /dev/null
@@ -0,0 +1,24 @@
+setup
+{
+    DROP TABLE IF EXISTS do_write;
+    CREATE TABLE do_write(id serial primary key);
+}
+
+teardown
+{
+    DROP TABLE do_write;
+    SELECT 'stop' FROM pg_drop_replication_slot('isolation_slot');
+}
+
+session "s1"
+setup { SET synchronous_commit=on; }
+step "s1b" { BEGIN ISOLATION LEVEL SERIALIZABLE; }
+step "s1w" { INSERT INTO do_write DEFAULT VALUES; }
+step "s1c" { COMMIT; }
+session "s2"
+setup { SET synchronous_commit=on; }
+step "s2init" {SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');}
+step "s2start" {SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false');}
+
+
+permutation "s1b" "s1w" "s2init" "s1c" "s2start" "s1b" "s1w" "s1c" "s2start" "s1b" "s1w" "s2start" "s1c" "s2start"
diff --git a/contrib/test_decoding/specs/mxact.spec b/contrib/test_decoding/specs/mxact.spec
new file mode 100644 (file)
index 0000000..ea5b1aa
--- /dev/null
@@ -0,0 +1,38 @@
+setup
+{
+    DROP TABLE IF EXISTS do_write;
+    CREATE TABLE do_write(id serial primary key);
+}
+
+teardown
+{
+    DROP TABLE IF EXISTS do_write;
+    SELECT 'stop' FROM pg_drop_replication_slot('isolation_slot');
+}
+
+session "s0"
+setup { SET synchronous_commit=on; }
+step "s0init" {SELECT 'init' FROM pg_create_logical_replication_slot('isolation_slot', 'test_decoding');}
+step "s0start" {SELECT data FROM pg_logical_slot_get_changes('isolation_slot', NULL, NULL, 'include-xids', 'false');}
+step "s0alter" {ALTER TABLE do_write ADD column ts timestamptz; }
+step "s0w" { INSERT INTO do_write DEFAULT VALUES; }
+
+session "s1"
+setup { SET synchronous_commit=on; }
+step "s1begin" {BEGIN;}
+step "s1sharepgclass" { SELECT count(*) > 1 FROM (SELECT * FROM pg_class FOR SHARE) s; }
+step "s1keysharepgclass" { SELECT count(*) > 1 FROM (SELECT * FROM pg_class FOR KEY SHARE) s; }
+step "s1commit" {COMMIT;}
+
+session "s2"
+setup { SET synchronous_commit=on; }
+step "s2begin" {BEGIN;}
+step "s2sharepgclass" { SELECT count(*) > 1 FROM (SELECT * FROM pg_class FOR SHARE) s; }
+step "s2keysharepgclass" { SELECT count(*) > 1 FROM (SELECT * FROM pg_class FOR KEY SHARE) s; }
+step "s2commit" {COMMIT;}
+
+# test that we're handling an update-only mxact xmax correctly
+permutation "s0init" "s0start" "s1begin" "s1sharepgclass" "s2begin" "s2sharepgclass" "s0w" "s0start" "s2commit" "s1commit"
+
+# test that we're handling an update-only mxact xmax correctly
+permutation "s0init" "s0start" "s1begin" "s1keysharepgclass" "s2begin" "s2keysharepgclass" "s0alter" "s0w" "s0start" "s2commit" "s1commit"
diff --git a/contrib/test_decoding/sql/binary.sql b/contrib/test_decoding/sql/binary.sql
new file mode 100644 (file)
index 0000000..619f00b
--- /dev/null
@@ -0,0 +1,14 @@
+-- predictability
+SET synchronous_commit = on;
+
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+-- succeeds, textual plugin, textual consumer
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '0');
+-- fails, binary plugin, textual consumer
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'force-binary', '1');
+-- succeeds, textual plugin, binary consumer
+SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '0');
+-- succeeds, binary plugin, binary consumer
+SELECT data FROM pg_logical_slot_get_binary_changes('regression_slot', NULL, NULL, 'force-binary', '1');
+
+SELECT 'init' FROM pg_drop_replication_slot('regression_slot');
diff --git a/contrib/test_decoding/sql/ddl.sql b/contrib/test_decoding/sql/ddl.sql
new file mode 100644 (file)
index 0000000..b4807e9
--- /dev/null
@@ -0,0 +1,337 @@
+-- predictability
+SET synchronous_commit = on;
+
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+-- fail because of an already existing slot
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+-- fail because of an invalid name
+SELECT 'init' FROM pg_create_logical_replication_slot('Invalid Name', 'test_decoding');
+
+-- fail twice because of an invalid parameter values
+SELECT 'init' FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', 'frakbar');
+SELECT 'init' FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'nonexistant-option', 'frakbar');
+SELECT 'init' FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', 'frakbar');
+
+-- succeed once
+SELECT pg_drop_replication_slot('regression_slot');
+-- fail
+SELECT pg_drop_replication_slot('regression_slot');
+
+-- check that we're detecting a streaming rep slot used for logical decoding 
+SELECT 'init' FROM pg_create_physical_replication_slot('repl');
+SELECT data FROM pg_logical_slot_get_changes('repl', NULL, NULL, 'include-xids', '0');
+SELECT pg_drop_replication_slot('repl');
+
+
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+
+/* check whether status function reports us, only reproduceable columns */
+SELECT slot_name, plugin, slot_type, active,
+    NOT catalog_xmin IS NULL AS catalog_xmin_set,
+    xmin IS NULl  AS data_xmin_not_set,
+    pg_xlog_location_diff(restart_lsn, '0/01000000') > 0 AS some_wal
+FROM pg_replication_slots;
+
+/*
+ * Check that changes are handled correctly when interleaved with ddl
+ */
+CREATE TABLE replication_example(id SERIAL PRIMARY KEY, somedata int, text varchar(120));
+BEGIN;
+INSERT INTO replication_example(somedata, text) VALUES (1, 1);
+INSERT INTO replication_example(somedata, text) VALUES (1, 2);
+COMMIT;
+
+ALTER TABLE replication_example ADD COLUMN bar int;
+
+INSERT INTO replication_example(somedata, text, bar) VALUES (2, 1, 4);
+
+BEGIN;
+INSERT INTO replication_example(somedata, text, bar) VALUES (2, 2, 4);
+INSERT INTO replication_example(somedata, text, bar) VALUES (2, 3, 4);
+INSERT INTO replication_example(somedata, text, bar) VALUES (2, 4, NULL);
+COMMIT;
+
+ALTER TABLE replication_example DROP COLUMN bar;
+INSERT INTO replication_example(somedata, text) VALUES (3, 1);
+
+BEGIN;
+INSERT INTO replication_example(somedata, text) VALUES (3, 2);
+INSERT INTO replication_example(somedata, text) VALUES (3, 3);
+COMMIT;
+
+ALTER TABLE replication_example RENAME COLUMN text TO somenum;
+
+INSERT INTO replication_example(somedata, somenum) VALUES (4, 1);
+
+-- collect all changes
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+ALTER TABLE replication_example ALTER COLUMN somenum TYPE int4 USING (somenum::int4);
+-- throw away changes, they contain oids
+SELECT count(data) FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+INSERT INTO replication_example(somedata, somenum) VALUES (5, 1);
+
+BEGIN;
+INSERT INTO replication_example(somedata, somenum) VALUES (6, 1);
+ALTER TABLE replication_example ADD COLUMN zaphod1 int;
+INSERT INTO replication_example(somedata, somenum, zaphod1) VALUES (6, 2, 1);
+ALTER TABLE replication_example ADD COLUMN zaphod2 int;
+INSERT INTO replication_example(somedata, somenum, zaphod2) VALUES (6, 3, 1);
+INSERT INTO replication_example(somedata, somenum, zaphod1) VALUES (6, 4, 2);
+COMMIT;
+
+-- show changes
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+-- hide changes bc of oid visible in full table rewrites
+CREATE TABLE tr_unique(id2 serial unique NOT NULL, data int);
+INSERT INTO tr_unique(data) VALUES(10);
+ALTER TABLE tr_unique RENAME TO tr_pkey;
+ALTER TABLE tr_pkey ADD COLUMN id serial primary key;
+SELECT count(data) FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+INSERT INTO tr_pkey(data) VALUES(1);
+--show deletion with primary key
+DELETE FROM tr_pkey;
+
+/* display results */
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+/*
+ * check that disk spooling works
+ */
+BEGIN;
+CREATE TABLE tr_etoomuch (id serial primary key, data int);
+INSERT INTO tr_etoomuch(data) SELECT g.i FROM generate_series(1, 10234) g(i);
+DELETE FROM tr_etoomuch WHERE id < 5000;
+UPDATE tr_etoomuch SET data = - data WHERE id > 5000;
+COMMIT;
+
+/* display results, but hide most of the output */
+SELECT count(*), min(data), max(data)
+FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0')
+GROUP BY substring(data, 1, 24)
+ORDER BY 1;
+
+/*
+ * check whether we decode subtransactions correctly in relation with each
+ * other
+ */
+CREATE TABLE tr_sub (id serial primary key, path text);
+
+-- toplevel, subtxn, toplevel, subtxn, subtxn
+BEGIN;
+INSERT INTO tr_sub(path) VALUES ('1-top-#1');
+
+SAVEPOINT a;
+INSERT INTO tr_sub(path) VALUES ('1-top-1-#1');
+INSERT INTO tr_sub(path) VALUES ('1-top-1-#2');
+RELEASE SAVEPOINT a;
+
+SAVEPOINT b;
+SAVEPOINT c;
+INSERT INTO tr_sub(path) VALUES ('1-top-2-1-#1');
+INSERT INTO tr_sub(path) VALUES ('1-top-2-1-#2');
+RELEASE SAVEPOINT c;
+INSERT INTO tr_sub(path) VALUES ('1-top-2-#1');
+RELEASE SAVEPOINT b;
+COMMIT;
+
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+-- check that we handle xlog assignments correctly
+BEGIN;
+-- nest 80 subtxns
+SAVEPOINT subtop;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;SAVEPOINT a;
+-- assign xid by inserting
+INSERT INTO tr_sub(path) VALUES ('2-top-1...--#1');
+INSERT INTO tr_sub(path) VALUES ('2-top-1...--#2');
+INSERT INTO tr_sub(path) VALUES ('2-top-1...--#3');
+RELEASE SAVEPOINT subtop;
+INSERT INTO tr_sub(path) VALUES ('2-top-#1');
+COMMIT;
+
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+-- make sure rollbacked subtransactions aren't decoded
+BEGIN;
+INSERT INTO tr_sub(path) VALUES ('3-top-2-#1');
+SAVEPOINT a;
+INSERT INTO tr_sub(path) VALUES ('3-top-2-1-#1');
+SAVEPOINT b;
+INSERT INTO tr_sub(path) VALUES ('3-top-2-2-#1');
+ROLLBACK TO SAVEPOINT b;
+INSERT INTO tr_sub(path) VALUES ('3-top-2-#2');
+COMMIT;
+
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+-- test whether a known, but not yet logged toplevel xact, followed by a
+-- subxact commit is handled correctly
+BEGIN;
+SELECT txid_current() != 0; -- so no fixed xid apears in the outfile
+SAVEPOINT a;
+INSERT INTO tr_sub(path) VALUES ('4-top-1-#1');
+RELEASE SAVEPOINT a;
+COMMIT;
+
+-- test whether a change in a subtransaction, in an unknown toplevel
+-- xact is handled correctly.
+BEGIN;
+SAVEPOINT a;
+INSERT INTO tr_sub(path) VALUES ('5-top-1-#1');
+COMMIT;
+
+
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+
+/*
+ * Check whether treating a table as a catalog table works somewhat
+ */
+CREATE TABLE replication_metadata (
+    id serial primary key,
+    relation name NOT NULL,
+    options text[]
+)
+WITH (user_catalog_table = true)
+;
+\d+ replication_metadata
+
+INSERT INTO replication_metadata(relation, options)
+VALUES ('foo', ARRAY['a', 'b']);
+
+ALTER TABLE replication_metadata RESET (user_catalog_table);
+\d+ replication_metadata
+
+INSERT INTO replication_metadata(relation, options)
+VALUES ('bar', ARRAY['a', 'b']);
+
+ALTER TABLE replication_metadata SET (user_catalog_table = true);
+\d+ replication_metadata
+
+INSERT INTO replication_metadata(relation, options)
+VALUES ('blub', NULL);
+
+-- make sure rewrites don't work
+ALTER TABLE replication_metadata ADD COLUMN rewritemeornot int;
+ALTER TABLE replication_metadata ALTER COLUMN rewritemeornot TYPE text;
+
+ALTER TABLE replication_metadata SET (user_catalog_table = false);
+\d+ replication_metadata
+
+INSERT INTO replication_metadata(relation, options)
+VALUES ('zaphod', NULL);
+
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+/*
+ * check whether we handle updates/deletes correct with & without a pkey
+ */
+
+/* we should handle the case without a key at all more gracefully */
+CREATE TABLE table_without_key(id serial, data int);
+INSERT INTO table_without_key(data) VALUES(1),(2);
+DELETE FROM table_without_key WHERE data = 1;
+-- won't log old keys
+UPDATE table_without_key SET data = 3 WHERE data = 2;
+UPDATE table_without_key SET id = -id;
+UPDATE table_without_key SET id = -id;
+-- should log the full old row now
+ALTER TABLE table_without_key REPLICA IDENTITY FULL;
+UPDATE table_without_key SET data = 3 WHERE data = 2;
+UPDATE table_without_key SET id = -id;
+UPDATE table_without_key SET id = -id;
+DELETE FROM table_without_key WHERE data = 3;
+
+CREATE TABLE table_with_pkey(id serial primary key, data int);
+INSERT INTO table_with_pkey(data) VALUES(1), (2);
+DELETE FROM table_with_pkey WHERE data = 1;
+-- should log the old pkey
+UPDATE table_with_pkey SET data = 3 WHERE data = 2;
+UPDATE table_with_pkey SET id = -id;
+UPDATE table_with_pkey SET id = -id;
+-- check that we log nothing despite having a pkey
+ALTER TABLE table_without_key REPLICA IDENTITY NOTHING;
+UPDATE table_with_pkey SET id = -id;
+-- check that we log everything despite having a pkey
+ALTER TABLE table_without_key REPLICA IDENTITY FULL;
+UPDATE table_with_pkey SET id = -id;
+DELETE FROM table_with_pkey WHERE data = 3;
+
+CREATE TABLE table_with_unique_not_null(id serial unique, data int);
+ALTER TABLE table_with_unique_not_null ALTER COLUMN id SET NOT NULL; --already set
+-- won't log anything, replica identity not setup
+INSERT INTO table_with_unique_not_null(data) VALUES(1), (2);
+DELETE FROM table_with_unique_not_null WHERE data = 1;
+UPDATE table_with_unique_not_null SET data = 3 WHERE data = 2;
+UPDATE table_with_unique_not_null SET id = -id;
+UPDATE table_with_unique_not_null SET id = -id;
+DELETE FROM table_with_unique_not_null WHERE data = 3;
+-- should log old key
+ALTER TABLE table_with_unique_not_null REPLICA IDENTITY USING INDEX table_with_unique_not_null_id_key;
+INSERT INTO table_with_unique_not_null(data) VALUES(1), (2);
+DELETE FROM table_with_unique_not_null WHERE data = 1;
+UPDATE table_with_unique_not_null SET data = 3 WHERE data = 2;
+UPDATE table_with_unique_not_null SET id = -id;
+UPDATE table_with_unique_not_null SET id = -id;
+DELETE FROM table_with_unique_not_null WHERE data = 3;
+
+-- check toast support
+BEGIN;
+CREATE SEQUENCE toasttable_rand_seq START 79 INCREMENT 1499; -- portable "random"
+CREATE TABLE toasttable(
+       id serial primary key,
+       toasted_col1 text,
+       rand1 float8 DEFAULT nextval('toasttable_rand_seq'),
+       toasted_col2 text,
+       rand2 float8 DEFAULT nextval('toasttable_rand_seq')
+       );
+COMMIT;
+-- uncompressed external toast data
+INSERT INTO toasttable(toasted_col1) SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i);
+
+-- compressed external toast data
+INSERT INTO toasttable(toasted_col2) SELECT repeat(string_agg(to_char(g.i, 'FM0000'), ''), 50) FROM generate_series(1, 500) g(i);
+
+-- update of existing column
+UPDATE toasttable
+    SET toasted_col1 = (SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i))
+WHERE id = 1;
+
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+INSERT INTO toasttable(toasted_col1) SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i);
+
+-- update of second column, first column unchanged
+UPDATE toasttable
+    SET toasted_col2 = (SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i))
+WHERE id = 1;
+
+-- make sure we decode correctly even if the toast table is gone
+DROP TABLE toasttable;
+
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+-- done, free logical replication slot
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+SELECT pg_drop_replication_slot('regression_slot');
+
+/* check that we aren't visible anymore now */
+SELECT * FROM pg_stat_replication;
diff --git a/contrib/test_decoding/sql/decoding_in_xact.sql b/contrib/test_decoding/sql/decoding_in_xact.sql
new file mode 100644 (file)
index 0000000..2771afe
--- /dev/null
@@ -0,0 +1,41 @@
+-- predictability
+SET synchronous_commit = on;
+
+-- fail because we're creating a slot while in an xact with xid
+BEGIN;
+SELECT txid_current() = 0;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ROLLBACK;
+
+-- fail because we're creating a slot while in an subxact whose topxact has a xid
+BEGIN;
+SELECT txid_current() = 0;
+SAVEPOINT barf;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+ROLLBACK TO SAVEPOINT barf;
+ROLLBACK;
+
+-- succeed, outside tx.
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+SELECT 'stop' FROM pg_drop_replication_slot('regression_slot');
+
+-- succeed, in tx without xid.
+BEGIN;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+COMMIT;
+
+CREATE TABLE nobarf(id serial primary key, data text);
+INSERT INTO nobarf(data) VALUES('1');
+
+-- decoding works in transaction with xid
+BEGIN;
+SELECT txid_current() = 0;
+-- don't show yet, haven't committed
+INSERT INTO nobarf(data) VALUES('2');
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+COMMIT;
+
+INSERT INTO nobarf(data) VALUES('3');
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+SELECT 'stop' FROM pg_drop_replication_slot('regression_slot');
diff --git a/contrib/test_decoding/sql/permissions.sql b/contrib/test_decoding/sql/permissions.sql
new file mode 100644 (file)
index 0000000..39d70b5
--- /dev/null
@@ -0,0 +1,69 @@
+-- predictability
+SET synchronous_commit = on;
+
+-- setup
+CREATE ROLE lr_normal;
+CREATE ROLE lr_superuser SUPERUSER;
+CREATE ROLE lr_replication REPLICATION;
+CREATE TABLE lr_test(data text);
+
+-- superuser can control replication
+SET ROLE lr_superuser;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+INSERT INTO lr_test VALUES('lr_superuser_init');
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+SELECT pg_drop_replication_slot('regression_slot');
+RESET ROLE;
+
+-- replication user can control replication
+SET ROLE lr_replication;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+INSERT INTO lr_test VALUES('lr_superuser_init');
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+SELECT pg_drop_replication_slot('regression_slot');
+RESET ROLE;
+
+-- plain user *can't* can control replication
+SET ROLE lr_normal;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+INSERT INTO lr_test VALUES('lr_superuser_init');
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+SELECT pg_drop_replication_slot('regression_slot');
+RESET ROLE;
+
+-- replication users can drop superuser created slots
+SET ROLE lr_superuser;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+RESET ROLE;
+SET ROLE lr_replication;
+SELECT pg_drop_replication_slot('regression_slot');
+RESET ROLE;
+
+-- normal users can't drop existing slots
+SET ROLE lr_superuser;
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+RESET ROLE;
+SET ROLE lr_normal;
+SELECT pg_drop_replication_slot('regression_slot');
+RESET ROLE;
+
+-- all users can see existing slots
+SET ROLE lr_superuser;
+SELECT slot_name, plugin FROM pg_replication_slots;
+RESET ROLE;
+
+SET ROLE lr_replication;
+SELECT slot_name, plugin FROM pg_replication_slots;
+RESET ROLE;
+
+SET ROLE lr_normal;
+SELECT slot_name, plugin FROM pg_replication_slots;
+RESET ROLE;
+
+-- cleanup
+SELECT pg_drop_replication_slot('regression_slot');
+
+DROP ROLE lr_normal;
+DROP ROLE lr_superuser;
+DROP ROLE lr_replication;
+DROP TABLE lr_test;
diff --git a/contrib/test_decoding/sql/rewrite.sql b/contrib/test_decoding/sql/rewrite.sql
new file mode 100644 (file)
index 0000000..9a3dcbf
--- /dev/null
@@ -0,0 +1,62 @@
+-- predictability
+SET synchronous_commit = on;
+
+DROP TABLE IF EXISTS replication_example;
+
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+CREATE TABLE replication_example(id SERIAL PRIMARY KEY, somedata int, text varchar(120));
+INSERT INTO replication_example(somedata) VALUES (1);
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+
+BEGIN;
+INSERT INTO replication_example(somedata) VALUES (2);
+ALTER TABLE replication_example ADD COLUMN testcolumn1 int;
+INSERT INTO replication_example(somedata, testcolumn1) VALUES (3,  1);
+COMMIT;
+
+BEGIN;
+INSERT INTO replication_example(somedata) VALUES (3);
+ALTER TABLE replication_example ADD COLUMN testcolumn2 int;
+INSERT INTO replication_example(somedata, testcolumn1, testcolumn2) VALUES (4,  2, 1);
+COMMIT;
+
+VACUUM FULL pg_am;
+VACUUM FULL pg_amop;
+VACUUM FULL pg_proc;
+VACUUM FULL pg_opclass;
+VACUUM FULL pg_type;
+VACUUM FULL pg_index;
+VACUUM FULL pg_database;
+
+-- repeated rewrites that fail
+BEGIN;
+CLUSTER pg_class USING pg_class_oid_index;
+CLUSTER pg_class USING pg_class_oid_index;
+ROLLBACK;
+
+-- repeated rewrites that succeed
+BEGIN;
+CLUSTER pg_class USING pg_class_oid_index;
+CLUSTER pg_class USING pg_class_oid_index;
+CLUSTER pg_class USING pg_class_oid_index;
+COMMIT;
+
+ -- repeated rewrites in different transactions
+VACUUM FULL pg_class;
+VACUUM FULL pg_class;
+
+INSERT INTO replication_example(somedata, testcolumn1) VALUES (5, 3);
+
+BEGIN;
+INSERT INTO replication_example(somedata, testcolumn1) VALUES (6, 4);
+ALTER TABLE replication_example ADD COLUMN testcolumn3 int;
+INSERT INTO replication_example(somedata, testcolumn1, testcolumn3) VALUES (7, 5, 1);
+COMMIT;
+
+-- make old files go away
+CHECKPOINT;
+
+SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+SELECT pg_drop_replication_slot('regression_slot');
+
+DROP TABLE IF EXISTS replication_example;
diff --git a/contrib/test_decoding/sql/toast.sql b/contrib/test_decoding/sql/toast.sql
new file mode 100644 (file)
index 0000000..943db9d
--- /dev/null
@@ -0,0 +1,51 @@
+-- predictability
+SET synchronous_commit = on;
+
+DROP TABLE IF EXISTS xpto;
+
+SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
+
+CREATE SEQUENCE xpto_rand_seq START 79 INCREMENT 1499; -- portable "random"
+CREATE TABLE xpto (
+    id serial primary key,
+    toasted_col1 text,
+    rand1 float8 DEFAULT nextval('xpto_rand_seq'),
+    toasted_col2 text,
+    rand2 float8 DEFAULT nextval('xpto_rand_seq')
+);
+
+-- uncompressed external toast data
+INSERT INTO xpto (toasted_col1, toasted_col2) SELECT string_agg(g.i::text, ''), string_agg((g.i*2)::text, '') FROM generate_series(1, 2000) g(i);
+
+-- compressed external toast data
+INSERT INTO xpto (toasted_col2) SELECT repeat(string_agg(to_char(g.i, 'FM0000'), ''), 50) FROM generate_series(1, 500) g(i);
+
+-- update of existing column
+UPDATE xpto SET toasted_col1 = (SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i)) WHERE id = 1;
+
+UPDATE xpto SET rand1 = 123.456 WHERE id = 1;
+
+DELETE FROM xpto WHERE id = 1;
+
+DROP TABLE IF EXISTS toasted_key;
+CREATE TABLE toasted_key (
+    id serial,
+    toasted_key text PRIMARY KEY,
+    toasted_col1 text,
+    toasted_col2 text
+);
+
+ALTER TABLE toasted_key ALTER COLUMN toasted_key SET STORAGE EXTERNAL;
+ALTER TABLE toasted_key ALTER COLUMN toasted_col1 SET STORAGE EXTERNAL;
+
+INSERT INTO toasted_key(toasted_key, toasted_col1) VALUES(repeat('1234567890', 200), repeat('9876543210', 200));
+
+-- test update of a toasted key without changing it
+UPDATE toasted_key SET toasted_col2 = toasted_col1;
+-- test update of a toasted key, changing it
+UPDATE toasted_key SET toasted_key = toasted_key || '1';
+
+DELETE FROM toasted_key;
+
+SELECT substr(data, 1, 200) FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0');
+SELECT pg_drop_replication_slot('regression_slot');
diff --git a/contrib/test_decoding/test_decoding.c b/contrib/test_decoding/test_decoding.c
new file mode 100644 (file)
index 0000000..ea463fb
--- /dev/null
@@ -0,0 +1,404 @@
+/*-------------------------------------------------------------------------
+ *
+ * test_decoding.c
+ *       example logical decoding output plugin
+ *
+ * Copyright (c) 2012-2014, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *       contrib/test_decoding/test_decoding.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/sysattr.h"
+
+#include "catalog/pg_class.h"
+#include "catalog/pg_type.h"
+
+#include "nodes/parsenodes.h"
+
+#include "replication/output_plugin.h"
+#include "replication/logical.h"
+
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/rel.h"
+#include "utils/relcache.h"
+#include "utils/syscache.h"
+#include "utils/typcache.h"
+
+
+PG_MODULE_MAGIC;
+
+extern void        _PG_init(void);
+extern void        _PG_output_plugin_init(OutputPluginCallbacks *cb);
+
+typedef struct
+{
+   MemoryContext context;
+   bool        include_xids;
+   bool        include_timestamp;
+} TestDecodingData;
+
+/* These must be available to pg_dlsym() */
+static void pg_decode_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt,
+                             bool is_init);
+static void pg_decode_shutdown(LogicalDecodingContext *ctx);
+static void pg_decode_begin_txn(LogicalDecodingContext *ctx,
+                   ReorderBufferTXN *txn);
+static void pg_decode_commit_txn(LogicalDecodingContext *ctx,
+                    ReorderBufferTXN *txn, XLogRecPtr commit_lsn);
+static void pg_decode_change(LogicalDecodingContext *ctx,
+                ReorderBufferTXN *txn, Relation rel,
+                ReorderBufferChange *change);
+
+void
+_PG_init(void)
+{
+   /* other plugins can perform things here */
+}
+
+/* specify output plugin callbacks */
+void
+_PG_output_plugin_init(OutputPluginCallbacks *cb)
+{
+   AssertVariableIsOfType(&_PG_output_plugin_init, LogicalOutputPluginInit);
+
+   cb->startup_cb = pg_decode_startup;
+   cb->begin_cb = pg_decode_begin_txn;
+   cb->change_cb = pg_decode_change;
+   cb->commit_cb = pg_decode_commit_txn;
+   cb->shutdown_cb = pg_decode_shutdown;
+}
+
+
+/* initialize this plugin */
+static void
+pg_decode_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt,
+                 bool is_init)
+{
+   ListCell   *option;
+   TestDecodingData *data;
+
+   data = palloc(sizeof(TestDecodingData));
+   data->context = AllocSetContextCreate(ctx->context,
+                                         "text conversion context",
+                                         ALLOCSET_DEFAULT_MINSIZE,
+                                         ALLOCSET_DEFAULT_INITSIZE,
+                                         ALLOCSET_DEFAULT_MAXSIZE);
+   data->include_xids = true;
+   data->include_timestamp = false;
+
+   ctx->output_plugin_private = data;
+
+   opt->output_type = OUTPUT_PLUGIN_TEXTUAL_OUTPUT;
+
+   foreach(option, ctx->output_plugin_options)
+   {
+       DefElem    *elem = lfirst(option);
+
+       Assert(elem->arg == NULL || IsA(elem->arg, String));
+
+       if (strcmp(elem->defname, "include-xids") == 0)
+       {
+           /* if option does not provide a value, it means its value is true */
+           if (elem->arg == NULL)
+               data->include_xids = true;
+           else if (!parse_bool(strVal(elem->arg), &data->include_xids))
+               ereport(ERROR,
+                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                        errmsg("could not parse value \"%s\" for parameter \"%s\"",
+                               strVal(elem->arg), elem->defname)));
+       }
+       else if (strcmp(elem->defname, "include-timestamp") == 0)
+       {
+           if (elem->arg == NULL)
+               data->include_timestamp = true;
+           else if (!parse_bool(strVal(elem->arg), &data->include_timestamp))
+               ereport(ERROR,
+                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                        errmsg("could not parse value \"%s\" for parameter \"%s\"",
+                               strVal(elem->arg), elem->defname)));
+       }
+       else if (strcmp(elem->defname, "force-binary") == 0)
+       {
+           bool force_binary;
+
+           if (elem->arg == NULL)
+               continue;
+           else if (!parse_bool(strVal(elem->arg), &force_binary))
+               ereport(ERROR,
+                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                        errmsg("could not parse value \"%s\" for parameter \"%s\"",
+                               strVal(elem->arg), elem->defname)));
+
+           if (force_binary)
+               opt->output_type = OUTPUT_PLUGIN_BINARY_OUTPUT;
+       }
+       else
+       {
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("option \"%s\" = \"%s\" is unknown",
+                           elem->defname,
+                           elem->arg ? strVal(elem->arg) : "(null)")));
+       }
+   }
+}
+
+/* cleanup this plugin's resources */
+static void
+pg_decode_shutdown(LogicalDecodingContext *ctx)
+{
+   TestDecodingData *data = ctx->output_plugin_private;
+
+   /* cleanup our own resources via memory context reset */
+   MemoryContextDelete(data->context);
+}
+
+/* BEGIN callback */
+static void
+pg_decode_begin_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn)
+{
+   TestDecodingData *data = ctx->output_plugin_private;
+
+   OutputPluginPrepareWrite(ctx, true);
+   if (data->include_xids)
+       appendStringInfo(ctx->out, "BEGIN %u", txn->xid);
+   else
+       appendStringInfoString(ctx->out, "BEGIN");
+   OutputPluginWrite(ctx, true);
+}
+
+/* COMMIT callback */
+static void
+pg_decode_commit_txn(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
+                    XLogRecPtr commit_lsn)
+{
+   TestDecodingData *data = ctx->output_plugin_private;
+
+   OutputPluginPrepareWrite(ctx, true);
+   if (data->include_xids)
+       appendStringInfo(ctx->out, "COMMIT %u", txn->xid);
+   else
+       appendStringInfoString(ctx->out, "COMMIT");
+
+   if (data->include_timestamp)
+       appendStringInfo(ctx->out, " (at %s)",
+                        timestamptz_to_str(txn->commit_time));
+
+   OutputPluginWrite(ctx, true);
+}
+
+/*
+ * Print literal `outputstr' already represented as string of type `typid'
+ * into stringbuf `s'.
+ *
+ * Some builtin types aren't quoted, the rest is quoted. Escaping is done as
+ * if standard_conforming_strings were enabled.
+ */
+static void
+print_literal(StringInfo s, Oid typid, char *outputstr)
+{
+   const char *valptr;
+
+   switch (typid)
+   {
+       case INT2OID:
+       case INT4OID:
+       case INT8OID:
+       case OIDOID:
+       case FLOAT4OID:
+       case FLOAT8OID:
+       case NUMERICOID:
+           /* NB: We don't care about Inf, NaN et al. */
+           appendStringInfoString(s, outputstr);
+           break;
+
+       case BITOID:
+       case VARBITOID:
+           appendStringInfo(s, "B'%s'", outputstr);
+           break;
+
+       case BOOLOID:
+           if (strcmp(outputstr, "t") == 0)
+               appendStringInfoString(s, "true");
+           else
+               appendStringInfoString(s, "false");
+           break;
+
+       default:
+           appendStringInfoChar(s, '\'');
+           for (valptr = outputstr; *valptr; valptr++)
+           {
+               char        ch = *valptr;
+
+               if (SQL_STR_DOUBLE(ch, false))
+                   appendStringInfoChar(s, ch);
+               appendStringInfoChar(s, ch);
+           }
+           appendStringInfoChar(s, '\'');
+           break;
+   }
+}
+
+/* print the tuple 'tuple' into the StringInfo s */
+static void
+tuple_to_stringinfo(StringInfo s, TupleDesc tupdesc, HeapTuple tuple, bool skip_nulls)
+{
+   int         natt;
+   Oid         oid;
+
+   /* print oid of tuple, it's not included in the TupleDesc */
+   if ((oid = HeapTupleHeaderGetOid(tuple->t_data)) != InvalidOid)
+   {
+       appendStringInfo(s, " oid[oid]:%u", oid);
+   }
+
+   /* print all columns individually */
+   for (natt = 0; natt < tupdesc->natts; natt++)
+   {
+       Form_pg_attribute attr; /* the attribute itself */
+       Oid         typid;      /* type of current attribute */
+       Oid         typoutput;  /* output function */
+       bool        typisvarlena;
+       Datum       origval;    /* possibly toasted Datum */
+       bool        isnull;     /* column is null? */
+
+       attr = tupdesc->attrs[natt];
+
+       /*
+        * don't print dropped columns, we can't be sure everything is
+        * available for them
+        */
+       if (attr->attisdropped)
+           continue;
+
+       /*
+        * Don't print system columns, oid will already have been printed if
+        * present.
+        */
+       if (attr->attnum < 0)
+           continue;
+
+       typid = attr->atttypid;
+
+       /* get Datum from tuple */
+       origval = fastgetattr(tuple, natt + 1, tupdesc, &isnull);
+
+       if (isnull && skip_nulls)
+           continue;
+
+       /* print attribute name */
+       appendStringInfoChar(s, ' ');
+       appendStringInfoString(s, quote_identifier(NameStr(attr->attname)));
+
+       /* print attribute type */
+       appendStringInfoChar(s, '[');
+       appendStringInfoString(s, format_type_be(typid));
+       appendStringInfoChar(s, ']');
+
+       /* query output function */
+       getTypeOutputInfo(typid,
+                         &typoutput, &typisvarlena);
+
+       /* print separator */
+       appendStringInfoChar(s, ':');
+
+       /* print data */
+       if (isnull)
+           appendStringInfoString(s, "null");
+       else if (typisvarlena && VARATT_IS_EXTERNAL_ONDISK(origval))
+           appendStringInfoString(s, "unchanged-toast-datum");
+       else if (!typisvarlena)
+           print_literal(s, typid,
+                         OidOutputFunctionCall(typoutput, origval));
+       else
+       {
+           Datum       val;        /* definitely detoasted Datum */
+           val = PointerGetDatum(PG_DETOAST_DATUM(origval));
+           print_literal(s, typid, OidOutputFunctionCall(typoutput, val));
+       }
+   }
+}
+
+/*
+ * callback for individual changed tuples
+ */
+static void
+pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
+                Relation relation, ReorderBufferChange *change)
+{
+   TestDecodingData *data;
+   Form_pg_class class_form;
+   TupleDesc   tupdesc;
+   MemoryContext old;
+
+   data = ctx->output_plugin_private;
+   class_form = RelationGetForm(relation);
+   tupdesc = RelationGetDescr(relation);
+
+   /* Avoid leaking memory by using and resetting our own context */
+   old = MemoryContextSwitchTo(data->context);
+
+   OutputPluginPrepareWrite(ctx, true);
+
+   appendStringInfoString(ctx->out, "table ");
+   appendStringInfoString(ctx->out,
+                          quote_qualified_identifier(
+                              get_namespace_name(
+                                  get_rel_namespace(RelationGetRelid(relation))),
+                              NameStr(class_form->relname)));
+   appendStringInfoString(ctx->out, ":");
+
+   switch (change->action)
+   {
+       case REORDER_BUFFER_CHANGE_INSERT:
+           appendStringInfoString(ctx->out, " INSERT:");
+           if (change->tp.newtuple == NULL)
+               appendStringInfoString(ctx->out, " (no-tuple-data)");
+           else
+               tuple_to_stringinfo(ctx->out, tupdesc,
+                                   &change->tp.newtuple->tuple,
+                                   false);
+           break;
+       case REORDER_BUFFER_CHANGE_UPDATE:
+           appendStringInfoString(ctx->out, " UPDATE:");
+           if (change->tp.oldtuple != NULL)
+           {
+               appendStringInfoString(ctx->out, " old-key:");
+               tuple_to_stringinfo(ctx->out, tupdesc,
+                                   &change->tp.oldtuple->tuple,
+                                   true);
+               appendStringInfoString(ctx->out, " new-tuple:");
+           }
+
+           if (change->tp.newtuple == NULL)
+               appendStringInfoString(ctx->out, " (no-tuple-data)");
+           else
+               tuple_to_stringinfo(ctx->out, tupdesc,
+                                   &change->tp.newtuple->tuple,
+                                   false);
+           break;
+       case REORDER_BUFFER_CHANGE_DELETE:
+           appendStringInfoString(ctx->out, " DELETE:");
+
+           /* if there was no PK, we only know that a delete happened */
+           if (change->tp.oldtuple == NULL)
+               appendStringInfoString(ctx->out, " (no-tuple-data)");
+           /* In DELETE, only the replica identity is present; display that */
+           else
+               tuple_to_stringinfo(ctx->out, tupdesc,
+                                   &change->tp.oldtuple->tuple,
+                                   true);
+           break;
+   }
+
+   MemoryContextSwitchTo(old);
+   MemoryContextReset(data->context);
+
+   OutputPluginWrite(ctx, true);
+}
index 336ba0c56439ec12d3c3fc1a18a450b2db9fb437..ec68f10b65c8c32e08295fbc038e21e387c87063 100644 (file)
@@ -140,6 +140,7 @@ CREATE EXTENSION module_name FROM unpackaged;
  &sslinfo;
  &tablefunc;
  &tcn;
+ &test-decoding;
  &test-parser;
  &test-shm-mq;
  &tsearch2;
index 09de4bd0518d5a5131eec6d710bd3a2e9022e421..0e863ee064e11f7fb40494b4576506e68068cab8 100644 (file)
 
 
 
+
 
 
 
diff --git a/doc/src/sgml/test-decoding.sgml b/doc/src/sgml/test-decoding.sgml
new file mode 100644 (file)
index 0000000..0fe3d0a
--- /dev/null
@@ -0,0 +1,42 @@
+
+
+
test_decoding
+
+  test_decoding
+
+  test_decoding is an example of a logical decoding
+  output plugin. It doesn't do anything especially useful, but can serve as
+  a starting point for developing your own decoder.
+
+  test_decoding receives WAL through the logical decoding
+  mechanism and decodes it into text representations of the operations
+  performed.
+
+  Typical output from this plugin, used over the SQL logical decoding
+  interface, might be:
+
+  
+postgres=# SELECT * FROM pg_logical_slot_get_changes('test_slot', 'now', 'include-xids', '0');
+ location  | xid |                       data
+-----------+-----+--------------------------------------------------
+ 0/16D30F8 | 691 | BEGIN
+ 0/16D32A0 | 691 | table public.data: INSERT: id[int4]:2 data[text]:'arg'
+ 0/16D32A0 | 691 | table public.data: INSERT: id[int4]:3 data[text]:'demo'
+ 0/16D32A0 | 691 | COMMIT
+ 0/16D32D8 | 692 | BEGIN
+ 0/16D3398 | 692 | table public.data: DELETE: id[int4]:2
+ 0/16D3398 | 692 | table public.data: DELETE: id[int4]:3
+ 0/16D3398 | 692 | COMMIT
+(8 rows)
+  
+
+
index 209d1bdf4dc3908fbc8d7ad560a1200cf2427bcf..cdddf492f459e7dc7dfcd9a4823bf4d2c1fc39bc 100644 (file)
@@ -468,6 +468,8 @@ pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir
 
 pg_regress_clean_files = results/ regression.diffs regression.out tmp_check/ log/
 
+pg_isolation_regress_check = $(top_builddir)/src/test/isolation/pg_isolation_regress --inputdir=$(srcdir) --temp-install=./tmp_check --top-builddir=$(top_builddir) $(pg_regress_locale_flags)
+pg_isolation_regress_installcheck = $(top_builddir)/src/test/isolation/pg_isolation_regress --inputdir=$(srcdir) --top-builddir=$(top_builddir) $(pg_regress_locale_flags)
 
 ##########################################################################
 #
index de4befa93f461988abc65b9b20b89a673e1d26c2..71ec74015cdc60cf6a21040c9142cdbac4c214da 100644 (file)
@@ -347,8 +347,7 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
    /*
     * Prune and repair fragmentation for the whole page, if possible.
     */
-   Assert(TransactionIdIsValid(RecentGlobalXmin));
-   heap_page_prune_opt(scan->rs_rd, buffer, RecentGlobalXmin);
+   heap_page_prune_opt(scan->rs_rd, buffer);
 
    /*
     * We must hold share lock on the buffer content while examining tuple
@@ -1750,10 +1749,22 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
         */
        if (!skip)
        {
+           /*
+            * For the benefit of logical decoding, have t_self point at the
+            * element of the HOT chain we're currently investigating instead
+            * of the root tuple of the HOT chain. This is important because
+            * the *Satisfies routine for historical mvcc snapshots needs the
+            * correct tid to decide about the visibility in some cases.
+            */
+           ItemPointerSet(&(heapTuple->t_self), BufferGetBlockNumber(buffer), offnum);
+
            /* If it's visible per the snapshot, we must return it */
            valid = HeapTupleSatisfiesVisibility(heapTuple, snapshot, buffer);
            CheckForSerializableConflictOut(valid, relation, heapTuple,
                                            buffer, snapshot);
+           /* reset to original, non-redirected, tid */
+           heapTuple->t_self = *tid;
+
            if (valid)
            {
                ItemPointerSetOffsetNumber(tid, offnum);
@@ -8207,6 +8218,9 @@ heap2_redo(XLogRecPtr lsn, XLogRecord *record)
             * decoding.
             */
            break;
+       case XLOG_HEAP2_REWRITE:
+           heap_xlog_logical_rewrite(lsn, record);
+           break;
        default:
            elog(PANIC, "heap2_redo: unknown op code %u", info);
    }
index 27cbac85256fb7034727ac627338d20e93e600bb..3c69e1badac8ed8424766b9d53821fd95cfc9cdd 100644 (file)
 #include "access/heapam_xlog.h"
 #include "access/transam.h"
 #include "access/htup_details.h"
+#include "catalog/catalog.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "storage/bufmgr.h"
+#include "utils/snapmgr.h"
 #include "utils/rel.h"
 #include "utils/tqual.h"
 
-
 /* Working data for heap_page_prune and subroutines */
 typedef struct
 {
@@ -70,10 +71,34 @@ static void heap_prune_record_unused(PruneState *prstate, OffsetNumber offnum);
  * or RECENTLY_DEAD (see HeapTupleSatisfiesVacuum).
  */
 void
-heap_page_prune_opt(Relation relation, Buffer buffer, TransactionId OldestXmin)
+heap_page_prune_opt(Relation relation, Buffer buffer)
 {
    Page        page = BufferGetPage(buffer);
    Size        minfree;
+   TransactionId OldestXmin;
+
+   /*
+    * We can't write WAL in recovery mode, so there's no point trying to
+    * clean the page. The master will likely issue a cleaning WAL record soon
+    * anyway, so this is no particular loss.
+    */
+   if (RecoveryInProgress())
+       return;
+
+   /*
+    * Use the appropriate xmin horizon for this relation. If it's a proper
+    * catalog relation or a user defined, additional, catalog relation, we
+    * need to use the horizon that includes slots, otherwise the data-only
+    * horizon can be used. Note that the toast relation of user defined
+    * relations are *not* considered catalog relations.
+    */
+   if (IsCatalogRelation(relation) ||
+       RelationIsAccessibleInLogicalDecoding(relation))
+       OldestXmin = RecentGlobalXmin;
+   else
+       OldestXmin = RecentGlobalDataXmin;
+
+   Assert(TransactionIdIsValid(OldestXmin));
 
    /*
     * Let's see if we really need pruning.
@@ -84,14 +109,6 @@ heap_page_prune_opt(Relation relation, Buffer buffer, TransactionId OldestXmin)
    if (!PageIsPrunable(page, OldestXmin))
        return;
 
-   /*
-    * We can't write WAL in recovery mode, so there's no point trying to
-    * clean the page. The master will likely issue a cleaning WAL record soon
-    * anyway, so this is no particular loss.
-    */
-   if (RecoveryInProgress())
-       return;
-
    /*
     * We prune when a previous UPDATE failed to find enough space on the page
     * for a new tuple version, or when free space falls below the relation's
index c34ab9865f8e7cf3e134d8e341c8edb36021d9f4..239c7dad0c9f32c1c7e55b435d2e0b1aaa74f724 100644 (file)
  */
 #include "postgres.h"
 
+#include 
+#include 
+
+#include "miscadmin.h"
+
 #include "access/heapam.h"
 #include "access/heapam_xlog.h"
 #include "access/rewriteheap.h"
 #include "access/transam.h"
 #include "access/tuptoaster.h"
+#include "access/xact.h"
+
+#include "catalog/catalog.h"
+
+#include "lib/ilist.h"
+
+#include "replication/logical.h"
+#include "replication/slot.h"
+
 #include "storage/bufmgr.h"
+#include "storage/fd.h"
 #include "storage/smgr.h"
+
 #include "utils/memutils.h"
 #include "utils/rel.h"
 #include "utils/tqual.h"
 
+#include "storage/procarray.h"
 
 /*
  * State associated with a rewrite operation. This is opaque to the user
  */
 typedef struct RewriteStateData
 {
+   Relation    rs_old_rel;     /* source heap */
    Relation    rs_new_rel;     /* destination heap */
    Page        rs_buffer;      /* page currently being built */
    BlockNumber rs_blockno;     /* block where page will go */
    bool        rs_buffer_valid;    /* T if any tuples in buffer */
    bool        rs_use_wal;     /* must we WAL-log inserts? */
+   bool        rs_logical_rewrite; /* do we need to do logical rewriting */
    TransactionId rs_oldest_xmin;       /* oldest xmin used by caller to
                                         * determine tuple visibility */
    TransactionId rs_freeze_xid;/* Xid that will be used as freeze cutoff
                                 * point */
+   TransactionId rs_logical_xmin;  /* Xid that will be used as cutoff
+                                    * point for logical rewrites */
    MultiXactId rs_cutoff_multi;/* MultiXactId that will be used as cutoff
                                 * point for multixacts */
    MemoryContext rs_cxt;       /* for hash tables and entries and tuples in
                                 * them */
+   XLogRecPtr  rs_begin_lsn;   /* XLogInsertLsn when starting the rewrite */
    HTAB       *rs_unresolved_tups;     /* unmatched A tuples */
    HTAB       *rs_old_new_tid_map;     /* unmatched B tuples */
+   HTAB       *rs_logical_mappings;    /* logical remapping files */
+   uint32      rs_num_rewrite_mappings; /* # in memory mappings */
 }  RewriteStateData;
 
 /*
@@ -169,14 +193,45 @@ typedef struct
 
 typedef OldToNewMappingData *OldToNewMapping;
 
+/*
+ * In-Memory data for a xid that might need logical remapping entries
+ * to be logged.
+ */
+typedef struct RewriteMappingFile
+{
+   TransactionId       xid;        /* xid that might need to see the row */
+   int                 vfd;        /* fd of mappings file */
+   off_t               off;        /* how far have we written yet */
+   uint32              num_mappings; /* number of in-memory mappings */
+   dlist_head          mappings;   /* list of in-memory mappings */
+   char                path[MAXPGPATH]; /* path, for error messages */
+} RewriteMappingFile;
+
+/*
+ * A single In-Memeory logical rewrite mapping, hanging of
+ * RewriteMappingFile->mappings.
+ */
+typedef struct RewriteMappingDataEntry
+{
+   LogicalRewriteMappingData map;  /* map between old and new location of
+                                    * the tuple */
+   dlist_node  node;
+} RewriteMappingDataEntry;
+
 
 /* prototypes for internal functions */
 static void raw_heap_insert(RewriteState state, HeapTuple tup);
 
+/* internal logical remapping prototypes */
+static void logical_begin_heap_rewrite(RewriteState state);
+static void logical_rewrite_heap_tuple(RewriteState state, ItemPointerData old_tid, HeapTuple new_tuple);
+static void logical_end_heap_rewrite(RewriteState state);
+
 
 /*
  * Begin a rewrite of a table
  *
+ * old_heap        old, locked heap relation tuples will be read from
  * new_heap        new, locked heap relation to insert tuples to
  * oldest_xmin xid used by the caller to determine which tuples are dead
  * freeze_xid  xid before which tuples will be frozen
@@ -187,7 +242,7 @@ static void raw_heap_insert(RewriteState state, HeapTuple tup);
  * to be used in subsequent calls to the other functions.
  */
 RewriteState
-begin_heap_rewrite(Relation new_heap, TransactionId oldest_xmin,
+begin_heap_rewrite(Relation old_heap, Relation new_heap, TransactionId oldest_xmin,
                   TransactionId freeze_xid, MultiXactId cutoff_multi,
                   bool use_wal)
 {
@@ -210,6 +265,7 @@ begin_heap_rewrite(Relation new_heap, TransactionId oldest_xmin,
    /* Create and fill in the state struct */
    state = palloc0(sizeof(RewriteStateData));
 
+   state->rs_old_rel = old_heap;
    state->rs_new_rel = new_heap;
    state->rs_buffer = (Page) palloc(BLCKSZ);
    /* new_heap needn't be empty, just locked */
@@ -244,6 +300,8 @@ begin_heap_rewrite(Relation new_heap, TransactionId oldest_xmin,
 
    MemoryContextSwitchTo(old_cxt);
 
+   logical_begin_heap_rewrite(state);
+
    return state;
 }
 
@@ -301,6 +359,8 @@ end_heap_rewrite(RewriteState state)
    if (RelationNeedsWAL(state->rs_new_rel))
        heap_sync(state->rs_new_rel);
 
+   logical_end_heap_rewrite(state);
+
    /* Deleting the context frees everything */
    MemoryContextDelete(state->rs_cxt);
 }
@@ -429,6 +489,8 @@ rewrite_heap_tuple(RewriteState state,
        raw_heap_insert(state, new_tuple);
        new_tid = new_tuple->t_self;
 
+       logical_rewrite_heap_tuple(state, old_tid, new_tuple);
+
        /*
         * If the tuple is the updated version of a row, and the prior version
         * wouldn't be DEAD yet, then we need to either resolve the prior
@@ -678,3 +740,545 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
    if (heaptup != tup)
        heap_freetuple(heaptup);
 }
+
+/* ------------------------------------------------------------------------
+ * Logical rewrite support
+ *
+ * When doing logical decoding - which relies on using cmin/cmax of catalog
+ * tuples, via xl_heap_new_cid records - heap rewrites have to log enough
+ * information to allow the decoding backend to updates its internal mapping
+ * of (relfilenode,ctid) => (cmin, cmax) to be correct for the rewritten heap.
+ *
+ * For that, every time we find a tuple that's been modified in a catalog
+ * relation within the xmin horizon of any decoding slot, we log a mapping
+ * from the old to the new location.
+ *
+ * To deal with rewrites that abort the filename of a mapping file contains
+ * the xid of the transaction performing the rewrite, which then can be
+ * checked before being read in.
+ *
+ * For efficiency we don't immediately spill every single map mapping for a
+ * row to disk but only do so in batches when we've collected several of them
+ * in memory or when end_heap_rewrite() has been called.
+ *
+ * Crash-Safety: This module diverts from the usual patterns of doing WAL
+ * since it cannot rely on checkpoint flushing out all buffers and thus
+ * waiting for exlusive locks on buffers. Usually the XLogInsert() covering
+ * buffer modifications is performed while the buffer(s) that are being
+ * modified are exlusively locked guaranteeing that both the WAL record and
+ * the modified heap are on either side of the checkpoint. But since the
+ * mapping files we log aren't in shared_buffers that interlock doesn't work.
+ *
+ * Instead we simply write the mapping files out to disk, *before* the
+ * XLogInsert() is performed. That guarantees that either the XLogInsert() is
+ * inserted after the checkpoint's redo pointer or that the checkpoint (via
+ * LogicalRewriteHeapCheckpoint()) has flushed the (partial) mapping file to
+ * disk. That leaves the tail end that has not yet been flushed open to
+ * corruption, which is solved by including the current offset in the
+ * xl_heap_rewrite_mapping records and truncating the mapping file to it
+ * during replay. Every time a rewrite is finished all generated mapping files
+ * are synced to disk.
+ *
+ * Note that if we were only concerned about crash safety we wouldn't have to
+ * deal with WAL logging at all - an fsync() at the end of a rewrite would be
+ * sufficient for crash safety. Any mapping that hasn't been safely flushed to
+ * disk has to be by an aborted (explicitly or via a crash) transaction and is
+ * ignored by virtue of the xid in it's name being subject to a
+ * TransactionDidCommit() check. But we want to support having standbys via
+ * physical replication, both for availability and to to do logical decoding
+ * there.
+ * ------------------------------------------------------------------------
+ */
+
+/*
+ * Do preparations for logging logical mappings during a rewrite if
+ * necessary. If we detect that we don't need to log anything we'll prevent
+ * any further action by the various logical rewrite functions.
+ */
+static void
+logical_begin_heap_rewrite(RewriteState state)
+{
+   HASHCTL     hash_ctl;
+   TransactionId logical_xmin;
+
+   /*
+    * We only need to persist these mappings if the rewritten table can be
+    * accessed during logical decoding, if not, we can skip doing any
+    * additional work.
+    */
+   state->rs_logical_rewrite =
+       RelationIsAccessibleInLogicalDecoding(state->rs_old_rel);
+
+   if (!state->rs_logical_rewrite)
+       return;
+
+   Assert(ReplicationSlotCtl != NULL);
+
+   ProcArrayGetReplicationSlotXmin(NULL, &logical_xmin);
+
+   /*
+    * If there are no logical slots in progress we don't need to do anything,
+    * there cannot be any remappings for relevant rows yet. The relation's
+    * lock protects us against races.
+    */
+   if (logical_xmin == InvalidTransactionId)
+   {
+       state->rs_logical_rewrite = false;
+       return;
+   }
+
+   state->rs_logical_xmin = logical_xmin;
+   state->rs_begin_lsn = GetXLogInsertRecPtr();
+   state->rs_num_rewrite_mappings = 0;
+
+   memset(&hash_ctl, 0, sizeof(hash_ctl));
+   hash_ctl.keysize = sizeof(TransactionId);
+   hash_ctl.entrysize = sizeof(RewriteMappingFile);
+   hash_ctl.hcxt = state->rs_cxt;
+   hash_ctl.hash = tag_hash;
+
+   state->rs_logical_mappings =
+       hash_create("Logical rewrite mapping",
+                   128,        /* arbitrary initial size */
+                   &hash_ctl,
+                   HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
+}
+
+/*
+ * Flush all logical in-memory mappings to disk, but don't fsync them yet.
+ */
+static void
+logical_heap_rewrite_flush_mappings(RewriteState state)
+{
+   HASH_SEQ_STATUS seq_status;
+   RewriteMappingFile *src;
+   dlist_mutable_iter iter;
+
+   Assert(state->rs_logical_rewrite);
+
+   /* no logical rewrite in progress, no need to iterate over mappings */
+   if (state->rs_num_rewrite_mappings == 0)
+       return;
+
+   elog(DEBUG1, "flushing %u logical rewrite mapping entries",
+        state->rs_num_rewrite_mappings);
+
+   hash_seq_init(&seq_status, state->rs_logical_mappings);
+   while ((src = (RewriteMappingFile *) hash_seq_search(&seq_status)) != NULL)
+   {
+       XLogRecData     rdata[2];
+       char           *waldata;
+       char           *waldata_start;
+       xl_heap_rewrite_mapping xlrec;
+       Oid             dboid;
+       uint32          len;
+       int             written;
+
+       /* this file hasn't got any new mappings */
+       if (src->num_mappings == 0)
+           continue;
+
+       if (state->rs_old_rel->rd_rel->relisshared)
+           dboid = InvalidOid;
+       else
+           dboid = MyDatabaseId;
+
+       xlrec.num_mappings = src->num_mappings;
+       xlrec.mapped_rel = RelationGetRelid(state->rs_old_rel);
+       xlrec.mapped_xid = src->xid;
+       xlrec.mapped_db = dboid;
+       xlrec.offset = src->off;
+       xlrec.start_lsn = state->rs_begin_lsn;
+
+       rdata[0].data = (char *) (&xlrec);
+       rdata[0].len = sizeof(xlrec);
+       rdata[0].buffer = InvalidBuffer;
+       rdata[0].next = &(rdata[1]);
+
+       /* write all mappings consecutively */
+       len = src->num_mappings * sizeof(LogicalRewriteMappingData);
+       waldata = palloc(len);
+       waldata_start = waldata;
+
+       /*
+        * collect data we need to write out, but don't modify ondisk data yet
+        */
+       dlist_foreach_modify(iter, &src->mappings)
+       {
+           RewriteMappingDataEntry *pmap;
+
+           pmap = dlist_container(RewriteMappingDataEntry, node, iter.cur);
+
+           memcpy(waldata, &pmap->map, sizeof(pmap->map));
+           waldata += sizeof(pmap->map);
+
+           /* remove from the list and free */
+           dlist_delete(&pmap->node);
+           pfree(pmap);
+
+           /* update bookkeeping */
+           state->rs_num_rewrite_mappings--;
+           src->num_mappings--;
+       }
+
+       /*
+        * Note that we deviate from the usual WAL coding practices here,
+        * check the above "Logical rewrite support" comment for reasoning.
+        */
+       written = FileWrite(src->vfd, waldata_start, len);
+       if (written != len)
+           ereport(ERROR,
+                   (errcode_for_file_access(),
+                    errmsg("could not write to file \"%s\", wrote %d of %d: %m", src->path,
+                           written, len)));
+       src->off += len;
+
+       Assert(src->num_mappings == 0);
+
+       rdata[1].data = waldata_start;
+       rdata[1].len = len;
+       rdata[1].buffer = InvalidBuffer;
+       rdata[1].next = NULL;
+
+       /* write xlog record */
+       XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_REWRITE, rdata);
+
+   }
+   Assert(state->rs_num_rewrite_mappings == 0);
+}
+
+/*
+ * Logical remapping part of end_heap_rewrite().
+ */
+static void
+logical_end_heap_rewrite(RewriteState state)
+{
+   HASH_SEQ_STATUS seq_status;
+   RewriteMappingFile *src;
+
+   /* done, no logical rewrite in progress */
+   if (!state->rs_logical_rewrite)
+       return;
+
+   /* writeout remaining in-memory entries */
+   if (state->rs_num_rewrite_mappings > 0 )
+       logical_heap_rewrite_flush_mappings(state);
+
+   /* Iterate over all mappings we have written and fsync the files. */
+   hash_seq_init(&seq_status, state->rs_logical_mappings);
+   while ((src = (RewriteMappingFile *) hash_seq_search(&seq_status)) != NULL)
+   {
+       if(FileSync(src->vfd) != 0)
+           ereport(ERROR,
+                   (errcode_for_file_access(),
+                    errmsg("could not fsync file \"%s\": %m", src->path)));
+       FileClose(src->vfd);
+   }
+   /* memory context cleanup will deal with the rest */
+}
+
+/*
+ * Log a single (old->new) mapping for 'xid'.
+ */
+static void
+logical_rewrite_log_mapping(RewriteState state, TransactionId xid,
+                           LogicalRewriteMappingData *map)
+{
+   RewriteMappingFile         *src;
+   RewriteMappingDataEntry    *pmap;
+   Oid                         relid;
+   bool                        found;
+
+   relid = RelationGetRelid(state->rs_old_rel);
+
+   /* look for existing mappings for this 'mapped' xid */
+   src = hash_search(state->rs_logical_mappings, &xid,
+                     HASH_ENTER, &found);
+
+   /*
+    * We haven't yet had the need to map anything for this xid, create
+    * per-xid data structures.
+    */
+   if (!found)
+   {
+       char        path[MAXPGPATH];
+       Oid         dboid;
+
+       if (state->rs_old_rel->rd_rel->relisshared)
+           dboid = InvalidOid;
+       else
+           dboid = MyDatabaseId;
+
+       snprintf(path, MAXPGPATH,
+                "pg_llog/mappings/" LOGICAL_REWRITE_FORMAT,
+                dboid, relid,
+                (uint32) (state->rs_begin_lsn >> 32),
+                (uint32) state->rs_begin_lsn,
+                xid, GetCurrentTransactionId());
+
+       dlist_init(&src->mappings);
+       src->num_mappings = 0;
+       src->off = 0;
+       memcpy(src->path, path, sizeof(path));
+       src->vfd = PathNameOpenFile(path,
+                                   O_CREAT | O_EXCL | O_WRONLY | PG_BINARY,
+                                   S_IRUSR | S_IWUSR);
+       if (src->vfd < 0)
+           ereport(ERROR,
+                   (errcode_for_file_access(),
+                    errmsg("could not create file \"%s\": %m", path)));
+   }
+
+   pmap = MemoryContextAlloc(state->rs_cxt,
+                             sizeof(RewriteMappingDataEntry));
+   memcpy(&pmap->map, map, sizeof(LogicalRewriteMappingData));
+   dlist_push_tail(&src->mappings, &pmap->node);
+   src->num_mappings++;
+   state->rs_num_rewrite_mappings++;
+
+   /*
+    * Write out buffer every time we've too many in-memory entries across all
+    * mapping files.
+    */
+   if (state->rs_num_rewrite_mappings >= 1000 /* arbitrary number */)
+       logical_heap_rewrite_flush_mappings(state);
+}
+
+/*
+ * Perform logical remapping for a tuple that's mapped from old_tid to
+ * new_tuple->t_self by rewrite_heap_tuple() iff necessary for the tuple.
+ */
+static void
+logical_rewrite_heap_tuple(RewriteState state, ItemPointerData old_tid,
+                          HeapTuple new_tuple)
+{
+   ItemPointerData new_tid = new_tuple->t_self;
+   TransactionId   cutoff = state->rs_logical_xmin;
+   TransactionId   xmin;
+   TransactionId   xmax;
+   bool            do_log_xmin = false;
+   bool            do_log_xmax = false;
+   LogicalRewriteMappingData map;
+
+   /* no logical rewrite in progress, we don't need to log anything */
+   if (!state->rs_logical_rewrite)
+       return;
+
+   xmin = HeapTupleHeaderGetXmin(new_tuple->t_data);
+   /* use *GetUpdateXid to correctly deal with multixacts */
+   xmax = HeapTupleHeaderGetUpdateXid(new_tuple->t_data);
+
+   /*
+    * Log the mapping iff the tuple has been created recently.
+    */
+   if (TransactionIdIsNormal(xmin) && !TransactionIdPrecedes(xmin, cutoff))
+       do_log_xmin = true;
+
+   if (!TransactionIdIsNormal(xmax))
+   {
+       /*
+        * no xmax is set, can't have any permanent ones, so this check is
+        * sufficient
+        */
+   }
+   else if (HEAP_XMAX_IS_LOCKED_ONLY(new_tuple->t_data->t_infomask))
+   {
+       /* only locked, we don't care */
+   }
+   else if (!TransactionIdPrecedes(xmax, cutoff))
+   {
+       /* tuple has been deleted recently, log */
+       do_log_xmax = true;
+   }
+
+   /* if neither needs to be logged, we're done */
+   if (!do_log_xmin && !do_log_xmax)
+       return;
+
+   /* fill out mapping information */
+   map.old_node = state->rs_old_rel->rd_node;
+   map.old_tid = old_tid;
+   map.new_node = state->rs_new_rel->rd_node;
+   map.new_tid = new_tid;
+
+   /* ---
+    * Now persist the mapping for the individual xids that are affected. We
+    * need to log for both xmin and xmax if they aren't the same transaction
+    * since the mapping files are per "affected" xid.
+    * We don't muster all that much effort detecting whether xmin and xmax
+    * are actually the same transaction, we just check whether the xid is the
+    * same disregarding subtransactions. Logging too much is relatively
+    * harmless and we could never do the check fully since subtransaction
+    * data is thrown away during restarts.
+    * ---
+    */
+   if (do_log_xmin)
+       logical_rewrite_log_mapping(state, xmin, &map);
+   /* separately log mapping for xmax unless it'd be redundant */
+   if (do_log_xmax && !TransactionIdEquals(xmin, xmax))
+       logical_rewrite_log_mapping(state, xmax, &map);
+}
+
+/*
+ * Replay XLOG_HEAP2_REWRITE records
+ */
+void
+heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r)
+{
+   char        path[MAXPGPATH];
+   int         fd;
+   xl_heap_rewrite_mapping *xlrec;
+   uint32      len;
+   char       *data;
+
+   xlrec = (xl_heap_rewrite_mapping *) XLogRecGetData(r);
+
+   snprintf(path, MAXPGPATH,
+            "pg_llog/mappings/" LOGICAL_REWRITE_FORMAT,
+            xlrec->mapped_db, xlrec->mapped_rel,
+            (uint32) (xlrec->start_lsn >> 32),
+            (uint32) xlrec->start_lsn,
+            xlrec->mapped_xid, r->xl_xid);
+
+   fd = OpenTransientFile(path,
+                          O_CREAT | O_WRONLY | PG_BINARY,
+                          S_IRUSR | S_IWUSR);
+   if (fd < 0)
+       ereport(ERROR,
+               (errcode_for_file_access(),
+                errmsg("could not create file \"%s\": %m", path)));
+   /*
+    * Truncate all data that's not guaranteed to have been safely fsynced (by
+    * previous record or by the last checkpoint).
+    */
+   if (ftruncate(fd, xlrec->offset) != 0)
+       ereport(ERROR,
+               (errcode_for_file_access(),
+                errmsg("could not truncate file \"%s\" to %u: %m",
+                       path, (uint32) xlrec->offset)));
+
+   /* now seek to the position we want to write our data to */
+   if (lseek(fd, xlrec->offset, SEEK_SET) != xlrec->offset)
+       ereport(ERROR,
+               (errcode_for_file_access(),
+                errmsg("could not seek to the end of file \"%s\": %m",
+                       path)));
+
+   data = XLogRecGetData(r) + sizeof(*xlrec);
+
+   len = xlrec->num_mappings * sizeof(LogicalRewriteMappingData);
+
+   /* write out tail end of mapping file (again) */
+   if (write(fd, data, len) != len)
+       ereport(ERROR,
+               (errcode_for_file_access(),
+                errmsg("could not write to file \"%s\": %m", path)));
+   /*
+    * Now fsync all previously written data. We could improve things and only
+    * do this for the last write to a file, but the required bookkeeping
+    * doesn't seem worth the trouble.
+    */
+   if (pg_fsync(fd) != 0)
+       ereport(ERROR,
+               (errcode_for_file_access(),
+                errmsg("could not fsync file \"%s\": %m", path)));
+
+   CloseTransientFile(fd);
+}
+
+/* ---
+ * Perform a checkpoint for logical rewrite mappings
+ *
+ * This serves two tasks:
+ * 1) Remove all mappings not needed anymore based on the logical restart LSN
+ * 2) Flush all remaining mappings to disk, so that replay after a checkpoint
+ *   only has to deal with the parts of a mapping that have been written out
+ *   after the checkpoint started.
+ * ---
+ */
+void
+CheckPointLogicalRewriteHeap(void)
+{
+   XLogRecPtr  cutoff;
+   XLogRecPtr  redo;
+   DIR        *mappings_dir;
+   struct dirent *mapping_de;
+   char        path[MAXPGPATH];
+
+   /*
+    * We start of with a minimum of the last redo pointer. No new decoding
+    * slot will start before that, so that's a safe upper bound for removal.
+    */
+   redo = GetRedoRecPtr();
+
+   /* now check for the restart ptrs from existing slots */
+   cutoff = ReplicationSlotsComputeLogicalRestartLSN();
+
+   /* don't start earlier than the restart lsn */
+   if (cutoff != InvalidXLogRecPtr && redo < cutoff)
+       cutoff = redo;
+
+   mappings_dir = AllocateDir("pg_llog/mappings");
+   while ((mapping_de = ReadDir(mappings_dir, "pg_llog/mappings")) != NULL)
+   {
+       struct stat statbuf;
+       Oid         dboid;
+       Oid         relid;
+       XLogRecPtr  lsn;
+       TransactionId rewrite_xid;
+       TransactionId create_xid;
+       uint32      hi, lo;
+
+       if (strcmp(mapping_de->d_name, ".") == 0 ||
+           strcmp(mapping_de->d_name, "..") == 0)
+           continue;
+
+       snprintf(path, MAXPGPATH, "pg_llog/mappings/%s", mapping_de->d_name);
+       if (lstat(path, &statbuf) == 0 && !S_ISREG(statbuf.st_mode))
+           continue;
+
+       /* Skip over files that cannot be ours. */
+       if (strncmp(mapping_de->d_name, "map-", 4) != 0)
+           continue;
+
+       if (sscanf(mapping_de->d_name, LOGICAL_REWRITE_FORMAT,
+                  &dboid, &relid, &hi, &lo, &rewrite_xid, &create_xid) != 6)
+           elog(ERROR,"could not parse filename \"%s\"", mapping_de->d_name);
+
+       lsn = ((uint64) hi) << 32 | lo;
+
+       if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+       {
+           elog(DEBUG1, "removing logical rewrite file \"%s\"", path);
+           if (unlink(path) < 0)
+               ereport(ERROR,
+                       (errcode_for_file_access(),
+                        errmsg("could not unlink file \"%s\": %m", path)));
+       }
+       else
+       {
+           int     fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
+
+           /*
+            * The file cannot vanish due to concurrency since this function
+            * is the only one removing logical mappings and it's run while
+            * CheckpointLock is held exclusively.
+            */
+           if (fd < 0)
+               ereport(ERROR,
+                       (errcode_for_file_access(),
+                        errmsg("could not open file \"%s\": %m", path)));
+           /*
+            * We could try to avoid fsyncing files that either haven't
+            * changed or have only been created since the checkpoint's start,
+            * but it's currently not deemed worth the effort.
+            */
+           else if (pg_fsync(fd) != 0)
+               ereport(ERROR,
+                       (errcode_for_file_access(),
+                        errmsg("could not fsync file \"%s\": %m", path)));
+           CloseTransientFile(fd);
+       }
+   }
+   FreeDir(mappings_dir);
+}
index 97c9f238a7bba104a8a43838b1576ae8dafa5257..9a821d3e1cf422e99440695a44e30c8dccf5025e 100644 (file)
 
 #undef TOAST_DEBUG
 
-/*
- * Testing whether an externally-stored value is compressed now requires
- * comparing extsize (the actual length of the external data) to rawsize
- * (the original uncompressed datum's size).  The latter includes VARHDRSZ
- * overhead, the former doesn't.  We never use compression unless it actually
- * saves space, so we expect either equality or less-than.
- */
-#define VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) \
-   ((toast_pointer).va_extsize < (toast_pointer).va_rawsize - VARHDRSZ)
-
-/*
- * Macro to fetch the possibly-unaligned contents of an EXTERNAL datum
- * into a local "struct varatt_external" toast pointer.  This should be
- * just a memcpy, but some versions of gcc seem to produce broken code
- * that assumes the datum contents are aligned.  Introducing an explicit
- * intermediate "varattrib_1b_e *" variable seems to fix it.
- */
-#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr) \
-do { \
-   varattrib_1b_e *attre = (varattrib_1b_e *) (attr); \
-   Assert(VARATT_IS_EXTERNAL(attre)); \
-   Assert(VARSIZE_EXTERNAL(attre) == sizeof(toast_pointer) + VARHDRSZ_EXTERNAL); \
-   memcpy(&(toast_pointer), VARDATA_EXTERNAL(attre), sizeof(toast_pointer)); \
-} while (0)
-
-
 static void toast_delete_datum(Relation rel, Datum value);
 static Datum toast_save_datum(Relation rel, Datum value,
                 struct varlena * oldexternal, int options);
index 1aba2f04cc4ea5845422fbce3766b0b08d9c3bf9..a4b5f3d698e0548bc710be37569c5d3491f28cbf 100644 (file)
 
 #include "access/relscan.h"
 #include "access/transam.h"
+#include "access/xlog.h"
+
 #include "catalog/index.h"
+#include "catalog/catalog.h"
 #include "pgstat.h"
 #include "storage/bufmgr.h"
 #include "storage/lmgr.h"
@@ -520,8 +523,7 @@ index_fetch_heap(IndexScanDesc scan)
         * Prune page, but only if we weren't already on this page
         */
        if (prev_buf != scan->xs_cbuf)
-           heap_page_prune_opt(scan->heapRelation, scan->xs_cbuf,
-                               RecentGlobalXmin);
+           heap_page_prune_opt(scan->heapRelation, scan->xs_cbuf);
    }
 
    /* Obtain share-lock on the buffer so we can examine visibility */
index 89ba09a206f61fc4fb980fe1e0c746a7045e40d0..c8a61669dd292c3fd7345fcbd8b274487cbe9f6b 100644 (file)
@@ -149,6 +149,10 @@ heap2_desc(StringInfo buf, uint8 xl_info, char *rec)
                         xlrec->node.relNode, xlrec->block,
                         xlrec->cutoff_xid, xlrec->ntuples);
    }
+   else if (info == XLOG_HEAP2_REWRITE)
+   {
+       appendStringInfoString(buf, "heap rewrite:");
+   }
    else if (info == XLOG_HEAP2_CLEANUP_INFO)
    {
        xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
index 0487be17df7d3f230b602097ab8509dcaa1f508c..b20d9732e78a7ba79f0eb19e6ac42a8365fdee2c 100644 (file)
@@ -1074,8 +1074,16 @@ RecordTransactionCommit(void)
 
        /*
         * Do we need the long commit record? If not, use the compact format.
+        *
+        * For now always use the non-compact version if wal_level=logical, so
+        * we can hide commits from other databases. TODO: In the future we
+        * should merge compact and non-compact commits and use a flags
+        * variable to determine if it contains subxacts, relations or
+        * invalidation messages, that's more extensible and degrades more
+        * gracefully. Till then, it's just 20 bytes of overhead.
         */
-       if (nrels > 0 || nmsgs > 0 || RelcacheInitFileInval || forceSyncCommit)
+       if (nrels > 0 || nmsgs > 0 || RelcacheInitFileInval || forceSyncCommit ||
+           XLogLogicalInfoActive())
        {
            XLogRecData rdata[4];
            int         lastrdata = 0;
index ad46eb0cebf2b880f9930480b6eeab6b6782cd35..53a20b1e60600016e3225b2be23ade41525ece7b 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "access/clog.h"
 #include "access/multixact.h"
+#include "access/rewriteheap.h"
 #include "access/subtrans.h"
 #include "access/timeline.h"
 #include "access/transam.h"
@@ -39,7 +40,9 @@
 #include "pgstat.h"
 #include "postmaster/bgwriter.h"
 #include "postmaster/startup.h"
+#include "replication/logical.h"
 #include "replication/slot.h"
+#include "replication/snapbuild.h"
 #include "replication/walreceiver.h"
 #include "replication/walsender.h"
 #include "storage/barrier.h"
@@ -4015,6 +4018,27 @@ CheckXLogRemoved(XLogSegNo segno, TimeLineID tli)
    }
 }
 
+/*
+ * Return the last WAL segment removed, or 0 if no segment has been removed
+ * since startup.
+ *
+ * NB: the result can be out of date arbitrarily fast, the caller has to deal
+ * with that.
+ */
+XLogSegNo
+XLogGetLastRemovedSegno(void)
+{
+   /* use volatile pointer to prevent code rearrangement */
+   volatile XLogCtlData *xlogctl = XLogCtl;
+   XLogSegNo   lastRemovedSegNo;
+
+   SpinLockAcquire(&xlogctl->info_lck);
+   lastRemovedSegNo = xlogctl->lastRemovedSegNo;
+   SpinLockRelease(&xlogctl->info_lck);
+
+   return lastRemovedSegNo;
+}
+
 /*
  * Update the last removed segno pointer in shared memory, to reflect
  * that the given XLOG file has been removed.
@@ -6558,6 +6582,12 @@ StartupXLOG(void)
     */
    StartupReplicationSlots(checkPoint.redo);
 
+   /*
+    * Startup logical state, needs to be setup now so we have proper data
+    * during crash recovery.
+    */
+   StartupReorderBuffer();
+
    /*
     * Startup MultiXact.  We need to do this early for two reasons: one
     * is that we might try to access multixacts when we do tuple freezing,
@@ -8589,7 +8619,7 @@ CreateCheckPoint(int flags)
     * StartupSUBTRANS hasn't been called yet.
     */
    if (!RecoveryInProgress())
-       TruncateSUBTRANS(GetOldestXmin(true, false));
+       TruncateSUBTRANS(GetOldestXmin(NULL, false));
 
    /* Real work is done, but log and update stats before releasing lock. */
    LogCheckpointEnd(false);
@@ -8674,6 +8704,8 @@ CheckPointGuts(XLogRecPtr checkPointRedo, int flags)
    CheckPointPredicate();
    CheckPointRelationMap();
    CheckPointReplicationSlots();
+   CheckPointSnapBuild();
+   CheckPointLogicalRewriteHeap();
    CheckPointBuffers(flags);   /* performs all required fsyncs */
    /* We deliberately delay 2PC checkpointing as long as possible */
    CheckPointTwoPhase(checkPointRedo);
@@ -8965,7 +8997,7 @@ CreateRestartPoint(int flags)
     * this because StartupSUBTRANS hasn't been called yet.
     */
    if (EnableHotStandby)
-       TruncateSUBTRANS(GetOldestXmin(true, false));
+       TruncateSUBTRANS(GetOldestXmin(NULL, false));
 
    /* Real work is done, but log and update before releasing lock. */
    LogCheckpointEnd(true);
index cebca95ac8d6e43fb038de981cc9bb22e4832e29..877d7678f7ae1f5a31c23f35ba095024b6d0f447 100644 (file)
@@ -2156,7 +2156,7 @@ IndexBuildHeapScan(Relation heapRelation,
    {
        snapshot = SnapshotAny;
        /* okay to ignore lazy VACUUMs here */
-       OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared, true);
+       OldestXmin = GetOldestXmin(heapRelation, true);
    }
 
    scan = heap_beginscan_strat(heapRelation,   /* relation */
index 04dfbb0ee54765dc3f23169fc932e1021f700170..0500a73e1ba2a70db284e1de1d7be8aa6fa20a67 100644 (file)
@@ -619,11 +619,13 @@ CREATE VIEW pg_stat_replication AS
 CREATE VIEW pg_replication_slots AS
     SELECT
             L.slot_name,
+            L.plugin,
             L.slot_type,
             L.datoid,
             D.datname AS database,
             L.active,
             L.xmin,
+            L.catalog_xmin,
             L.restart_lsn
     FROM pg_get_replication_slots() AS L
             LEFT JOIN pg_database D ON (L.datoid = D.oid);
@@ -822,3 +824,35 @@ CREATE OR REPLACE FUNCTION
 CREATE OR REPLACE FUNCTION
   json_populate_recordset(base anyelement, from_json json, use_json_as_text boolean DEFAULT false)
   RETURNS SETOF anyelement LANGUAGE internal STABLE ROWS 100  AS 'json_populate_recordset';
+
+CREATE OR REPLACE FUNCTION pg_logical_slot_get_changes(
+    IN slotname name, IN upto_lsn pg_lsn, IN upto_nchanges int, VARIADIC options text[] DEFAULT '{}',
+    OUT location pg_lsn, OUT xid xid, OUT data text)
+RETURNS SETOF RECORD
+LANGUAGE INTERNAL
+VOLATILE ROWS 1000 COST 1000
+AS 'pg_logical_slot_get_changes';
+
+CREATE OR REPLACE FUNCTION pg_logical_slot_peek_changes(
+    IN slotname name, IN upto_lsn pg_lsn, IN upto_nchanges int, VARIADIC options text[] DEFAULT '{}',
+    OUT location pg_lsn, OUT xid xid, OUT data text)
+RETURNS SETOF RECORD
+LANGUAGE INTERNAL
+VOLATILE ROWS 1000 COST 1000
+AS 'pg_logical_slot_peek_changes';
+
+CREATE OR REPLACE FUNCTION pg_logical_slot_get_binary_changes(
+    IN slotname name, IN upto_lsn pg_lsn, IN upto_nchanges int, VARIADIC options text[] DEFAULT '{}',
+    OUT location pg_lsn, OUT xid xid, OUT data bytea)
+RETURNS SETOF RECORD
+LANGUAGE INTERNAL
+VOLATILE ROWS 1000 COST 1000
+AS 'pg_logical_slot_get_binary_changes';
+
+CREATE OR REPLACE FUNCTION pg_logical_slot_peek_binary_changes(
+    IN slotname name, IN upto_lsn pg_lsn, IN upto_nchanges int, VARIADIC options text[] DEFAULT '{}',
+    OUT location pg_lsn, OUT xid xid, OUT data bytea)
+RETURNS SETOF RECORD
+LANGUAGE INTERNAL
+VOLATILE ROWS 1000 COST 1000
+AS 'pg_logical_slot_peek_binary_changes';
index e7fcb55868489d88f0246546a1affec58316a8b0..a04adeaac754873c3841e76c4c6db50f0dde01fe 100644 (file)
@@ -22,6 +22,7 @@
 #include "access/tuptoaster.h"
 #include "access/visibilitymap.h"
 #include "access/xact.h"
+#include "catalog/catalog.h"
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_collation.h"
@@ -1081,7 +1082,7 @@ acquire_sample_rows(Relation onerel, int elevel,
    totalblocks = RelationGetNumberOfBlocks(onerel);
 
    /* Need a cutoff xmin for HeapTupleSatisfiesVacuum */
-   OldestXmin = GetOldestXmin(onerel->rd_rel->relisshared, true);
+   OldestXmin = GetOldestXmin(onerel, true);
 
    /* Prepare for sampling block numbers */
    BlockSampler_Init(&bs, totalblocks, targrows);
index 8b18e4acb72b53307397a6e07428b8ba396e63b5..b6b40e724e76ca1fd9ce8011f5652aa031646186 100644 (file)
@@ -850,7 +850,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
     * Since we're going to rewrite the whole table anyway, there's no reason
     * not to be aggressive about this.
     */
-   vacuum_set_xid_limits(0, 0, 0, 0, OldHeap->rd_rel->relisshared,
+   vacuum_set_xid_limits(OldHeap, 0, 0, 0, 0,
                          &OldestXmin, &FreezeXid, NULL, &MultiXactCutoff,
                          NULL);
 
@@ -869,7 +869,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose,
    is_system_catalog = IsSystemRelation(OldHeap);
 
    /* Initialize the rewrite operation */
-   rwstate = begin_heap_rewrite(NewHeap, OldestXmin, FreezeXid,
+   rwstate = begin_heap_rewrite(OldHeap, NewHeap, OldestXmin, FreezeXid,
                                 MultiXactCutoff, use_wal);
 
    /*
index 5d540aa3a017c42c470e9386b6cd1b7fd7d9517c..4996a2e7cd2eb62168f7f89cd1506708f2dd9e6a 100644 (file)
@@ -45,6 +45,7 @@
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "postmaster/bgwriter.h"
+#include "replication/slot.h"
 #include "storage/copydir.h"
 #include "storage/fd.h"
 #include "storage/lmgr.h"
@@ -750,6 +751,7 @@ dropdb(const char *dbname, bool missing_ok)
    HeapTuple   tup;
    int         notherbackends;
    int         npreparedxacts;
+   int         nslots, nslots_active;
 
    /*
     * Look up the target database's OID, and get exclusive lock on it. We
@@ -806,6 +808,19 @@ dropdb(const char *dbname, bool missing_ok)
                (errcode(ERRCODE_OBJECT_IN_USE),
                 errmsg("cannot drop the currently open database")));
 
+   /*
+    * Check whether there are, possibly unconnected, logical slots that refer
+    * to the to-be-dropped database. The database lock we are holding
+    * prevents the creation of new slots using the database.
+    */
+   if (ReplicationSlotsCountDBSlots(db_id, &nslots, &nslots_active))
+       ereport(ERROR,
+               (errcode(ERRCODE_OBJECT_IN_USE),
+                errmsg("database \"%s\" is used by a logical decoding slot",
+                       dbname),
+                errdetail("There are %d slot(s), %d of them active",
+                          nslots, nslots_active)));
+
    /*
     * Check for other backends in the target database.  (Because we hold the
     * database lock, no new ones can start after this.)
index 5ae7763534b35be938ac45960ef775460739bdcb..ded1841dc652d218badb0959ff89d36ab0e62684 100644 (file)
@@ -398,11 +398,11 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
  * not interested.
  */
 void
-vacuum_set_xid_limits(int freeze_min_age,
+vacuum_set_xid_limits(Relation rel,
+                     int freeze_min_age,
                      int freeze_table_age,
                      int multixact_freeze_min_age,
                      int multixact_freeze_table_age,
-                     bool sharedRel,
                      TransactionId *oldestXmin,
                      TransactionId *freezeLimit,
                      TransactionId *xidFullScanLimit,
@@ -425,7 +425,7 @@ vacuum_set_xid_limits(int freeze_min_age,
     * working on a particular table at any time, and that each vacuum is
     * always an independent transaction.
     */
-   *oldestXmin = GetOldestXmin(sharedRel, true);
+   *oldestXmin = GetOldestXmin(rel, true);
 
    Assert(TransactionIdIsNormal(*oldestXmin));
 
@@ -795,7 +795,7 @@ vac_update_datfrozenxid(void)
     * committed pg_class entries for new tables; see AddNewRelationTuple().
     * So we cannot produce a wrong minimum by starting with this.
     */
-   newFrozenXid = GetOldestXmin(true, true);
+   newFrozenXid = GetOldestXmin(NULL, true);
 
    /*
     * Similarly, initialize the MultiXact "min" with the value that would be
index d77892ee7f8ce0f1cfd5ca67b5f0d4e0b2b5e37d..d5db917d97f3fe29e237ebd9950b5fba6c555159 100644 (file)
@@ -44,6 +44,7 @@
 #include "access/multixact.h"
 #include "access/transam.h"
 #include "access/visibilitymap.h"
+#include "catalog/catalog.h"
 #include "catalog/storage.h"
 #include "commands/dbcommands.h"
 #include "commands/vacuum.h"
@@ -204,10 +205,10 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
 
    vac_strategy = bstrategy;
 
-   vacuum_set_xid_limits(vacstmt->freeze_min_age, vacstmt->freeze_table_age,
+   vacuum_set_xid_limits(onerel,
+                         vacstmt->freeze_min_age, vacstmt->freeze_table_age,
                          vacstmt->multixact_freeze_min_age,
                          vacstmt->multixact_freeze_table_age,
-                         onerel->rd_rel->relisshared,
                          &OldestXmin, &FreezeLimit, &xidFullScanLimit,
                          &MultiXactCutoff, &mxactFullScanLimit);
 
index 1a8d4e51430b232d96080da14a3ecd781f2787d0..7d8a3f2c24830a197c8094bb693a5ab91c82fd32 100644 (file)
@@ -336,8 +336,7 @@ bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres)
    /*
     * Prune and repair fragmentation for the whole page, if possible.
     */
-   Assert(TransactionIdIsValid(RecentGlobalXmin));
-   heap_page_prune_opt(scan->rs_rd, buffer, RecentGlobalXmin);
+   heap_page_prune_opt(scan->rs_rd, buffer);
 
    /*
     * We must hold share lock on the buffer content while examining tuple
index 7941cb8d5e7663d4b4bb72f53b685a1f326de0cb..6f17b08a6a539bad70d4a445f2aec29cc14f3eb0 100644 (file)
@@ -17,6 +17,8 @@ override CPPFLAGS := -I$(srcdir) $(CPPFLAGS)
 OBJS = walsender.o walreceiverfuncs.o walreceiver.o basebackup.o \
    repl_gram.o slot.o slotfuncs.o syncrep.o
 
+SUBDIRS = logical
+
 include $(top_srcdir)/src/backend/common.mk
 
 # repl_scanner is compiled as part of repl_gram
diff --git a/src/backend/replication/logical/Makefile b/src/backend/replication/logical/Makefile
new file mode 100644 (file)
index 0000000..310a45c
--- /dev/null
@@ -0,0 +1,19 @@
+#-------------------------------------------------------------------------
+#
+# Makefile--
+#    Makefile for src/backend/replication/logical
+#
+# IDENTIFICATION
+#    src/backend/replication/logical/Makefile
+#
+#-------------------------------------------------------------------------
+
+subdir = src/backend/replication/logical
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+
+override CPPFLAGS := -I$(srcdir) $(CPPFLAGS)
+
+OBJS = decode.o logical.o logicalfuncs.o reorderbuffer.o snapbuild.o
+
+include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
new file mode 100644 (file)
index 0000000..e8949aa
--- /dev/null
@@ -0,0 +1,826 @@
+/* -------------------------------------------------------------------------
+ *
+ * decode.c
+ *     This module decodes WAL records read using xlogreader.h's APIs for the
+ *     purpose of logical decoding by passing information to the
+ *     reorderbuffer module (containing the actual changes) and to the
+ *     snapbuild module to build a fitting catalog snapshot (to be able to
+ *     properly decode the changes in the reorderbuffer).
+ *
+ * NOTE:
+ *     This basically tries to handle all low level xlog stuff for
+ *      reorderbuffer.c and snapbuild.c. There's some minor leakage where a
+ *      specific record's struct is used to pass data along, but those just
+ *      happen to contain the right amount of data in a convenient
+ *      format. There isn't and shouldn't be much intelligence about the
+ *      contents of records in here except turning them into a more usable
+ *      format.
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *   src/backend/replication/logical/decode.c
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "access/heapam_xlog.h"
+#include "access/transam.h"
+#include "access/xact.h"
+#include "access/xlog_internal.h"
+#include "access/xlogreader.h"
+
+#include "catalog/pg_control.h"
+
+#include "replication/decode.h"
+#include "replication/logical.h"
+#include "replication/reorderbuffer.h"
+#include "replication/snapbuild.h"
+
+#include "storage/standby.h"
+
+typedef struct XLogRecordBuffer
+{
+   XLogRecPtr origptr;
+   XLogRecPtr endptr;
+   XLogRecord record;
+   char *record_data;
+} XLogRecordBuffer;
+
+/* RMGR Handlers */
+static void DecodeXLogOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
+static void DecodeHeapOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
+static void DecodeHeap2Op(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
+static void DecodeXactOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
+static void DecodeStandbyOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
+
+/* individual record(group)'s handlers */
+static void DecodeInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
+static void DecodeUpdate(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
+static void DecodeDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
+static void DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
+static void DecodeCommit(LogicalDecodingContext *ctx, XLogRecordBuffer *buf,
+                        TransactionId xid, Oid dboid,
+                        TimestampTz commit_time,
+                        int nsubxacts, TransactionId *sub_xids,
+                        int ninval_msgs, SharedInvalidationMessage *msg);
+static void DecodeAbort(LogicalDecodingContext *ctx, XLogRecPtr lsn,
+           TransactionId xid, TransactionId *sub_xids, int nsubxacts);
+
+/* common function to decode tuples */
+static void DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tup);
+
+/*
+ * Take every XLogReadRecord()ed record and perform the actions required to
+ * decode it using the output plugin already setup in the logical decoding
+ * context.
+ */
+void
+LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogRecord *record)
+{
+   XLogRecordBuffer buf;
+
+   buf.origptr = ctx->reader->ReadRecPtr;
+   buf.endptr = ctx->reader->EndRecPtr;
+   buf.record = *record;
+   buf.record_data = XLogRecGetData(record);
+
+   /* cast so we get a warning when new rmgrs are added */
+   switch ((RmgrIds) buf.record.xl_rmid)
+   {
+       /*
+        * Rmgrs we care about for logical decoding. Add new rmgrs in
+        * rmgrlist.h's order.
+        */
+       case RM_XLOG_ID:
+           DecodeXLogOp(ctx, &buf);
+           break;
+
+       case RM_XACT_ID:
+           DecodeXactOp(ctx, &buf);
+           break;
+
+       case RM_STANDBY_ID:
+           DecodeStandbyOp(ctx, &buf);
+           break;
+
+       case RM_HEAP2_ID:
+           DecodeHeap2Op(ctx, &buf);
+           break;
+
+       case RM_HEAP_ID:
+           DecodeHeapOp(ctx, &buf);
+           break;
+
+       /*
+        * Rmgrs irrelevant for logical decoding; they describe stuff not
+        * represented in logical decoding. Add new rmgrs in rmgrlist.h's
+        * order.
+        */
+       case RM_SMGR_ID:
+       case RM_CLOG_ID:
+       case RM_DBASE_ID:
+       case RM_TBLSPC_ID:
+       case RM_MULTIXACT_ID:
+       case RM_RELMAP_ID:
+       case RM_BTREE_ID:
+       case RM_HASH_ID:
+       case RM_GIN_ID:
+       case RM_GIST_ID:
+       case RM_SEQ_ID:
+       case RM_SPGIST_ID:
+           break;
+       case RM_NEXT_ID:
+           elog(ERROR, "unexpected RM_NEXT_ID rmgr_id: %u", (RmgrIds) buf.record.xl_rmid);
+   }
+}
+
+/*
+ * Handle rmgr XLOG_ID records for DecodeRecordIntoReorderBuffer().
+ */
+static void
+DecodeXLogOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
+{
+   SnapBuild  *builder = ctx->snapshot_builder;
+   uint8       info = buf->record.xl_info & ~XLR_INFO_MASK;
+
+   switch (info)
+   {
+       /* this is also used in END_OF_RECOVERY checkpoints */
+       case XLOG_CHECKPOINT_SHUTDOWN:
+       case XLOG_END_OF_RECOVERY:
+           SnapBuildSerializationPoint(builder, buf->origptr);
+
+           break;
+       case XLOG_CHECKPOINT_ONLINE:
+           /*
+            * a RUNNING_XACTS record will have been logged near to this, we
+            * can restart from there.
+            */
+           break;
+       case XLOG_NOOP:
+       case XLOG_NEXTOID:
+       case XLOG_SWITCH:
+       case XLOG_BACKUP_END:
+       case XLOG_PARAMETER_CHANGE:
+       case XLOG_RESTORE_POINT:
+       case XLOG_FPW_CHANGE:
+       case XLOG_FPI:
+           break;
+       default:
+           elog(ERROR, "unexpected RM_XLOG_ID record type: %u", info);
+   }
+}
+
+/*
+ * Handle rmgr XACT_ID records for DecodeRecordIntoReorderBuffer().
+ */
+static void
+DecodeXactOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
+{
+   SnapBuild      *builder = ctx->snapshot_builder;
+   ReorderBuffer  *reorder = ctx->reorder;
+   XLogRecord     *r = &buf->record;
+   uint8       info = r->xl_info & ~XLR_INFO_MASK;
+
+   /* no point in doing anything yet, data could not be decoded anyway */
+   if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT)
+       return;
+
+   switch (info)
+   {
+       case XLOG_XACT_COMMIT:
+           {
+               xl_xact_commit *xlrec;
+               TransactionId *subxacts = NULL;
+               SharedInvalidationMessage *invals = NULL;
+
+               xlrec = (xl_xact_commit *) buf->record_data;
+
+               subxacts = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
+               invals = (SharedInvalidationMessage *) &(subxacts[xlrec->nsubxacts]);
+
+               DecodeCommit(ctx, buf, r->xl_xid, xlrec->dbId,
+                            xlrec->xact_time,
+                            xlrec->nsubxacts, subxacts,
+                            xlrec->nmsgs, invals);
+
+               break;
+           }
+       case XLOG_XACT_COMMIT_PREPARED:
+           {
+               xl_xact_commit_prepared *prec;
+               xl_xact_commit *xlrec;
+               TransactionId *subxacts;
+               SharedInvalidationMessage *invals = NULL;
+
+               /* Prepared commits contain a normal commit record... */
+               prec = (xl_xact_commit_prepared *) buf->record_data;
+               xlrec = &prec->crec;
+
+               subxacts = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
+               invals = (SharedInvalidationMessage *) &(subxacts[xlrec->nsubxacts]);
+
+               DecodeCommit(ctx, buf, r->xl_xid, xlrec->dbId,
+                            xlrec->xact_time,
+                            xlrec->nsubxacts, subxacts,
+                            xlrec->nmsgs, invals);
+
+               break;
+           }
+       case XLOG_XACT_COMMIT_COMPACT:
+           {
+               xl_xact_commit_compact *xlrec;
+
+               xlrec = (xl_xact_commit_compact *) buf->record_data;
+
+               DecodeCommit(ctx, buf, r->xl_xid, InvalidOid,
+                            xlrec->xact_time,
+                            xlrec->nsubxacts, xlrec->subxacts,
+                            0, NULL);
+               break;
+           }
+       case XLOG_XACT_ABORT:
+           {
+               xl_xact_abort *xlrec;
+               TransactionId *sub_xids;
+
+               xlrec = (xl_xact_abort *) buf->record_data;
+
+               sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
+
+               DecodeAbort(ctx, buf->origptr, r->xl_xid,
+                           sub_xids, xlrec->nsubxacts);
+               break;
+           }
+       case XLOG_XACT_ABORT_PREPARED:
+           {
+               xl_xact_abort_prepared *prec;
+               xl_xact_abort *xlrec;
+               TransactionId *sub_xids;
+
+               /* prepared abort contain a normal commit abort... */
+               prec = (xl_xact_abort_prepared *) buf->record_data;
+               xlrec = &prec->arec;
+
+               sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
+
+               /* r->xl_xid is committed in a separate record */
+               DecodeAbort(ctx, buf->origptr, prec->xid,
+                           sub_xids, xlrec->nsubxacts);
+               break;
+           }
+
+       case XLOG_XACT_ASSIGNMENT:
+           {
+               xl_xact_assignment *xlrec;
+               int         i;
+               TransactionId *sub_xid;
+
+               xlrec = (xl_xact_assignment *) buf->record_data;
+
+               sub_xid = &xlrec->xsub[0];
+
+               for (i = 0; i < xlrec->nsubxacts; i++)
+               {
+                   ReorderBufferAssignChild(reorder, xlrec->xtop,
+                                            *(sub_xid++), buf->origptr);
+               }
+               break;
+           }
+       case XLOG_XACT_PREPARE:
+           /*
+            * Currently decoding ignores PREPARE TRANSACTION and will just
+            * decode the transaction when the COMMIT PREPARED is sent or
+            * throw away the transaction's contents when a ROLLBACK PREPARED
+            * is received. In the future we could add code to expose prepared
+            * transactions in the changestream allowing for a kind of
+            * distributed 2PC.
+            */
+           break;
+       default:
+           elog(ERROR, "unexpected RM_XACT_ID record type: %u", info);
+   }
+}
+
+/*
+ * Handle rmgr STANDBY_ID records for DecodeRecordIntoReorderBuffer().
+ */
+static void
+DecodeStandbyOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
+{
+   SnapBuild  *builder = ctx->snapshot_builder;
+   XLogRecord *r = &buf->record;
+   uint8       info = r->xl_info & ~XLR_INFO_MASK;
+
+   switch (info)
+   {
+       case XLOG_RUNNING_XACTS:
+           {
+               xl_running_xacts *running = (xl_running_xacts *) buf->record_data;
+               SnapBuildProcessRunningXacts(builder, buf->origptr, running);
+               /*
+                * Abort all transactions that we keep track of, that are
+                * older than the record's oldestRunningXid. This is the most
+                * convenient spot for doing so since, in contrast to shutdown
+                * or end-of-recovery checkpoints, we have information about
+                * all running transactions which includes prepared ones,
+                * while shutdown checkpoints just know that no non-prepared
+                * transactions are in progress.
+                */
+               ReorderBufferAbortOld(ctx->reorder, running->oldestRunningXid);
+           }
+           break;
+       case XLOG_STANDBY_LOCK:
+           break;
+       default:
+           elog(ERROR, "unexpected RM_STANDBY_ID record type: %u", info);
+   }
+}
+
+/*
+ * Handle rmgr HEAP2_ID records for DecodeRecordIntoReorderBuffer().
+ */
+static void
+DecodeHeap2Op(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
+{
+   uint8       info = buf->record.xl_info & XLOG_HEAP_OPMASK;
+   TransactionId xid = buf->record.xl_xid;
+   SnapBuild  *builder = ctx->snapshot_builder;
+
+   /* no point in doing anything yet */
+   if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT)
+       return;
+
+   switch (info)
+   {
+       case XLOG_HEAP2_MULTI_INSERT:
+           if (SnapBuildProcessChange(builder, xid, buf->origptr))
+               DecodeMultiInsert(ctx, buf);
+           break;
+       case XLOG_HEAP2_NEW_CID:
+           {
+               xl_heap_new_cid *xlrec;
+               xlrec = (xl_heap_new_cid *) buf->record_data;
+               SnapBuildProcessNewCid(builder, xid, buf->origptr, xlrec);
+
+               break;
+           }
+       case XLOG_HEAP2_REWRITE:
+           /*
+            * Although these records only exist to serve the needs of logical
+            * decoding, all the work happens as part of crash or archive
+            * recovery, so we don't need to do anything here.
+            */
+           break;
+       /*
+        * Everything else here is just low level physical stuff we're
+        * not interested in.
+        */
+       case XLOG_HEAP2_FREEZE_PAGE:
+       case XLOG_HEAP2_CLEAN:
+       case XLOG_HEAP2_CLEANUP_INFO:
+       case XLOG_HEAP2_VISIBLE:
+       case XLOG_HEAP2_LOCK_UPDATED:
+           break;
+       default:
+           elog(ERROR, "unexpected RM_HEAP2_ID record type: %u", info);
+   }
+}
+
+/*
+ * Handle rmgr HEAP_ID records for DecodeRecordIntoReorderBuffer().
+ */
+static void
+DecodeHeapOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
+{
+   uint8       info = buf->record.xl_info & XLOG_HEAP_OPMASK;
+   TransactionId xid = buf->record.xl_xid;
+   SnapBuild  *builder = ctx->snapshot_builder;
+
+   /* no point in doing anything yet */
+   if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT)
+       return;
+
+   switch (info)
+   {
+       case XLOG_HEAP_INSERT:
+           if (SnapBuildProcessChange(builder, xid, buf->origptr))
+               DecodeInsert(ctx, buf);
+           break;
+
+           /*
+            * Treat HOT update as normal updates. There is no useful
+            * information in the fact that we could make it a HOT update
+            * locally and the WAL layout is compatible.
+            */
+       case XLOG_HEAP_HOT_UPDATE:
+       case XLOG_HEAP_UPDATE:
+           if (SnapBuildProcessChange(builder, xid, buf->origptr))
+               DecodeUpdate(ctx, buf);
+           break;
+
+       case XLOG_HEAP_DELETE:
+           if (SnapBuildProcessChange(builder, xid, buf->origptr))
+               DecodeDelete(ctx, buf);
+           break;
+
+       case XLOG_HEAP_NEWPAGE:
+           /*
+            * This is only used in places like indexams and CLUSTER which
+            * don't contain changes relevant for logical replication.
+            */
+           break;
+
+       case XLOG_HEAP_INPLACE:
+           /*
+            * Inplace updates are only ever performed on catalog tuples and
+            * can, per definition, not change tuple visibility.  Since we
+            * don't decode catalog tuples, we're not interested in the
+            * record's contents.
+            *
+            * In-place updates can be used either by XID-bearing transactions
+            * (e.g.  in CREATE INDEX CONCURRENTLY) or by XID-less
+            * transactions (e.g.  VACUUM).  In the former case, the commit
+            * record will include cache invalidations, so we mark the
+            * transaction as catalog modifying here. Currently that's
+            * redundant because the commit will do that as well, but once we
+            * support decoding in-progress relations, this will be important.
+            */
+           if (!TransactionIdIsValid(xid))
+               break;
+
+           SnapBuildProcessChange(builder, xid, buf->origptr);
+           ReorderBufferXidSetCatalogChanges(ctx->reorder, xid, buf->origptr);
+           break;
+
+       case XLOG_HEAP_LOCK:
+           /* we don't care about row level locks for now */
+           break;
+
+       default:
+           elog(ERROR, "unexpected RM_HEAP_ID record type: %u", info);
+           break;
+   }
+}
+
+/*
+ * Consolidated commit record handling between the different form of commit
+ * records.
+ */
+static void
+DecodeCommit(LogicalDecodingContext *ctx, XLogRecordBuffer *buf,
+            TransactionId xid, Oid dboid,
+            TimestampTz commit_time,
+            int nsubxacts, TransactionId *sub_xids,
+            int ninval_msgs, SharedInvalidationMessage *msgs)
+{
+   int         i;
+
+   /*
+    * Process invalidation messages, even if we're not interested in the
+    * transaction's contents, since the various caches need to always be
+    * consistent.
+    */
+   if (ninval_msgs > 0)
+   {
+       ReorderBufferAddInvalidations(ctx->reorder, xid, buf->origptr,
+                                     ninval_msgs, msgs);
+       ReorderBufferXidSetCatalogChanges(ctx->reorder, xid, buf->origptr);
+   }
+
+   SnapBuildCommitTxn(ctx->snapshot_builder, buf->origptr, xid,
+                      nsubxacts, sub_xids);
+
+   /* ----
+    * Check whether we are interested in this specific transaction, and tell
+    * the the reorderbuffer to forget the content of the (sub-)transactions
+    * if not.
+    *
+    * There basically two reasons we might not be interested in this
+    * transaction:
+    * 1) We might not be interested in decoding transactions up to this
+    *    LSN. This can happen because we previously decoded it and now just
+    *    are restarting or if we haven't assembled a consistent snapshot yet.
+    * 2) The transaction happened in another database.
+    *
+    * We can't just use ReorderBufferAbort() here, because we need to execute
+    * the transaction's invalidations.  This currently won't be needed if
+    * we're just skipping over the transaction because currently we only do
+    * so during startup, to get to the first transaction the client needs. As
+    * we have reset the catalog caches before starting to read WAL, and we
+    * haven't yet touched any catalogs, there can't be anything to invalidate.
+    * But if we're "forgetting" this commit because it's it happened in
+    * another database, the invalidations might be important, because they
+    * could be for shared catalogs and we might have loaded data into the
+    * relevant syscaches.
+    * ---
+    */
+   if (SnapBuildXactNeedsSkip(ctx->snapshot_builder, buf->origptr) ||
+       (dboid != InvalidOid && dboid != ctx->slot->data.database))
+   {
+       for (i = 0; i < nsubxacts; i++)
+       {
+           ReorderBufferForget(ctx->reorder, *sub_xids, buf->origptr);
+           sub_xids++;
+       }
+       ReorderBufferForget(ctx->reorder, xid, buf->origptr);
+
+       return;
+   }
+
+   /* tell the reorderbuffer about the surviving subtransactions */
+   for (i = 0; i < nsubxacts; i++)
+   {
+       ReorderBufferCommitChild(ctx->reorder, xid, *sub_xids,
+                                buf->origptr, buf->endptr);
+       sub_xids++;
+   }
+
+   /* replay actions of all transaction + subtransactions in order */
+   ReorderBufferCommit(ctx->reorder, xid, buf->origptr, buf->endptr,
+                       commit_time);
+}
+
+/*
+ * Get the data from the various forms of abort records and pass it on to
+ * snapbuild.c and reorderbuffer.c
+ */
+static void
+DecodeAbort(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
+           TransactionId *sub_xids, int nsubxacts)
+{
+   int         i;
+
+   SnapBuildAbortTxn(ctx->snapshot_builder, lsn, xid, nsubxacts, sub_xids);
+
+   for (i = 0; i < nsubxacts; i++)
+   {
+       ReorderBufferAbort(ctx->reorder, *sub_xids, lsn);
+       sub_xids++;
+   }
+
+   ReorderBufferAbort(ctx->reorder, xid, lsn);
+}
+
+/*
+ * Parse XLOG_HEAP_INSERT (not MULTI_INSERT!) records into tuplebufs.
+ *
+ * Deletes can contain the new tuple.
+ */
+static void
+DecodeInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
+{
+   XLogRecord *r = &buf->record;
+   xl_heap_insert *xlrec;
+   ReorderBufferChange *change;
+
+   xlrec = (xl_heap_insert *) buf->record_data;
+
+   /* only interested in our database */
+   if (xlrec->target.node.dbNode != ctx->slot->data.database)
+       return;
+
+   change = ReorderBufferGetChange(ctx->reorder);
+   change->action = REORDER_BUFFER_CHANGE_INSERT;
+   memcpy(&change->tp.relnode, &xlrec->target.node, sizeof(RelFileNode));
+
+   if (xlrec->flags & XLOG_HEAP_CONTAINS_NEW_TUPLE)
+   {
+       Assert(r->xl_len > (SizeOfHeapInsert + SizeOfHeapHeader));
+
+       change->tp.newtuple = ReorderBufferGetTupleBuf(ctx->reorder);
+
+       DecodeXLogTuple((char *) xlrec + SizeOfHeapInsert,
+                       r->xl_len - SizeOfHeapInsert,
+                       change->tp.newtuple);
+   }
+
+   ReorderBufferQueueChange(ctx->reorder, r->xl_xid, buf->origptr, change);
+}
+
+/*
+ * Parse XLOG_HEAP_UPDATE and XLOG_HEAP_HOT_UPDATE, which have the same layout
+ * in the record, from wal into proper tuplebufs.
+ *
+ * Updates can possibly contain a new tuple and the old primary key.
+ */
+static void
+DecodeUpdate(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
+{
+   XLogRecord *r = &buf->record;
+   xl_heap_update *xlrec;
+   xl_heap_header_len *xlhdr;
+   ReorderBufferChange *change;
+   char       *data;
+
+   xlrec = (xl_heap_update *) buf->record_data;
+   xlhdr = (xl_heap_header_len *) (buf->record_data + SizeOfHeapUpdate);
+
+   /* only interested in our database */
+   if (xlrec->target.node.dbNode != ctx->slot->data.database)
+       return;
+
+   change = ReorderBufferGetChange(ctx->reorder);
+   change->action = REORDER_BUFFER_CHANGE_UPDATE;
+   memcpy(&change->tp.relnode, &xlrec->target.node, sizeof(RelFileNode));
+
+   data = (char *) &xlhdr->header;
+
+   if (xlrec->flags & XLOG_HEAP_CONTAINS_NEW_TUPLE)
+   {
+       Assert(r->xl_len > (SizeOfHeapUpdate + SizeOfHeapHeaderLen));
+
+       change->tp.newtuple = ReorderBufferGetTupleBuf(ctx->reorder);
+
+       DecodeXLogTuple(data,
+                       xlhdr->t_len + SizeOfHeapHeader,
+                       change->tp.newtuple);
+       /* skip over the rest of the tuple header */
+       data += SizeOfHeapHeader;
+       /* skip over the tuple data */
+       data += xlhdr->t_len;
+   }
+
+   if (xlrec->flags & XLOG_HEAP_CONTAINS_OLD)
+   {
+       xlhdr = (xl_heap_header_len *) data;
+       change->tp.oldtuple = ReorderBufferGetTupleBuf(ctx->reorder);
+       DecodeXLogTuple((char *) &xlhdr->header,
+                       xlhdr->t_len + SizeOfHeapHeader,
+                       change->tp.oldtuple);
+       data = (char *) &xlhdr->header;
+       data += SizeOfHeapHeader;
+       data += xlhdr->t_len;
+   }
+
+   ReorderBufferQueueChange(ctx->reorder, r->xl_xid, buf->origptr, change);
+}
+
+/*
+ * Parse XLOG_HEAP_DELETE from wal into proper tuplebufs.
+ *
+ * Deletes can possibly contain the old primary key.
+ */
+static void
+DecodeDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
+{
+   XLogRecord *r = &buf->record;
+   xl_heap_delete *xlrec;
+   ReorderBufferChange *change;
+
+   xlrec = (xl_heap_delete *) buf->record_data;
+
+   /* only interested in our database */
+   if (xlrec->target.node.dbNode != ctx->slot->data.database)
+       return;
+
+   change = ReorderBufferGetChange(ctx->reorder);
+   change->action = REORDER_BUFFER_CHANGE_DELETE;
+
+   memcpy(&change->tp.relnode, &xlrec->target.node, sizeof(RelFileNode));
+
+   /* old primary key stored */
+   if (xlrec->flags & XLOG_HEAP_CONTAINS_OLD)
+   {
+       Assert(r->xl_len > (SizeOfHeapDelete + SizeOfHeapHeader));
+
+       change->tp.oldtuple = ReorderBufferGetTupleBuf(ctx->reorder);
+
+       DecodeXLogTuple((char *) xlrec + SizeOfHeapDelete,
+                       r->xl_len - SizeOfHeapDelete,
+                       change->tp.oldtuple);
+   }
+   ReorderBufferQueueChange(ctx->reorder, r->xl_xid, buf->origptr, change);
+}
+
+/*
+ * Decode XLOG_HEAP2_MULTI_INSERT_insert record into multiple tuplebufs.
+ *
+ * Currently MULTI_INSERT will always contain the full tuples.
+ */
+static void
+DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
+{
+   XLogRecord *r = &buf->record;
+   xl_heap_multi_insert *xlrec;
+   int         i;
+   char       *data;
+   bool        isinit = (r->xl_info & XLOG_HEAP_INIT_PAGE) != 0;
+
+   xlrec = (xl_heap_multi_insert *) buf->record_data;
+
+   /* only interested in our database */
+   if (xlrec->node.dbNode != ctx->slot->data.database)
+       return;
+
+   data = buf->record_data + SizeOfHeapMultiInsert;
+
+   /*
+    * OffsetNumbers (which are not of interest to us) are stored when
+    * XLOG_HEAP_INIT_PAGE is not set -- skip over them.
+    */
+   if (!isinit)
+       data += sizeof(OffsetNumber) * xlrec->ntuples;
+
+   for (i = 0; i < xlrec->ntuples; i++)
+   {
+       ReorderBufferChange *change;
+       xl_multi_insert_tuple *xlhdr;
+       int         datalen;
+       ReorderBufferTupleBuf *tuple;
+
+       change = ReorderBufferGetChange(ctx->reorder);
+       change->action = REORDER_BUFFER_CHANGE_INSERT;
+       memcpy(&change->tp.relnode, &xlrec->node, sizeof(RelFileNode));
+
+       /*
+        * CONTAINS_NEW_TUPLE will always be set currently as multi_insert
+        * isn't used for catalogs, but better be future proof.
+        *
+        * We decode the tuple in pretty much the same way as DecodeXLogTuple,
+        * but since the layout is slightly different, we can't use it here.
+        */
+       if (xlrec->flags & XLOG_HEAP_CONTAINS_NEW_TUPLE)
+       {
+           change->tp.newtuple = ReorderBufferGetTupleBuf(ctx->reorder);
+
+           tuple = change->tp.newtuple;
+
+           /* not a disk based tuple */
+           ItemPointerSetInvalid(&tuple->tuple.t_self);
+
+           xlhdr = (xl_multi_insert_tuple *) SHORTALIGN(data);
+           data = ((char *) xlhdr) + SizeOfMultiInsertTuple;
+           datalen = xlhdr->datalen;
+
+           /*
+            * We can only figure this out after reassembling the
+            * transactions.
+            */
+           tuple->tuple.t_tableOid = InvalidOid;
+           tuple->tuple.t_data = &tuple->header;
+           tuple->tuple.t_len = datalen
+               + offsetof(HeapTupleHeaderData, t_bits);
+
+           memset(&tuple->header, 0, sizeof(HeapTupleHeaderData));
+
+           memcpy((char *) &tuple->header
+                  + offsetof(HeapTupleHeaderData, t_bits),
+                  (char *) data,
+                  datalen);
+           data += datalen;
+
+           tuple->header.t_infomask = xlhdr->t_infomask;
+           tuple->header.t_infomask2 = xlhdr->t_infomask2;
+           tuple->header.t_hoff = xlhdr->t_hoff;
+       }
+
+       ReorderBufferQueueChange(ctx->reorder, r->xl_xid,
+                                buf->origptr, change);
+   }
+}
+
+/*
+ * Read a HeapTuple as WAL logged by heap_insert, heap_update and heap_delete
+ * (but not by heap_multi_insert) into a tuplebuf.
+ *
+ * The size 'len' and the pointer 'data' in the record need to be
+ * computed outside as they are record specific.
+ */
+static void
+DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple)
+{
+   xl_heap_header xlhdr;
+   int         datalen = len - SizeOfHeapHeader;
+
+   Assert(datalen >= 0);
+   Assert(datalen <= MaxHeapTupleSize);
+
+   tuple->tuple.t_len = datalen + offsetof(HeapTupleHeaderData, t_bits);
+
+   /* not a disk based tuple */
+   ItemPointerSetInvalid(&tuple->tuple.t_self);
+
+   /* we can only figure this out after reassembling the transactions */
+   tuple->tuple.t_tableOid = InvalidOid;
+   tuple->tuple.t_data = &tuple->header;
+
+   /* data is not stored aligned, copy to aligned storage */
+   memcpy((char *) &xlhdr,
+          data,
+          SizeOfHeapHeader);
+
+   memset(&tuple->header, 0, sizeof(HeapTupleHeaderData));
+
+   memcpy((char *) &tuple->header + offsetof(HeapTupleHeaderData, t_bits),
+          data + SizeOfHeapHeader,
+          datalen);
+
+   tuple->header.t_infomask = xlhdr.t_infomask;
+   tuple->header.t_infomask2 = xlhdr.t_infomask2;
+   tuple->header.t_hoff = xlhdr.t_hoff;
+}
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
new file mode 100644 (file)
index 0000000..4fb0974
--- /dev/null
@@ -0,0 +1,920 @@
+/*-------------------------------------------------------------------------
+ * logical.c
+ *    PostgreSQL logical decoding coordination
+ *
+ * Copyright (c) 2012-2014, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/backend/replication/logical/logical.c
+ *
+ * NOTES
+ *    This file coordinates interaction between the various modules that
+ *    together providethe logical decoding, primarily by providing so
+ *    called LogicalDecodingContexts. The goal is to encapsulate most of the
+ *    internal complexity for consumers of logical decoding, so they can
+ *    create and consume a changestream with a low amount of code.
+ *
+ *    The idea is that a consumer provides three callbacks, one to read WAL,
+ *    one to prepare a data write, and a final one for actually writing since
+ *    their implementation depends on the type of consumer.  Check
+ *    logicalfunc.c for an example implementations of a fairly simple consumer
+ *    and a implementation of a WAL reading callback that's suitable for
+ *    simpler consumers.
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include 
+#include 
+
+#include "miscadmin.h"
+
+#include "access/xact.h"
+
+#include "replication/decode.h"
+#include "replication/logical.h"
+#include "replication/reorderbuffer.h"
+#include "replication/snapbuild.h"
+
+#include "storage/proc.h"
+#include "storage/procarray.h"
+
+#include "utils/memutils.h"
+
+/* data for errcontext callback */
+typedef struct LogicalErrorCallbackState
+{
+   LogicalDecodingContext *ctx;
+   const char *callback_name;
+   XLogRecPtr  report_location;
+} LogicalErrorCallbackState;
+
+/* wrappers around output plugin callbacks */
+static void output_plugin_error_callback(void *arg);
+static void startup_cb_wrapper(LogicalDecodingContext *ctx, OutputPluginOptions *opt,
+                                bool is_init);
+static void shutdown_cb_wrapper(LogicalDecodingContext *ctx);
+static void begin_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn);
+static void commit_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn,
+                              XLogRecPtr commit_lsn);
+static void change_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn,
+                          Relation relation, ReorderBufferChange *change);
+
+static void LoadOutputPlugin(OutputPluginCallbacks *callbacks, char *plugin);
+
+/*
+ * Make sure the current settings & environment are capable of doing logical
+ * decoding.
+ */
+void
+CheckLogicalDecodingRequirements(void)
+{
+   CheckSlotRequirements();
+
+   if (wal_level < WAL_LEVEL_LOGICAL)
+       ereport(ERROR,
+               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                errmsg("logical decoding requires wal_level >= logical")));
+
+   if (MyDatabaseId == InvalidOid)
+       ereport(ERROR,
+               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                errmsg("logical decoding requires a database connection")));
+
+   /* ----
+    * TODO: We got to change that someday soon...
+    *
+    * There's basically three things missing to allow this:
+    * 1) We need to be able to correctly and quickly identify the timeline a
+    *    LSN belongs to
+    * 2) We need to force hot_standby_feedback to be enabled at all times so
+    *    the primary cannot remove rows we need.
+    * 3) support dropping replication slots referring to a database, in
+    *    dbase_redo. There can't be any active ones due to HS recovery
+    *    conflicts, so that should be relatively easy.
+    * ----
+    */
+   if (RecoveryInProgress())
+       ereport(ERROR,
+               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                errmsg("logical decoding cannot be used while in recovery")));
+}
+
+/*
+ * Helper function for CreateInitialDecodingContext() and
+ * CreateDecodingContext() performing common tasks.
+ */
+static LogicalDecodingContext *
+StartupDecodingContext(List *output_plugin_options,
+                      XLogRecPtr start_lsn,
+                      TransactionId xmin_horizon,
+                      XLogPageReadCB read_page,
+                      LogicalOutputPluginWriterPrepareWrite prepare_write,
+                      LogicalOutputPluginWriterWrite do_write)
+{
+   ReplicationSlot *slot;
+   MemoryContext context, old_context;
+   LogicalDecodingContext *ctx;
+
+   /* shorter lines... */
+   slot = MyReplicationSlot;
+
+   context = AllocSetContextCreate(CurrentMemoryContext,
+                                   "Changeset Extraction Context",
+                                   ALLOCSET_DEFAULT_MINSIZE,
+                                   ALLOCSET_DEFAULT_INITSIZE,
+                                   ALLOCSET_DEFAULT_MAXSIZE);
+   old_context = MemoryContextSwitchTo(context);
+   ctx = palloc0(sizeof(LogicalDecodingContext));
+
+   ctx->context = context;
+
+   /* (re-)load output plugins, so we detect a bad (removed) output plugin now. */
+   LoadOutputPlugin(&ctx->callbacks, NameStr(slot->data.plugin));
+
+   /*
+    * Now that the slot's xmin has been set, we can announce ourselves as a
+    * logical decoding backend which doesn't need to be checked individually
+    * when computing the xmin horizon because the xmin is enforced via
+    * replication slots.
+    */
+   LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+   MyPgXact->vacuumFlags |= PROC_IN_LOGICAL_DECODING;
+   LWLockRelease(ProcArrayLock);
+
+   ctx->slot = slot;
+
+   ctx->reader = XLogReaderAllocate(read_page, ctx);
+   ctx->reader->private_data = ctx;
+
+   ctx->reorder = ReorderBufferAllocate();
+   ctx->snapshot_builder =
+       AllocateSnapshotBuilder(ctx->reorder, xmin_horizon, start_lsn);
+
+   ctx->reorder->private_data = ctx;
+
+   /* wrap output plugin callbacks, so we can add error context information */
+   ctx->reorder->begin = begin_cb_wrapper;
+   ctx->reorder->apply_change = change_cb_wrapper;
+   ctx->reorder->commit = commit_cb_wrapper;
+
+   ctx->out = makeStringInfo();
+   ctx->prepare_write = prepare_write;
+   ctx->write = do_write;
+
+   ctx->output_plugin_options = output_plugin_options;
+
+   MemoryContextSwitchTo(old_context);
+
+   return ctx;
+}
+
+/*
+ * Create a new decoding context, for a new logical slot.
+ *
+ * plugin contains the name of the output plugin
+ * output_plugin_options contains options passed to the output plugin
+ * read_page, prepare_write, do_write are callbacks that have to be filled to
+ *     perform the use-case dependent, actual, work.
+ *
+ * Needs to be called while in a memory context that's at least as long lived
+ * as the the decoding context because further memory contexts will be created
+ * inside it.
+ *
+ * Returns an initialized decoding context after calling the output plugin's
+ * startup function.
+ */
+LogicalDecodingContext *
+CreateInitDecodingContext(char *plugin,
+                         List *output_plugin_options,
+                         XLogPageReadCB read_page,
+                         LogicalOutputPluginWriterPrepareWrite prepare_write,
+                         LogicalOutputPluginWriterWrite do_write)
+{
+   TransactionId   xmin_horizon = InvalidTransactionId;
+   ReplicationSlot *slot;
+   LogicalDecodingContext *ctx;
+   MemoryContext   old_context;
+
+   /* shorter lines... */
+   slot = MyReplicationSlot;
+
+   /* first some sanity checks that are unlikely to be violated */
+   if (slot == NULL)
+       elog(ERROR, "cannot perform logical decoding without a acquired slot");
+
+   if (plugin == NULL)
+       elog(ERROR, "cannot initialize logical decoding without a specified plugin");
+
+   /* Make sure the passed slot is suitable. These are user facing errors. */
+   if (slot->data.database == InvalidOid)
+       ereport(ERROR,
+               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                errmsg("cannot use physical replication slot created for logical decoding")));
+
+   if (slot->data.database != MyDatabaseId)
+       ereport(ERROR,
+               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                errmsg("replication slot \"%s\" was not created in this database",
+                        NameStr(slot->data.name))));
+
+   if (IsTransactionState() &&
+       GetTopTransactionIdIfAny() != InvalidTransactionId)
+       ereport(ERROR,
+               (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
+                errmsg("cannot create logical replication slot in transaction that has performed writes")));
+
+   /* register output plugin name with slot */
+   SpinLockAcquire(&slot->mutex);
+   strncpy(NameStr(slot->data.plugin), plugin,
+           NAMEDATALEN);
+   NameStr(slot->data.plugin)[NAMEDATALEN - 1] = '\0';
+   SpinLockRelease(&slot->mutex);
+
+   /*
+    * The replication slot mechanism is used to prevent removal of required
+    * WAL. As there is no interlock between this and checkpoints required WAL
+    * could be removed before ReplicationSlotsComputeRequiredLSN() has been
+    * called to prevent that. In the very unlikely case that this happens
+    * we'll just retry.
+    */
+   while (true)
+   {
+       XLogSegNo   segno;
+
+       /*
+        * Let's start with enough information if we can, so log a standby
+        * snapshot and start decoding at exactly that position.
+        */
+       if (!RecoveryInProgress())
+       {
+           XLogRecPtr flushptr;
+
+           /* start at current insert position*/
+           slot->data.restart_lsn = GetXLogInsertRecPtr();
+
+           /* make sure we have enough information to start */
+           flushptr = LogStandbySnapshot();
+
+           /* and make sure it's fsynced to disk */
+           XLogFlush(flushptr);
+       }
+       else
+           slot->data.restart_lsn = GetRedoRecPtr();
+
+       /* prevent WAL removal as fast as possible */
+       ReplicationSlotsComputeRequiredLSN();
+
+       /*
+        * If all required WAL is still there, great, otherwise retry. The
+        * slot should prevent further removal of WAL, unless there's a
+        * concurrent ReplicationSlotsComputeRequiredLSN() after we've written
+        * the new restart_lsn above, so normally we should never need to loop
+        * more than twice.
+        */
+       XLByteToSeg(slot->data.restart_lsn, segno);
+       if (XLogGetLastRemovedSegno() < segno)
+           break;
+   }
+
+
+   /* ----
+    * This is a bit tricky: We need to determine a safe xmin horizon to start
+    * decoding from, to avoid starting from a running xacts record referring
+    * to xids whose rows have been vacuumed or pruned
+    * already. GetOldestSafeDecodingTransactionId() returns such a value, but
+    * without further interlock it's return value might immediately be out of
+    * date.
+    *
+    * So we have to acquire the ProcArrayLock to prevent computation of new
+    * xmin horizons by other backends, get the safe decoding xid, and inform
+    * the slot machinery about the new limit. Once that's done the
+    * ProcArrayLock can be be released as the slot machinery now is
+    * protecting against vacuum.
+    * ----
+    */
+   LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+
+   slot->effective_catalog_xmin = GetOldestSafeDecodingTransactionId();
+   slot->data.catalog_xmin = slot->effective_catalog_xmin;
+
+   ReplicationSlotsComputeRequiredXmin(true);
+
+   LWLockRelease(ProcArrayLock);
+
+   /*
+    * tell the snapshot builder to only assemble snapshot once reaching
+    * the a running_xact's record with the respective xmin.
+    */
+   xmin_horizon = slot->data.catalog_xmin;
+
+   ReplicationSlotMarkDirty();
+   ReplicationSlotSave();
+
+   ctx = StartupDecodingContext(NIL, InvalidXLogRecPtr, xmin_horizon,
+                                 read_page, prepare_write, do_write);
+
+   /* call output plugin initialization callback */
+   old_context = MemoryContextSwitchTo(ctx->context);
+   if (ctx->callbacks.startup_cb != NULL)
+       startup_cb_wrapper(ctx, &ctx->options, true);
+   MemoryContextSwitchTo(old_context);
+
+   return ctx;
+}
+
+/*
+ * Create a new decoding context, for a logical slot that has previously been
+ * used already.
+ *
+ * start_lsn contains the LSN of the last received data or InvalidXLogRecPtr
+ * output_plugin_options contains options passed to the output plugin
+ * read_page, prepare_write, do_write are callbacks that have to be filled to
+ *     perform the use-case dependent, actual, work.
+ *
+ * Needs to be called while in a memory context that's at least as long lived
+ * as the the decoding context because further memory contexts will be created
+ * inside it.
+ *
+ * Returns an initialized decoding context after calling the output plugin's
+ * startup function.
+ */
+LogicalDecodingContext *
+CreateDecodingContext(XLogRecPtr start_lsn,
+                     List *output_plugin_options,
+                     XLogPageReadCB read_page,
+                     LogicalOutputPluginWriterPrepareWrite prepare_write,
+                     LogicalOutputPluginWriterWrite do_write)
+{
+   LogicalDecodingContext *ctx;
+   ReplicationSlot *slot;
+   MemoryContext   old_context;
+
+   /* shorter lines... */
+   slot = MyReplicationSlot;
+
+   /* first some sanity checks that are unlikely to be violated */
+   if (slot == NULL)
+       elog(ERROR, "cannot perform logical decoding without a acquired slot");
+
+   /* make sure the passed slot is suitable, these are user facing errors */
+   if (slot->data.database == InvalidOid)
+       ereport(ERROR,
+               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                (errmsg("cannot use physical replication slot for logical decoding"))));
+
+   if (slot->data.database != MyDatabaseId)
+       ereport(ERROR,
+               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                (errmsg("replication slot \"%s\" was not created in this database",
+                        NameStr(slot->data.name)))));
+
+   if (start_lsn == InvalidXLogRecPtr)
+   {
+       /* continue from last position */
+       start_lsn = slot->data.confirmed_flush;
+   }
+   else if (start_lsn < slot->data.confirmed_flush)
+   {
+       /*
+        * It might seem like we should error out in this case, but it's
+        * pretty common for a client to acknowledge a LSN it doesn't have to
+        * do anything for, and thus didn't store persistently, because the
+        * xlog records didn't result in anything relevant for logical
+        * decoding. Clients have to be able to do that to support
+        * synchronous replication.
+        */
+       start_lsn = slot->data.confirmed_flush;
+       elog(DEBUG1, "cannot stream from %X/%X, minimum is %X/%X, forwarding",
+            (uint32)(start_lsn >> 32), (uint32)start_lsn,
+            (uint32)(slot->data.confirmed_flush >> 32),
+            (uint32)slot->data.confirmed_flush);
+   }
+
+   ctx = StartupDecodingContext(output_plugin_options,
+                                start_lsn, InvalidTransactionId,
+                                read_page, prepare_write, do_write);
+
+   /* call output plugin initialization callback */
+   old_context = MemoryContextSwitchTo(ctx->context);
+   if (ctx->callbacks.startup_cb != NULL)
+       startup_cb_wrapper(ctx, &ctx->options, true);
+   MemoryContextSwitchTo(old_context);
+
+   ereport(LOG,
+           (errmsg("starting logical decoding for slot %s",
+                   NameStr(slot->data.name)),
+            errdetail("streaming transactions committing after %X/%X, reading WAL from %X/%X",
+                      (uint32)(slot->data.confirmed_flush >> 32),
+                      (uint32)slot->data.confirmed_flush,
+                      (uint32)(slot->data.restart_lsn >> 32),
+                      (uint32)slot->data.restart_lsn)));
+
+   return ctx;
+}
+
+/*
+ * Returns true if an consistent initial decoding snapshot has been built.
+ */
+bool
+DecodingContextReady(LogicalDecodingContext *ctx)
+{
+   return SnapBuildCurrentState(ctx->snapshot_builder) == SNAPBUILD_CONSISTENT;
+}
+
+/*
+ * Read from the decoding slot, until it is ready to start extracting changes.
+ */
+void
+DecodingContextFindStartpoint(LogicalDecodingContext *ctx)
+{
+   XLogRecPtr  startptr;
+
+   /* Initialize from where to start reading WAL. */
+   startptr = ctx->slot->data.restart_lsn;
+
+   elog(DEBUG1, "searching for logical decoding starting point, starting at %X/%X",
+        (uint32)(ctx->slot->data.restart_lsn >> 32),
+        (uint32)ctx->slot->data.restart_lsn);
+
+   /* Wait for a consistent starting point */
+   for (;;)
+   {
+       XLogRecord *record;
+       char       *err = NULL;
+
+       /*
+        * If the caller requires that interrupts be checked, the read_page
+        * callback should do so, as those will often wait.
+        */
+
+       /* the read_page callback waits for new WAL */
+       record = XLogReadRecord(ctx->reader, startptr, &err);
+       if (err)
+           elog(ERROR, "%s", err);
+
+       Assert(record);
+
+       startptr = InvalidXLogRecPtr;
+
+       LogicalDecodingProcessRecord(ctx, record);
+
+       /* only continue till we found a consistent spot */
+       if (DecodingContextReady(ctx))
+           break;
+   }
+
+   ctx->slot->data.confirmed_flush = ctx->reader->EndRecPtr;
+}
+
+/*
+ * Free a previously allocated decoding context, invoking the shutdown
+ * callback if necessary.
+ */
+void
+FreeDecodingContext(LogicalDecodingContext *ctx)
+{
+   if (ctx->callbacks.shutdown_cb != NULL)
+       shutdown_cb_wrapper(ctx);
+
+   ReorderBufferFree(ctx->reorder);
+   FreeSnapshotBuilder(ctx->snapshot_builder);
+   XLogReaderFree(ctx->reader);
+   MemoryContextDelete(ctx->context);
+}
+
+/*
+ * Prepare a write using the context's output routine.
+ */
+void
+OutputPluginPrepareWrite(struct LogicalDecodingContext *ctx, bool last_write)
+{
+   if (!ctx->accept_writes)
+       elog(ERROR, "writes are only accepted in commit, begin and change callbacks");
+
+   ctx->prepare_write(ctx, ctx->write_location, ctx->write_xid, last_write);
+   ctx->prepared_write = true;
+}
+
+/*
+ * Perform a write using the context's output routine.
+ */
+void
+OutputPluginWrite(struct LogicalDecodingContext *ctx, bool last_write)
+{
+   if (!ctx->prepared_write)
+       elog(ERROR, "OutputPluginPrepareWrite needs to be called before OutputPluginWrite");
+
+   ctx->write(ctx, ctx->write_location, ctx->write_xid, last_write);
+   ctx->prepared_write = false;
+}
+
+/*
+ * Load the output plugin, lookup its output plugin init function, and check
+ * that it provides the required callbacks.
+ */
+static void
+LoadOutputPlugin(OutputPluginCallbacks *callbacks, char *plugin)
+{
+   LogicalOutputPluginInit plugin_init;
+
+   plugin_init = (LogicalOutputPluginInit)
+       load_external_function(plugin, "_PG_output_plugin_init", false, NULL);
+
+   if (plugin_init == NULL)
+       elog(ERROR, "output plugins have to declare the _PG_output_plugin_init symbol");
+
+   /* ask the output plugin to fill the callback struct */
+   plugin_init(callbacks);
+
+   if (callbacks->begin_cb == NULL)
+       elog(ERROR, "output plugins have to register a begin callback");
+   if (callbacks->change_cb == NULL)
+       elog(ERROR, "output plugins have to register a change callback");
+   if (callbacks->commit_cb == NULL)
+       elog(ERROR, "output plugins have to register a commit callback");
+}
+
+static void
+output_plugin_error_callback(void *arg)
+{
+   LogicalErrorCallbackState *state = (LogicalErrorCallbackState *) arg;
+   /* not all callbacks have an associated LSN  */
+   if (state->report_location != InvalidXLogRecPtr)
+       errcontext("slot \"%s\", output plugin \"%s\", in the %s callback, associated LSN %X/%X",
+                  NameStr(state->ctx->slot->data.name),
+                  NameStr(state->ctx->slot->data.plugin),
+                  state->callback_name,
+                  (uint32)(state->report_location >> 32),
+                  (uint32)state->report_location);
+   else
+       errcontext("slot \"%s\", output plugin \"%s\", in the %s callback",
+                  NameStr(state->ctx->slot->data.name),
+                  NameStr(state->ctx->slot->data.plugin),
+                  state->callback_name);
+}
+
+static void
+startup_cb_wrapper(LogicalDecodingContext *ctx, OutputPluginOptions *opt, bool is_init)
+{
+   LogicalErrorCallbackState state;
+   ErrorContextCallback errcallback;
+
+   /* Push callback + info on the error context stack */
+   state.ctx = ctx;
+   state.callback_name = "startup";
+   state.report_location = InvalidXLogRecPtr;
+   errcallback.callback = output_plugin_error_callback;
+   errcallback.arg = (void *) &state;
+   errcallback.previous = error_context_stack;
+   error_context_stack = &errcallback;
+
+   /* set output state */
+   ctx->accept_writes = false;
+
+   /* do the actual work: call callback */
+   ctx->callbacks.startup_cb(ctx, opt, is_init);
+
+   /* Pop the error context stack */
+   error_context_stack = errcallback.previous;
+}
+
+static void
+shutdown_cb_wrapper(LogicalDecodingContext *ctx)
+{
+   LogicalErrorCallbackState state;
+   ErrorContextCallback errcallback;
+
+   /* Push callback + info on the error context stack */
+   state.ctx = ctx;
+   state.callback_name = "shutdown";
+   state.report_location = InvalidXLogRecPtr;
+   errcallback.callback = output_plugin_error_callback;
+   errcallback.arg = (void *) &state;
+   errcallback.previous = error_context_stack;
+   error_context_stack = &errcallback;
+
+   /* set output state */
+   ctx->accept_writes = false;
+
+   /* do the actual work: call callback */
+   ctx->callbacks.shutdown_cb(ctx);
+
+   /* Pop the error context stack */
+   error_context_stack = errcallback.previous;
+}
+
+
+/*
+ * Callbacks for ReorderBuffer which add in some more information and then call
+ * output_plugin.h plugins.
+ */
+static void
+begin_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn)
+{
+   LogicalDecodingContext *ctx = cache->private_data;
+   LogicalErrorCallbackState state;
+   ErrorContextCallback errcallback;
+
+   /* Push callback + info on the error context stack */
+   state.ctx = ctx;
+   state.callback_name = "begin";
+   state.report_location = txn->first_lsn;
+   errcallback.callback = output_plugin_error_callback;
+   errcallback.arg = (void *) &state;
+   errcallback.previous = error_context_stack;
+   error_context_stack = &errcallback;
+
+   /* set output state */
+   ctx->accept_writes = true;
+   ctx->write_xid = txn->xid;
+   ctx->write_location = txn->first_lsn;
+
+   /* do the actual work: call callback */
+   ctx->callbacks.begin_cb(ctx, txn);
+
+   /* Pop the error context stack */
+   error_context_stack = errcallback.previous;
+}
+
+static void
+commit_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn,
+                  XLogRecPtr commit_lsn)
+{
+   LogicalDecodingContext *ctx = cache->private_data;
+   LogicalErrorCallbackState state;
+   ErrorContextCallback errcallback;
+
+   /* Push callback + info on the error context stack */
+   state.ctx = ctx;
+   state.callback_name = "commit";
+   state.report_location = txn->final_lsn; /* beginning of commit record */
+   errcallback.callback = output_plugin_error_callback;
+   errcallback.arg = (void *) &state;
+   errcallback.previous = error_context_stack;
+   error_context_stack = &errcallback;
+
+   /* set output state */
+   ctx->accept_writes = true;
+   ctx->write_xid = txn->xid;
+   ctx->write_location = txn->end_lsn; /* points to the end of the record */
+
+   /* do the actual work: call callback */
+   ctx->callbacks.commit_cb(ctx, txn, commit_lsn);
+
+   /* Pop the error context stack */
+   error_context_stack = errcallback.previous;
+}
+
+static void
+change_cb_wrapper(ReorderBuffer *cache, ReorderBufferTXN *txn,
+              Relation relation, ReorderBufferChange *change)
+{
+   LogicalDecodingContext *ctx = cache->private_data;
+   LogicalErrorCallbackState state;
+   ErrorContextCallback errcallback;
+
+   /* Push callback + info on the error context stack */
+   state.ctx = ctx;
+   state.callback_name = "change";
+   state.report_location = change->lsn;
+   errcallback.callback = output_plugin_error_callback;
+   errcallback.arg = (void *) &state;
+   errcallback.previous = error_context_stack;
+   error_context_stack = &errcallback;
+
+   /* set output state */
+   ctx->accept_writes = true;
+   ctx->write_xid = txn->xid;
+   /*
+    * report this change's lsn so replies from clients can give an up2date
+    * answer. This won't ever be enough (and shouldn't be!) to confirm
+    * receipt of this transaction, but it might allow another transaction's
+    * commit to be confirmed with one message.
+    */
+   ctx->write_location = change->lsn;
+
+   ctx->callbacks.change_cb(ctx, txn, relation, change);
+
+   /* Pop the error context stack */
+   error_context_stack = errcallback.previous;
+}
+
+/*
+ * Set the required catalog xmin horizon for historic snapshots in the current
+ * replication slot.
+ *
+ * Note that in the most cases, we won't be able to immediately use the xmin
+ * to increase the xmin horizon, we need to wait till the client has confirmed
+ * receiving current_lsn with LogicalConfirmReceivedLocation().
+ */
+void
+LogicalIncreaseXminForSlot(XLogRecPtr current_lsn, TransactionId xmin)
+{
+   bool    updated_xmin = false;
+   ReplicationSlot *slot;
+
+   slot = MyReplicationSlot;
+
+   Assert(slot != NULL);
+
+   SpinLockAcquire(&slot->mutex);
+
+   /*
+    * don't overwrite if we already have a newer xmin. This can
+    * happen if we restart decoding in a slot.
+    */
+   if (TransactionIdPrecedesOrEquals(xmin, slot->data.catalog_xmin))
+   {
+   }
+   /*
+    * If the client has already confirmed up to this lsn, we directly
+    * can mark this as accepted. This can happen if we restart
+    * decoding in a slot.
+    */
+   else if (current_lsn <= slot->data.confirmed_flush)
+   {
+       slot->candidate_catalog_xmin = xmin;
+       slot->candidate_xmin_lsn = current_lsn;
+
+       /* our candidate can directly be used */
+       updated_xmin = true;
+   }
+   /*
+    * Only increase if the previous values have been applied, otherwise we
+    * might never end up updating if the receiver acks too slowly.
+    */
+   else if (slot->candidate_xmin_lsn == InvalidXLogRecPtr)
+   {
+       slot->candidate_catalog_xmin = xmin;
+       slot->candidate_xmin_lsn = current_lsn;
+   }
+   SpinLockRelease(&slot->mutex);
+
+   /* candidate already valid with the current flush position, apply */
+   if (updated_xmin)
+       LogicalConfirmReceivedLocation(slot->data.confirmed_flush);
+}
+
+/*
+ * Mark the minimal LSN (restart_lsn) we need to read to replay all
+ * transactions that have not yet committed at current_lsn.
+ *
+ * Just like IncreaseRestartDecodingForSlot this nly takes effect when the
+ * client has confirmed to have received current_lsn.
+ */
+void
+LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart_lsn)
+{
+   bool    updated_lsn = false;
+   ReplicationSlot *slot;
+
+   slot = MyReplicationSlot;
+
+   Assert(slot != NULL);
+   Assert(restart_lsn != InvalidXLogRecPtr);
+   Assert(current_lsn != InvalidXLogRecPtr);
+
+   SpinLockAcquire(&slot->mutex);
+
+   /* don't overwrite if have a newer restart lsn*/
+   if (restart_lsn <= slot->data.restart_lsn)
+   {
+   }
+   /*
+    * We might have already flushed far enough to directly accept this lsn, in
+    * this case there is no need to check for existing candidate LSNs
+    */
+   else if (current_lsn <= slot->data.confirmed_flush)
+   {
+       slot->candidate_restart_valid = current_lsn;
+       slot->candidate_restart_lsn = restart_lsn;
+
+       /* our candidate can directly be used */
+       updated_lsn = true;
+   }
+   /*
+    * Only increase if the previous values have been applied, otherwise we
+    * might never end up updating if the receiver acks too slowly. A missed
+    * value here will just cause some extra effort after reconnecting.
+    */
+   if (slot->candidate_restart_valid == InvalidXLogRecPtr)
+   {
+       slot->candidate_restart_valid = current_lsn;
+       slot->candidate_restart_lsn = restart_lsn;
+
+       elog(DEBUG1, "got new restart lsn %X/%X at %X/%X",
+            (uint32) (restart_lsn >> 32), (uint32) restart_lsn,
+            (uint32) (current_lsn >> 32), (uint32) current_lsn);
+   }
+   else
+   {
+       elog(DEBUG1, "failed to increase restart lsn: proposed %X/%X, after %X/%X, current candidate %X/%X, current after %X/%X, flushed up to %X/%X",
+            (uint32) (restart_lsn >> 32), (uint32) restart_lsn,
+            (uint32) (current_lsn >> 32), (uint32) current_lsn,
+            (uint32) (slot->candidate_restart_lsn >> 32),
+            (uint32) slot->candidate_restart_lsn,
+            (uint32) (slot->candidate_restart_valid >> 32),
+            (uint32) slot->candidate_restart_valid,
+            (uint32) (slot->data.confirmed_flush >> 32),
+            (uint32) slot->data.confirmed_flush
+           );
+   }
+   SpinLockRelease(&slot->mutex);
+
+   /* candidates are already valid with the current flush position, apply */
+   if (updated_lsn)
+       LogicalConfirmReceivedLocation(slot->data.confirmed_flush);
+}
+
+/*
+ * Handle a consumer's conformation having received all changes up to lsn.
+ */
+void
+LogicalConfirmReceivedLocation(XLogRecPtr lsn)
+{
+   Assert(lsn != InvalidXLogRecPtr);
+
+   /* Do an unlocked check for candidate_lsn first. */
+   if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr ||
+       MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr)
+   {
+       bool        updated_xmin = false;
+       bool        updated_restart = false;
+
+       /* use volatile pointer to prevent code rearrangement */
+       volatile ReplicationSlot *slot = MyReplicationSlot;
+
+       SpinLockAcquire(&slot->mutex);
+
+       slot->data.confirmed_flush = lsn;
+
+       /* if were past the location required for bumping xmin, do so */
+       if (slot->candidate_xmin_lsn != InvalidXLogRecPtr &&
+           slot->candidate_xmin_lsn <= lsn)
+       {
+           /*
+            * We have to write the changed xmin to disk *before* we change
+            * the in-memory value, otherwise after a crash we wouldn't know
+            * that some catalog tuples might have been removed already.
+            *
+            * Ensure that by first writing to ->xmin and only update
+            * ->effective_xmin once the new state is synced to disk. After a
+            * crash ->effective_xmin is set to ->xmin.
+            */
+           if (TransactionIdIsValid(slot->candidate_catalog_xmin) &&
+               slot->data.catalog_xmin != slot->candidate_catalog_xmin)
+           {
+               slot->data.catalog_xmin = slot->candidate_catalog_xmin;
+               slot->candidate_catalog_xmin = InvalidTransactionId;
+               slot->candidate_xmin_lsn = InvalidXLogRecPtr;
+               updated_xmin = true;
+           }
+       }
+
+       if (slot->candidate_restart_valid != InvalidXLogRecPtr &&
+           slot->candidate_restart_valid <= lsn)
+       {
+           Assert(slot->candidate_restart_lsn != InvalidXLogRecPtr);
+
+           slot->data.restart_lsn = slot->candidate_restart_lsn;
+           slot->candidate_restart_lsn = InvalidXLogRecPtr;
+           slot->candidate_restart_valid = InvalidXLogRecPtr;
+           updated_restart = true;
+       }
+
+       SpinLockRelease(&slot->mutex);
+
+       /* first write new xmin to disk, so we know whats up after a crash */
+       if (updated_xmin || updated_restart)
+       {
+           ReplicationSlotMarkDirty();
+           ReplicationSlotSave();
+           elog(DEBUG1, "updated xmin: %u restart: %u", updated_xmin, updated_restart);
+       }
+       /*
+        * Now the new xmin is safely on disk, we can let the global value
+        * advance. We do not take ProcArrayLock or similar since we only
+        * advance xmin here and there's not much harm done by a concurrent
+        * computation missing that.
+        */
+       if (updated_xmin)
+       {
+           SpinLockAcquire(&slot->mutex);
+           slot->effective_catalog_xmin = slot->data.catalog_xmin;
+           SpinLockRelease(&slot->mutex);
+
+           ReplicationSlotsComputeRequiredXmin(false);
+           ReplicationSlotsComputeRequiredLSN();
+       }
+   }
+   else
+   {
+       volatile ReplicationSlot *slot = MyReplicationSlot;
+
+       SpinLockAcquire(&slot->mutex);
+       slot->data.confirmed_flush = lsn;
+       SpinLockRelease(&slot->mutex);
+   }
+}
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
new file mode 100644 (file)
index 0000000..3b8ae38
--- /dev/null
@@ -0,0 +1,509 @@
+/*-------------------------------------------------------------------------
+ *
+ * logicalfuncs.c
+ *
+ *    Support functions for using logical decoding and managemnt of
+ *    logical replication slots via SQL.
+ *
+ *
+ * Copyright (c) 2012-2014, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/backend/replication/logicalfuncs.c
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include 
+
+#include "fmgr.h"
+#include "funcapi.h"
+#include "miscadmin.h"
+
+#include "catalog/pg_type.h"
+
+#include "nodes/makefuncs.h"
+
+#include "mb/pg_wchar.h"
+
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/inval.h"
+#include "utils/memutils.h"
+#include "utils/pg_lsn.h"
+#include "utils/resowner.h"
+#include "utils/lsyscache.h"
+
+#include "replication/decode.h"
+#include "replication/logical.h"
+#include "replication/logicalfuncs.h"
+
+#include "storage/fd.h"
+
+/* private date for writing out data */
+typedef struct DecodingOutputState {
+   Tuplestorestate *tupstore;
+   TupleDesc tupdesc;
+   bool binary_output;
+   int64 returned_rows;
+} DecodingOutputState;
+
+/*
+ * Prepare for a output plugin write.
+ */
+static void
+LogicalOutputPrepareWrite(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
+                         bool last_write)
+{
+   resetStringInfo(ctx->out);
+}
+
+/*
+ * Perform output plugin write into tuplestore.
+ */
+static void
+LogicalOutputWrite(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
+                  bool last_write)
+{
+   Datum       values[3];
+   bool        nulls[3];
+   DecodingOutputState *p;
+
+   /* SQL Datums can only be of a limited length... */
+   if (ctx->out->len > MaxAllocSize - VARHDRSZ)
+       elog(ERROR, "too much output for sql interface");
+
+   p = (DecodingOutputState *) ctx->output_writer_private;
+
+   memset(nulls, 0, sizeof(nulls));
+   values[0] = LSNGetDatum(lsn);
+   values[1] = TransactionIdGetDatum(xid);
+
+   /*
+    * Assert ctx->out is in database encoding when we're writing textual
+    * output.
+    */
+   if (!p->binary_output)
+       Assert(pg_verify_mbstr(GetDatabaseEncoding(),
+                              ctx->out->data, ctx->out->len,
+                              false));
+
+   /* ick, but cstring_to_text_with_len works for bytea perfectly fine */
+   values[2] = PointerGetDatum(
+       cstring_to_text_with_len(ctx->out->data, ctx->out->len));
+
+   tuplestore_putvalues(p->tupstore, p->tupdesc, values, nulls);
+   p->returned_rows++;
+}
+
+/*
+ * TODO: This is duplicate code with pg_xlogdump, similar to walsender.c, but
+ * we currently don't have the infrastructure (elog!) to share it.
+ */
+static void
+XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
+{
+   char       *p;
+   XLogRecPtr  recptr;
+   Size        nbytes;
+
+   static int  sendFile = -1;
+   static XLogSegNo sendSegNo = 0;
+   static uint32 sendOff = 0;
+
+   p = buf;
+   recptr = startptr;
+   nbytes = count;
+
+   while (nbytes > 0)
+   {
+       uint32      startoff;
+       int         segbytes;
+       int         readbytes;
+
+       startoff = recptr % XLogSegSize;
+
+       if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo))
+       {
+           char        path[MAXPGPATH];
+
+           /* Switch to another logfile segment */
+           if (sendFile >= 0)
+               close(sendFile);
+
+           XLByteToSeg(recptr, sendSegNo);
+
+           XLogFilePath(path, tli, sendSegNo);
+
+           sendFile = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);
+
+           if (sendFile < 0)
+           {
+               if (errno == ENOENT)
+                   ereport(ERROR,
+                           (errcode_for_file_access(),
+                            errmsg("requested WAL segment %s has already been removed",
+                                   path)));
+               else
+                   ereport(ERROR,
+                           (errcode_for_file_access(),
+                            errmsg("could not open file \"%s\": %m",
+                                   path)));
+           }
+           sendOff = 0;
+       }
+
+       /* Need to seek in the file? */
+       if (sendOff != startoff)
+       {
+           if (lseek(sendFile, (off_t) startoff, SEEK_SET) < 0)
+           {
+               char        path[MAXPGPATH];
+
+               XLogFilePath(path, tli, sendSegNo);
+
+               ereport(ERROR,
+                       (errcode_for_file_access(),
+                 errmsg("could not seek in log segment %s to offset %u: %m",
+                        path, startoff)));
+           }
+           sendOff = startoff;
+       }
+
+       /* How many bytes are within this segment? */
+       if (nbytes > (XLogSegSize - startoff))
+           segbytes = XLogSegSize - startoff;
+       else
+           segbytes = nbytes;
+
+       readbytes = read(sendFile, p, segbytes);
+       if (readbytes <= 0)
+       {
+           char        path[MAXPGPATH];
+
+           XLogFilePath(path, tli, sendSegNo);
+
+           ereport(ERROR,
+                   (errcode_for_file_access(),
+                    errmsg("could not read from log segment %s, offset %u, length %lu: %m",
+                           path, sendOff, (unsigned long) segbytes)));
+       }
+
+       /* Update state for read */
+       recptr += readbytes;
+
+       sendOff += readbytes;
+       nbytes -= readbytes;
+       p += readbytes;
+   }
+}
+
+static void
+check_permissions(void)
+{
+   if (!superuser() && !has_rolreplication(GetUserId()))
+       ereport(ERROR,
+               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                (errmsg("must be superuser or replication role to use replication slots"))));
+}
+
+/*
+ * read_page callback for logical decoding contexts.
+ *
+ * Public because it would likely be very helpful for someone writing another
+ * output method outside walsender, e.g. in a bgworker.
+ *
+ * TODO: The walsender has it's own version of this, but it relies on the
+ * walsender's latch being set whenever WAL is flushed. No such infrastructure
+ * exists for normal backends, so we have to do a check/sleep/repeat style of
+ * loop for now.
+ */
+int
+logical_read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr,
+   int reqLen, XLogRecPtr targetRecPtr, char *cur_page, TimeLineID *pageTLI)
+{
+   XLogRecPtr  flushptr,
+               loc;
+   int         count;
+
+   loc = targetPagePtr + reqLen;
+   while (1)
+   {
+       /*
+        * TODO: we're going to have to do something more intelligent about
+        * timelines on standbys. Use readTimeLineHistory() and
+        * tliOfPointInHistory() to get the proper LSN? For now we'll catch
+        * that case earlier, but the code and TODO is left in here for when
+        * that changes.
+        */
+       if (!RecoveryInProgress())
+       {
+           *pageTLI = ThisTimeLineID;
+           flushptr = GetFlushRecPtr();
+       }
+       else
+           flushptr = GetXLogReplayRecPtr(pageTLI);
+
+       if (loc <= flushptr)
+           break;
+
+       CHECK_FOR_INTERRUPTS();
+       pg_usleep(1000L);
+   }
+
+   /* more than one block available */
+   if (targetPagePtr + XLOG_BLCKSZ <= flushptr)
+       count = XLOG_BLCKSZ;
+   /* not enough data there */
+   else if (targetPagePtr + reqLen > flushptr)
+       return -1;
+   /* part of the page available */
+   else
+       count = flushptr - targetPagePtr;
+
+   XLogRead(cur_page, *pageTLI, targetPagePtr, XLOG_BLCKSZ);
+
+   return count;
+}
+
+/*
+ * Helper function for the various SQL callable logical decoding functions.
+ */
+static Datum
+pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool binary)
+{
+   Name        name = PG_GETARG_NAME(0);
+   XLogRecPtr  upto_lsn;
+   int32       upto_nchanges;
+
+   ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+   MemoryContext per_query_ctx;
+   MemoryContext oldcontext;
+
+   XLogRecPtr  end_of_wal;
+   XLogRecPtr  startptr;
+
+   LogicalDecodingContext *ctx;
+
+   ResourceOwner old_resowner = CurrentResourceOwner;
+   ArrayType  *arr;
+   Size        ndim;
+   List       *options = NIL;
+   DecodingOutputState *p;
+
+   if (PG_ARGISNULL(1))
+       upto_lsn = InvalidXLogRecPtr;
+   else
+       upto_lsn = PG_GETARG_LSN(1);
+
+   if (PG_ARGISNULL(2))
+       upto_nchanges = InvalidXLogRecPtr;
+   else
+       upto_nchanges = PG_GETARG_INT32(2);
+
+   /* check to see if caller supports us returning a tuplestore */
+   if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+       ereport(ERROR,
+               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                errmsg("set-valued function called in context that cannot accept a set")));
+   if (!(rsinfo->allowedModes & SFRM_Materialize))
+       ereport(ERROR,
+               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                errmsg("materialize mode required, but it is not allowed in this context")));
+
+   /* state to write output to */
+   p = palloc0(sizeof(DecodingOutputState));
+
+   p->binary_output = binary;
+
+   /* Build a tuple descriptor for our result type */
+   if (get_call_result_type(fcinfo, NULL, &p->tupdesc) != TYPEFUNC_COMPOSITE)
+       elog(ERROR, "return type must be a row type");
+
+   check_permissions();
+
+   CheckLogicalDecodingRequirements();
+
+   arr = PG_GETARG_ARRAYTYPE_P(3);
+   ndim = ARR_NDIM(arr);
+
+   per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+   oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+   if (ndim > 1)
+   {
+       ereport(ERROR,
+               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                errmsg("array must be one-dimensional")));
+   }
+   else if (array_contains_nulls(arr))
+   {
+       ereport(ERROR,
+               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                errmsg("array must not contain nulls")));
+   }
+   else if (ndim == 1)
+   {
+       int         nelems;
+       Datum      *datum_opts;
+       int         i;
+
+       Assert(ARR_ELEMTYPE(arr) == TEXTOID);
+
+       deconstruct_array(arr, TEXTOID, -1, false, 'i',
+                         &datum_opts, NULL, &nelems);
+
+       if (nelems % 2 != 0)
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("array must have even number of elements")));
+
+       for (i = 0; i < nelems; i += 2)
+       {
+           char       *name = TextDatumGetCString(datum_opts[i]);
+           char       *opt = TextDatumGetCString(datum_opts[i + 1]);
+
+           options = lappend(options, makeDefElem(name, (Node *) makeString(opt)));
+       }
+   }
+
+   p->tupstore = tuplestore_begin_heap(true, false, work_mem);
+   rsinfo->returnMode = SFRM_Materialize;
+   rsinfo->setResult = p->tupstore;
+   rsinfo->setDesc = p->tupdesc;
+
+   /* compute the current end-of-wal */
+   if (!RecoveryInProgress())
+       end_of_wal = GetFlushRecPtr();
+   else
+       end_of_wal = GetXLogReplayRecPtr(NULL);
+
+   CheckLogicalDecodingRequirements();
+   ReplicationSlotAcquire(NameStr(*name));
+
+   PG_TRY();
+   {
+       ctx = CreateDecodingContext(InvalidXLogRecPtr,
+                                   options,
+                                   logical_read_local_xlog_page,
+                                   LogicalOutputPrepareWrite,
+                                   LogicalOutputWrite);
+
+       MemoryContextSwitchTo(oldcontext);
+
+       /*
+        * Check whether the output pluggin writes textual output if that's
+        * what we need.
+        */
+       if (!binary &&
+           ctx->options.output_type != OUTPUT_PLUGIN_TEXTUAL_OUTPUT)
+           ereport(ERROR,
+                   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("output plugin cannot produce text output")));
+
+       ctx->output_writer_private = p;
+
+       startptr = MyReplicationSlot->data.restart_lsn;
+
+       CurrentResourceOwner = ResourceOwnerCreate(CurrentResourceOwner, "logical decoding");
+
+       /* invalidate non-timetravel entries */
+       InvalidateSystemCaches();
+
+       while ((startptr != InvalidXLogRecPtr && startptr < end_of_wal) ||
+              (ctx->reader->EndRecPtr && ctx->reader->EndRecPtr < end_of_wal))
+       {
+           XLogRecord *record;
+           char       *errm = NULL;
+
+           record = XLogReadRecord(ctx->reader, startptr, &errm);
+           if (errm)
+               elog(ERROR, "%s", errm);
+
+           startptr = InvalidXLogRecPtr;
+
+           /*
+            * The {begin_txn,change,commit_txn}_wrapper callbacks above will
+            * store the description into our tuplestore.
+            */
+           if (record != NULL)
+               LogicalDecodingProcessRecord(ctx, record);
+
+           /* check limits */
+           if (upto_lsn != InvalidXLogRecPtr &&
+               upto_lsn <= ctx->reader->EndRecPtr)
+               break;
+           if (upto_nchanges != 0 &&
+               upto_nchanges <= p->returned_rows)
+               break;
+       }
+   }
+   PG_CATCH();
+   {
+       /* clear all timetravel entries */
+       InvalidateSystemCaches();
+
+       PG_RE_THROW();
+   }
+   PG_END_TRY();
+
+   tuplestore_donestoring(tupstore);
+
+   CurrentResourceOwner = old_resowner;
+
+   /*
+    * Next time, start where we left off. (Hunting things, the family
+    * business..)
+    */
+   if (ctx->reader->EndRecPtr != InvalidXLogRecPtr && confirm)
+       LogicalConfirmReceivedLocation(ctx->reader->EndRecPtr);
+
+   /* free context, call shutdown callback */
+   FreeDecodingContext(ctx);
+
+   ReplicationSlotRelease();
+   InvalidateSystemCaches();
+
+   return (Datum) 0;
+}
+
+/*
+ * SQL function returning the changestream as text, consuming the data.
+ */
+Datum
+pg_logical_slot_get_changes(PG_FUNCTION_ARGS)
+{
+   Datum ret = pg_logical_slot_get_changes_guts(fcinfo, true, false);
+   return ret;
+}
+
+/*
+ * SQL function returning the changestream as text, only peeking ahead.
+ */
+Datum
+pg_logical_slot_peek_changes(PG_FUNCTION_ARGS)
+{
+   Datum ret = pg_logical_slot_get_changes_guts(fcinfo, false, false);
+   return ret;
+}
+
+/*
+ * SQL function returning the changestream in binary, consuming the data.
+ */
+Datum
+pg_logical_slot_get_binary_changes(PG_FUNCTION_ARGS)
+{
+   Datum ret = pg_logical_slot_get_changes_guts(fcinfo, true, true);
+   return ret;
+}
+
+/*
+ * SQL function returning the changestream in binary, only peeking ahead.
+ */
+Datum
+pg_logical_slot_peek_binary_changes(PG_FUNCTION_ARGS)
+{
+   Datum ret = pg_logical_slot_get_changes_guts(fcinfo, false, true);
+   return ret;
+}
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
new file mode 100644 (file)
index 0000000..e718233
--- /dev/null
@@ -0,0 +1,3059 @@
+/*-------------------------------------------------------------------------
+ *
+ * reorderbuffer.c
+ *   PostgreSQL logical replay/reorder buffer management
+ *
+ *
+ * Copyright (c) 2012-2014, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ *   src/backend/replication/reorderbuffer.c
+ *
+ * NOTES
+ *   This module gets handed individual pieces of transactions in the order
+ *   they are written to the WAL and is responsible to reassemble them into
+ *   toplevel transaction sized pieces. When a transaction is completely
+ *   reassembled - signalled by reading the transaction commit record - it
+ *   will then call the output plugin (c.f. ReorderBufferCommit()) with the
+ *   individual changes. The output plugins rely on snapshots built by
+ *   snapbuild.c which hands them to us.
+ *
+ *   Transactions and subtransactions/savepoints in postgres are not
+ *   immediately linked to each other from outside the performing
+ *   backend. Only at commit/abort (or special xact_assignment records) they
+ *   are linked together. Which means that we will have to splice together a
+ *   toplevel transaction from its subtransactions. To do that efficiently we
+ *   build a binary heap indexed by the smallest current lsn of the individual
+ *   subtransactions' changestreams. As the individual streams are inherently
+ *   ordered by LSN - since that is where we build them from - the transaction
+ *   can easily be reassembled by always using the subtransaction with the
+ *   smallest current LSN from the heap.
+ *
+ *   In order to cope with large transactions - which can be several times as
+ *   big as the available memory - this module supports spooling the contents
+ *   of a large transactions to disk. When the transaction is replayed the
+ *   contents of individual (sub-)transactions will be read from disk in
+ *   chunks.
+ *
+ *   This module also has to deal with reassembling toast records from the
+ *   individual chunks stored in WAL. When a new (or initial) version of a
+ *   tuple is stored in WAL it will always be preceded by the toast chunks
+ *   emitted for the columns stored out of line. Within a single toplevel
+ *   transaction there will be no other data carrying records between a row's
+ *   toast chunks and the row data itself. See ReorderBufferToast* for
+ *   details.
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include 
+#include 
+
+#include "miscadmin.h"
+
+#include "access/rewriteheap.h"
+#include "access/transam.h"
+#include "access/tuptoaster.h"
+#include "access/xact.h"
+
+#include "catalog/catalog.h"
+
+#include "common/relpath.h"
+
+#include "lib/binaryheap.h"
+
+#include "replication/logical.h"
+#include "replication/reorderbuffer.h"
+#include "replication/slot.h"
+#include "replication/snapbuild.h" /* just for SnapBuildSnapDecRefcount */
+
+#include "storage/bufmgr.h"
+#include "storage/fd.h"
+#include "storage/sinval.h"
+
+#include "utils/builtins.h"
+#include "utils/combocid.h"
+#include "utils/memdebug.h"
+#include "utils/memutils.h"
+#include "utils/relcache.h"
+#include "utils/relfilenodemap.h"
+#include "utils/tqual.h"
+
+/*
+ * For efficiency and simplicity reasons we want to keep Snapshots, CommandIds
+ * and ComboCids in the same list with the user visible INSERT/UPDATE/DELETE
+ * changes. We don't want to leak those internal values to external users
+ * though (they would just use switch()...default:) because that would make it
+ * harder to add to new user visible values.
+ *
+ * This needs to be synchronized with ReorderBufferChangeType! Adjust the
+ * StaticAssertExpr's in ReorderBufferAllocate if you add anything!
+ */
+typedef enum
+{
+   REORDER_BUFFER_CHANGE_INTERNAL_INSERT,
+   REORDER_BUFFER_CHANGE_INTERNAL_UPDATE,
+   REORDER_BUFFER_CHANGE_INTERNAL_DELETE,
+   REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT,
+   REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID,
+   REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID
+} ReorderBufferChangeTypeInternal;
+
+/* entry for a hash table we use to map from xid to our transaction state */
+typedef struct ReorderBufferTXNByIdEnt
+{
+   TransactionId xid;
+   ReorderBufferTXN *txn;
+} ReorderBufferTXNByIdEnt;
+
+/* data structures for (relfilenode, ctid) => (cmin, cmax) mapping */
+typedef struct ReorderBufferTupleCidKey
+{
+   RelFileNode relnode;
+   ItemPointerData tid;
+} ReorderBufferTupleCidKey;
+
+typedef struct ReorderBufferTupleCidEnt
+{
+   ReorderBufferTupleCidKey key;
+   CommandId   cmin;
+   CommandId   cmax;
+   CommandId   combocid;       /* just for debugging */
+} ReorderBufferTupleCidEnt;
+
+/* k-way in-order change iteration support structures */
+typedef struct ReorderBufferIterTXNEntry
+{
+   XLogRecPtr  lsn;
+   ReorderBufferChange *change;
+   ReorderBufferTXN *txn;
+   int         fd;
+   XLogSegNo   segno;
+} ReorderBufferIterTXNEntry;
+
+typedef struct ReorderBufferIterTXNState
+{
+   binaryheap *heap;
+   Size        nr_txns;
+   dlist_head  old_change;
+   ReorderBufferIterTXNEntry entries[FLEXIBLE_ARRAY_MEMBER];
+} ReorderBufferIterTXNState;
+
+/* toast datastructures */
+typedef struct ReorderBufferToastEnt
+{
+   Oid         chunk_id;       /* toast_table.chunk_id */
+   int32       last_chunk_seq; /* toast_table.chunk_seq of the last chunk we
+                                * have seen */
+   Size        num_chunks;     /* number of chunks we've already seen */
+   Size        size;           /* combined size of chunks seen */
+   dlist_head  chunks;         /* linked list of chunks */
+   struct varlena *reconstructed;      /* reconstructed varlena now pointed
+                                        * to in main tup */
+} ReorderBufferToastEnt;
+
+/* Disk serialization support datastructures */
+typedef struct ReorderBufferDiskChange
+{
+   Size        size;
+   ReorderBufferChange change;
+   /* data follows */
+} ReorderBufferDiskChange;
+
+/*
+ * Maximum number of changes kept in memory, per transaction. After that,
+ * changes are spooled to disk.
+ *
+ * The current value should be sufficient to decode the entire transaction
+ * without hitting disk in OLTP workloads, while starting to spool to disk in
+ * other workloads reasonably fast.
+ *
+ * At some point in the future it probaly makes sense to have a more elaborate
+ * resource management here, but it's not entirely clear what that would look
+ * like.
+ */
+static const Size max_changes_in_memory = 4096;
+
+/*
+ * We use a very simple form of a slab allocator for frequently allocated
+ * objects, simply keeping a fixed number in a linked list when unused,
+ * instead pfree()ing them. Without that in many workloads aset.c becomes a
+ * major bottleneck, especially when spilling to disk while decoding batch
+ * workloads.
+ */
+static const Size max_cached_changes = 4096 * 2;
+static const Size max_cached_tuplebufs = 4096 * 2;     /* ~8MB */
+static const Size max_cached_transactions = 512;
+
+
+/* ---------------------------------------
+ * primary reorderbuffer support routines
+ * ---------------------------------------
+ */
+static ReorderBufferTXN *ReorderBufferGetTXN(ReorderBuffer *rb);
+static void ReorderBufferReturnTXN(ReorderBuffer *rb, ReorderBufferTXN *txn);
+static ReorderBufferTXN *ReorderBufferTXNByXid(ReorderBuffer *rb,
+                     TransactionId xid, bool create, bool *is_new,
+                     XLogRecPtr lsn, bool create_as_top);
+
+static void AssertTXNLsnOrder(ReorderBuffer *rb);
+
+/* ---------------------------------------
+ * support functions for lsn-order iterating over the ->changes of a
+ * transaction and its subtransactions
+ *
+ * used for iteration over the k-way heap merge of a transaction and its
+ * subtransactions
+ * ---------------------------------------
+ */
+static ReorderBufferIterTXNState *ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn);
+static ReorderBufferChange *
+           ReorderBufferIterTXNNext(ReorderBuffer *rb, ReorderBufferIterTXNState *state);
+static void ReorderBufferIterTXNFinish(ReorderBuffer *rb,
+                          ReorderBufferIterTXNState *state);
+static void ReorderBufferExecuteInvalidations(ReorderBuffer *rb, ReorderBufferTXN *txn);
+
+/*
+ * ---------------------------------------
+ * Disk serialization support functions
+ * ---------------------------------------
+ */
+static void ReorderBufferCheckSerializeTXN(ReorderBuffer *rb, ReorderBufferTXN *txn);
+static void ReorderBufferSerializeTXN(ReorderBuffer *rb, ReorderBufferTXN *txn);
+static void ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
+                            int fd, ReorderBufferChange *change);
+static Size ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
+                           int *fd, XLogSegNo *segno);
+static void ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
+                          char *change);
+static void ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn);
+
+static void ReorderBufferFreeSnap(ReorderBuffer *rb, Snapshot snap);
+static Snapshot ReorderBufferCopySnap(ReorderBuffer *rb, Snapshot orig_snap,
+                     ReorderBufferTXN *txn, CommandId cid);
+
+/* ---------------------------------------
+ * toast reassembly support
+ * ---------------------------------------
+ */
+static void ReorderBufferToastInitHash(ReorderBuffer *rb, ReorderBufferTXN *txn);
+static void ReorderBufferToastReset(ReorderBuffer *rb, ReorderBufferTXN *txn);
+static void ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
+                         Relation relation, ReorderBufferChange *change);
+static void ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
+                             Relation relation, ReorderBufferChange *change);
+
+
+/*
+ * Allocate a new ReorderBuffer
+ */
+ReorderBuffer *
+ReorderBufferAllocate(void)
+{
+   ReorderBuffer *buffer;
+   HASHCTL     hash_ctl;
+   MemoryContext new_ctx;
+
+   StaticAssertExpr((int) REORDER_BUFFER_CHANGE_INTERNAL_INSERT == (int) REORDER_BUFFER_CHANGE_INSERT, "out of sync enums");
+   StaticAssertExpr((int) REORDER_BUFFER_CHANGE_INTERNAL_UPDATE == (int) REORDER_BUFFER_CHANGE_UPDATE, "out of sync enums");
+   StaticAssertExpr((int) REORDER_BUFFER_CHANGE_INTERNAL_DELETE == (int) REORDER_BUFFER_CHANGE_DELETE, "out of sync enums");
+
+   /* allocate memory in own context, to have better accountability */
+   new_ctx = AllocSetContextCreate(CurrentMemoryContext,
+                                   "ReorderBuffer",
+                                   ALLOCSET_DEFAULT_MINSIZE,
+                                   ALLOCSET_DEFAULT_INITSIZE,
+                                   ALLOCSET_DEFAULT_MAXSIZE);
+
+   buffer =
+       (ReorderBuffer *) MemoryContextAlloc(new_ctx, sizeof(ReorderBuffer));
+
+   memset(&hash_ctl, 0, sizeof(hash_ctl));
+
+   buffer->context = new_ctx;
+
+   hash_ctl.keysize = sizeof(TransactionId);
+   hash_ctl.entrysize = sizeof(ReorderBufferTXNByIdEnt);
+   hash_ctl.hash = tag_hash;
+   hash_ctl.hcxt = buffer->context;
+
+   buffer->by_txn = hash_create("ReorderBufferByXid", 1000, &hash_ctl,
+                                HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
+
+   buffer->by_txn_last_xid = InvalidTransactionId;
+   buffer->by_txn_last_txn = NULL;
+
+   buffer->nr_cached_transactions = 0;
+   buffer->nr_cached_changes = 0;
+   buffer->nr_cached_tuplebufs = 0;
+
+   buffer->outbuf = NULL;
+   buffer->outbufsize = 0;
+
+   buffer->current_restart_decoding_lsn = InvalidXLogRecPtr;
+
+   dlist_init(&buffer->toplevel_by_lsn);
+   dlist_init(&buffer->cached_transactions);
+   dlist_init(&buffer->cached_changes);
+   slist_init(&buffer->cached_tuplebufs);
+
+   return buffer;
+}
+
+/*
+ * Free a ReorderBuffer
+ */
+void
+ReorderBufferFree(ReorderBuffer *rb)
+{
+   MemoryContext context = rb->context;
+
+   /*
+    * We free separately allocated data by entirely scrapping reorderbuffer's
+    * memory context.
+    */
+   MemoryContextDelete(context);
+}
+
+/*
+ * Get a unused, possibly preallocated, ReorderBufferTXN.
+ */
+static ReorderBufferTXN *
+ReorderBufferGetTXN(ReorderBuffer *rb)
+{
+   ReorderBufferTXN *txn;
+
+   /* check the slab cache */
+   if (rb->nr_cached_transactions > 0)
+   {
+       rb->nr_cached_transactions--;
+       txn = (ReorderBufferTXN *)
+           dlist_container(ReorderBufferTXN, node,
+                           dlist_pop_head_node(&rb->cached_transactions));
+   }
+   else
+   {
+       txn = (ReorderBufferTXN *)
+           MemoryContextAlloc(rb->context, sizeof(ReorderBufferTXN));
+   }
+
+   memset(txn, 0, sizeof(ReorderBufferTXN));
+
+   dlist_init(&txn->changes);
+   dlist_init(&txn->tuplecids);
+   dlist_init(&txn->subtxns);
+
+   return txn;
+}
+
+/*
+ * Free a ReorderBufferTXN.
+ *
+ * Deallocation might be delayed for efficiency purposes, for details check
+ * the comments above max_cached_changes's definition.
+ */
+void
+ReorderBufferReturnTXN(ReorderBuffer *rb, ReorderBufferTXN *txn)
+{
+   /* clean the lookup cache if we were cached (quite likely) */
+   if (rb->by_txn_last_xid == txn->xid)
+   {
+       rb->by_txn_last_xid = InvalidTransactionId;
+       rb->by_txn_last_txn = NULL;
+   }
+
+   /* free data that's contained */
+
+   if (txn->tuplecid_hash != NULL)
+   {
+       hash_destroy(txn->tuplecid_hash);
+       txn->tuplecid_hash = NULL;
+   }
+
+   if (txn->invalidations)
+   {
+       pfree(txn->invalidations);
+       txn->invalidations = NULL;
+   }
+
+   /* check whether to put into the slab cache */
+   if (rb->nr_cached_transactions < max_cached_transactions)
+   {
+       rb->nr_cached_transactions++;
+       dlist_push_head(&rb->cached_transactions, &txn->node);
+       VALGRIND_MAKE_MEM_UNDEFINED(txn, sizeof(ReorderBufferTXN));
+       VALGRIND_MAKE_MEM_DEFINED(&txn->node, sizeof(txn->node));
+   }
+   else
+   {
+       pfree(txn);
+   }
+}
+
+/*
+ * Get a unused, possibly preallocated, ReorderBufferChange.
+ */
+ReorderBufferChange *
+ReorderBufferGetChange(ReorderBuffer *rb)
+{
+   ReorderBufferChange *change;
+
+   /* check the slab cache */
+   if (rb->nr_cached_changes)
+   {
+       rb->nr_cached_changes--;
+       change = (ReorderBufferChange *)
+           dlist_container(ReorderBufferChange, node,
+                           dlist_pop_head_node(&rb->cached_changes));
+   }
+   else
+   {
+       change = (ReorderBufferChange *)
+           MemoryContextAlloc(rb->context, sizeof(ReorderBufferChange));
+   }
+
+   memset(change, 0, sizeof(ReorderBufferChange));
+   return change;
+}
+
+/*
+ * Free an ReorderBufferChange.
+ *
+ * Deallocation might be delayed for efficiency purposes, for details check
+ * the comments above max_cached_changes's definition.
+ */
+void
+ReorderBufferReturnChange(ReorderBuffer *rb, ReorderBufferChange *change)
+{
+   /* free contained data */
+   switch ((ReorderBufferChangeTypeInternal) change->action_internal)
+   {
+       case REORDER_BUFFER_CHANGE_INTERNAL_INSERT:
+       case REORDER_BUFFER_CHANGE_INTERNAL_UPDATE:
+       case REORDER_BUFFER_CHANGE_INTERNAL_DELETE:
+           if (change->tp.newtuple)
+           {
+               ReorderBufferReturnTupleBuf(rb, change->tp.newtuple);
+               change->tp.newtuple = NULL;
+           }
+
+           if (change->tp.oldtuple)
+           {
+               ReorderBufferReturnTupleBuf(rb, change->tp.oldtuple);
+               change->tp.oldtuple = NULL;
+           }
+           break;
+       case REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:
+           if (change->snapshot)
+           {
+               ReorderBufferFreeSnap(rb, change->snapshot);
+               change->snapshot = NULL;
+           }
+           break;
+       case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
+           break;
+       case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID:
+           break;
+   }
+
+   /* check whether to put into the slab cache */
+   if (rb->nr_cached_changes < max_cached_changes)
+   {
+       rb->nr_cached_changes++;
+       dlist_push_head(&rb->cached_changes, &change->node);
+       VALGRIND_MAKE_MEM_UNDEFINED(change, sizeof(ReorderBufferChange));
+       VALGRIND_MAKE_MEM_DEFINED(&change->node, sizeof(change->node));
+   }
+   else
+   {
+       pfree(change);
+   }
+}
+
+
+/*
+ * Get a unused, possibly preallocated, ReorderBufferTupleBuf
+ */
+ReorderBufferTupleBuf *
+ReorderBufferGetTupleBuf(ReorderBuffer *rb)
+{
+   ReorderBufferTupleBuf *tuple;
+
+   /* check the slab cache */
+   if (rb->nr_cached_tuplebufs)
+   {
+       rb->nr_cached_tuplebufs--;
+       tuple = slist_container(ReorderBufferTupleBuf, node,
+                               slist_pop_head_node(&rb->cached_tuplebufs));
+#ifdef USE_ASSERT_CHECKING
+       memset(tuple, 0xdeadbeef, sizeof(ReorderBufferTupleBuf));
+#endif
+   }
+   else
+   {
+       tuple = (ReorderBufferTupleBuf *)
+           MemoryContextAlloc(rb->context, sizeof(ReorderBufferTupleBuf));
+   }
+
+   return tuple;
+}
+
+/*
+ * Free an ReorderBufferTupleBuf.
+ *
+ * Deallocation might be delayed for efficiency purposes, for details check
+ * the comments above max_cached_changes's definition.
+ */
+void
+ReorderBufferReturnTupleBuf(ReorderBuffer *rb, ReorderBufferTupleBuf *tuple)
+{
+   /* check whether to put into the slab cache */
+   if (rb->nr_cached_tuplebufs < max_cached_tuplebufs)
+   {
+       rb->nr_cached_tuplebufs++;
+       slist_push_head(&rb->cached_tuplebufs, &tuple->node);
+       VALGRIND_MAKE_MEM_UNDEFINED(tuple, sizeof(ReorderBufferTupleBuf));
+       VALGRIND_MAKE_MEM_DEFINED(&tuple->node, sizeof(tuple->node));
+   }
+   else
+   {
+       pfree(tuple);
+   }
+}
+
+/*
+ * Return the ReorderBufferTXN from the given buffer, specified by Xid.
+ * If create is true, and a transaction doesn't already exist, create it
+ * (with the given LSN, and as top transaction if that's specified);
+ * when this happens, is_new is set to true.
+ */
+static ReorderBufferTXN *
+ReorderBufferTXNByXid(ReorderBuffer *rb, TransactionId xid, bool create,
+                     bool *is_new, XLogRecPtr lsn, bool create_as_top)
+{
+   ReorderBufferTXN *txn;
+   ReorderBufferTXNByIdEnt *ent;
+   bool        found;
+
+   Assert(TransactionIdIsValid(xid));
+   Assert(!create || lsn != InvalidXLogRecPtr);
+
+   /*
+    * Check the one-entry lookup cache first
+    */
+   if (TransactionIdIsValid(rb->by_txn_last_xid) &&
+       rb->by_txn_last_xid == xid)
+   {
+       txn = rb->by_txn_last_txn;
+
+       if (txn != NULL)
+       {
+           /* found it, and it's valid */
+           if (is_new)
+               *is_new = false;
+           return txn;
+       }
+
+       /*
+        * cached as non-existant, and asked not to create? Then nothing else
+        * to do.
+        */
+       if (!create)
+           return NULL;
+       /* otherwise fall through to create it */
+   }
+
+   /*
+    * If the cache wasn't hit or it yielded an "does-not-exist" and we want
+    * to create an entry.
+    */
+
+   /* search the lookup table */
+   ent = (ReorderBufferTXNByIdEnt *)
+       hash_search(rb->by_txn,
+                   (void *) &xid,
+                   create ? HASH_ENTER : HASH_FIND,
+                   &found);
+   if (found)
+       txn = ent->txn;
+   else if (create)
+   {
+       /* initialize the new entry, if creation was requested */
+       Assert(ent != NULL);
+
+       ent->txn = ReorderBufferGetTXN(rb);
+       ent->txn->xid = xid;
+       txn = ent->txn;
+       txn->first_lsn = lsn;
+       txn->restart_decoding_lsn = rb->current_restart_decoding_lsn;
+
+       if (create_as_top)
+       {
+           dlist_push_tail(&rb->toplevel_by_lsn, &txn->node);
+           AssertTXNLsnOrder(rb);
+       }
+   }
+   else
+       txn = NULL;             /* not found and not asked to create */
+
+   /* update cache */
+   rb->by_txn_last_xid = xid;
+   rb->by_txn_last_txn = txn;
+
+   if (is_new)
+       *is_new = !found;
+
+   Assert(!create || !!txn);
+   return txn;
+}
+
+/*
+ * Queue a change into a transaction so it can be replayed upon commit.
+ */
+void
+ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
+                      ReorderBufferChange *change)
+{
+   ReorderBufferTXN *txn;
+
+   txn = ReorderBufferTXNByXid(rb, xid, true, NULL, lsn, true);
+
+   change->lsn = lsn;
+   Assert(InvalidXLogRecPtr != lsn);
+   dlist_push_tail(&txn->changes, &change->node);
+   txn->nentries++;
+   txn->nentries_mem++;
+
+   ReorderBufferCheckSerializeTXN(rb, txn);
+}
+
+static void
+AssertTXNLsnOrder(ReorderBuffer *rb)
+{
+#ifdef USE_ASSERT_CHECKING
+   dlist_iter  iter;
+   XLogRecPtr  prev_first_lsn = InvalidXLogRecPtr;
+
+  &nb