
# Copyright (c) 2021-2024, PostgreSQL Global Development Group

# This tests that more complex datatypes are replicated correctly
# by logical replication
use strict;
use warnings FATAL => 'all';
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;

# Initialize publisher node
my $node_publisher = PostgreSQL::Test::Cluster->new('publisher');
$node_publisher->init(allows_streaming => 'logical');
$node_publisher->start;

# Create subscriber node
my $node_subscriber = PostgreSQL::Test::Cluster->new('subscriber');
$node_subscriber->init;
$node_subscriber->start;

# Create some preexisting content on publisher
my $ddl = qq(
	CREATE EXTENSION hstore WITH SCHEMA public;
	CREATE TABLE public.tst_one_array (
		a INTEGER PRIMARY KEY,
		b INTEGER[]
		);
	CREATE TABLE public.tst_arrays (
		a INTEGER[] PRIMARY KEY,
		b TEXT[],
		c FLOAT[],
		d INTERVAL[]
		);

	CREATE TYPE public.tst_enum_t AS ENUM ('a', 'b', 'c', 'd', 'e');
	CREATE TABLE public.tst_one_enum (
		a INTEGER PRIMARY KEY,
		b public.tst_enum_t
		);
	CREATE TABLE public.tst_enums (
		a public.tst_enum_t PRIMARY KEY,
		b public.tst_enum_t[]
		);

	CREATE TYPE public.tst_comp_basic_t AS (a FLOAT, b TEXT, c INTEGER);
	CREATE TYPE public.tst_comp_enum_t AS (a FLOAT, b public.tst_enum_t, c INTEGER);
	CREATE TYPE public.tst_comp_enum_array_t AS (a FLOAT, b public.tst_enum_t[], c INTEGER);
	CREATE TABLE public.tst_one_comp (
		a INTEGER PRIMARY KEY,
		b public.tst_comp_basic_t
		);
	CREATE TABLE public.tst_comps (
		a public.tst_comp_basic_t PRIMARY KEY,
		b public.tst_comp_basic_t[]
		);
	CREATE TABLE public.tst_comp_enum (
		a INTEGER PRIMARY KEY,
		b public.tst_comp_enum_t
		);
	CREATE TABLE public.tst_comp_enum_array (
		a public.tst_comp_enum_t PRIMARY KEY,
		b public.tst_comp_enum_t[]
		);
	CREATE TABLE public.tst_comp_one_enum_array (
		a INTEGER PRIMARY KEY,
		b public.tst_comp_enum_array_t
		);
	CREATE TABLE public.tst_comp_enum_what (
		a public.tst_comp_enum_array_t PRIMARY KEY,
		b public.tst_comp_enum_array_t[]
		);

	CREATE TYPE public.tst_comp_mix_t AS (
		a public.tst_comp_basic_t,
		b public.tst_comp_basic_t[],
		c public.tst_enum_t,
		d public.tst_enum_t[]
		);
	CREATE TABLE public.tst_comp_mix_array (
		a public.tst_comp_mix_t PRIMARY KEY,
		b public.tst_comp_mix_t[]
		);
	CREATE TABLE public.tst_range (
		a INTEGER PRIMARY KEY,
		b int4range
	);
	CREATE TABLE public.tst_range_array (
		a INTEGER PRIMARY KEY,
		b TSTZRANGE,
		c int8range[]
	);
	CREATE TABLE public.tst_hstore (
		a INTEGER PRIMARY KEY,
		b public.hstore
	);

	SET check_function_bodies=off;
	CREATE FUNCTION public.monot_incr(int) RETURNS bool LANGUAGE sql
		AS ' select \$1 > max(a) from public.tst_dom_constr; ';
	CREATE DOMAIN monot_int AS int CHECK (monot_incr(VALUE));
	CREATE TABLE public.tst_dom_constr (a monot_int););

# Setup structure on both nodes
$node_publisher->safe_psql('postgres', $ddl);
$node_subscriber->safe_psql('postgres', $ddl);

# Setup logical replication
my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres';
$node_publisher->safe_psql('postgres',
	"CREATE PUBLICATION tap_pub FOR ALL TABLES");

$node_subscriber->safe_psql('postgres',
	"CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr' PUBLICATION tap_pub WITH (slot_name = tap_sub_slot)"
);

# Wait for initial sync to finish as well
$node_subscriber->wait_for_subscription_sync($node_publisher, 'tap_sub');

# Insert initial test data
$node_publisher->safe_psql(
	'postgres', qq(
	-- test_tbl_one_array_col
	INSERT INTO tst_one_array (a, b) VALUES
		(1, '{1, 2, 3}'),
		(2, '{2, 3, 1}'),
		(3, '{3, 2, 1}'),
		(4, '{4, 3, 2}'),
		(5, '{5, NULL, 3}');

	-- test_tbl_arrays
	INSERT INTO tst_arrays (a, b, c, d) VALUES
		('{1, 2, 3}', '{"a", "b", "c"}', '{1.1, 2.2, 3.3}', '{"1 day", "2 days", "3 days"}'),
		('{2, 3, 1}', '{"b", "c", "a"}', '{2.2, 3.3, 1.1}', '{"2 minutes", "3 minutes", "1 minute"}'),
		('{3, 1, 2}', '{"c", "a", "b"}', '{3.3, 1.1, 2.2}', '{"3 years", "1 year", "2 years"}'),
		('{4, 1, 2}', '{"d", "a", "b"}', '{4.4, 1.1, 2.2}', '{"4 years", "1 year", "2 years"}'),
		('{5, NULL, NULL}', '{"e", NULL, "b"}', '{5.5, 1.1, NULL}', '{"5 years", NULL, NULL}');

	-- test_tbl_single_enum
	INSERT INTO tst_one_enum (a, b) VALUES
		(1, 'a'),
		(2, 'b'),
		(3, 'c'),
		(4, 'd'),
		(5, NULL);

	-- test_tbl_enums
	INSERT INTO tst_enums (a, b) VALUES
		('a', '{b, c}'),
		('b', '{c, a}'),
		('c', '{b, a}'),
		('d', '{c, b}'),
		('e', '{d, NULL}');

	-- test_tbl_single_composites
	INSERT INTO tst_one_comp (a, b) VALUES
		(1, ROW(1.0, 'a', 1)),
		(2, ROW(2.0, 'b', 2)),
		(3, ROW(3.0, 'c', 3)),
		(4, ROW(4.0, 'd', 4)),
		(5, ROW(NULL, NULL, 5));

	-- test_tbl_composites
	INSERT INTO tst_comps (a, b) VALUES
		(ROW(1.0, 'a', 1), ARRAY[ROW(1, 'a', 1)::tst_comp_basic_t]),
		(ROW(2.0, 'b', 2), ARRAY[ROW(2, 'b', 2)::tst_comp_basic_t]),
		(ROW(3.0, 'c', 3), ARRAY[ROW(3, 'c', 3)::tst_comp_basic_t]),
		(ROW(4.0, 'd', 4), ARRAY[ROW(4, 'd', 3)::tst_comp_basic_t]),
		(ROW(5.0, 'e', NULL), ARRAY[NULL, ROW(5, NULL, 5)::tst_comp_basic_t]);

	-- test_tbl_composite_with_enums
	INSERT INTO tst_comp_enum (a, b) VALUES
		(1, ROW(1.0, 'a', 1)),
		(2, ROW(2.0, 'b', 2)),
		(3, ROW(3.0, 'c', 3)),
		(4, ROW(4.0, 'd', 4)),
		(5, ROW(NULL, 'e', NULL));

	-- test_tbl_composite_with_enums_array
	INSERT INTO tst_comp_enum_array (a, b) VALUES
		(ROW(1.0, 'a', 1), ARRAY[ROW(1, 'a', 1)::tst_comp_enum_t]),
		(ROW(2.0, 'b', 2), ARRAY[ROW(2, 'b', 2)::tst_comp_enum_t]),
		(ROW(3.0, 'c', 3), ARRAY[ROW(3, 'c', 3)::tst_comp_enum_t]),
		(ROW(4.0, 'd', 3), ARRAY[ROW(3, 'd', 3)::tst_comp_enum_t]),
		(ROW(5.0, 'e', 3), ARRAY[ROW(3, 'e', 3)::tst_comp_enum_t, NULL]);

	-- test_tbl_composite_with_single_enums_array_in_composite
	INSERT INTO tst_comp_one_enum_array (a, b) VALUES
		(1, ROW(1.0, '{a, b, c}', 1)),
		(2, ROW(2.0, '{a, b, c}', 2)),
		(3, ROW(3.0, '{a, b, c}', 3)),
		(4, ROW(4.0, '{c, b, d}', 4)),
		(5, ROW(5.0, '{NULL, e, NULL}', 5));

	-- test_tbl_composite_with_enums_array_in_composite
	INSERT INTO tst_comp_enum_what (a, b) VALUES
		(ROW(1.0, '{a, b, c}', 1), ARRAY[ROW(1, '{a, b, c}', 1)::tst_comp_enum_array_t]),
		(ROW(2.0, '{b, c, a}', 2), ARRAY[ROW(2, '{b, c, a}', 1)::tst_comp_enum_array_t]),
		(ROW(3.0, '{c, a, b}', 1), ARRAY[ROW(3, '{c, a, b}', 1)::tst_comp_enum_array_t]),
		(ROW(4.0, '{c, b, d}', 4), ARRAY[ROW(4, '{c, b, d}', 4)::tst_comp_enum_array_t]),
		(ROW(5.0, '{c, NULL, b}', NULL), ARRAY[ROW(5, '{c, e, b}', 1)::tst_comp_enum_array_t]);

	-- test_tbl_mixed_composites
	INSERT INTO tst_comp_mix_array (a, b) VALUES
		(ROW(
			ROW(1,'a',1),
			ARRAY[ROW(1,'a',1)::tst_comp_basic_t, ROW(2,'b',2)::tst_comp_basic_t],
			'a',
			'{a,b,NULL,c}'),
		ARRAY[
			ROW(
				ROW(1,'a',1),
				ARRAY[
					ROW(1,'a',1)::tst_comp_basic_t,
					ROW(2,'b',2)::tst_comp_basic_t,
					NULL
					],
				'a',
				'{a,b,c}'
				)::tst_comp_mix_t
			]
		);

	-- test_tbl_range
	INSERT INTO tst_range (a, b) VALUES
		(1, '[1, 10]'),
		(2, '[2, 20]'),
		(3, '[3, 30]'),
		(4, '[4, 40]'),
		(5, '[5, 50]');

	-- test_tbl_range_array
	INSERT INTO tst_range_array (a, b, c) VALUES
		(1, tstzrange('Mon Aug 04 00:00:00 2014 CEST'::timestamptz, 'infinity'), '{"[1,2]", "[10,20]"}'),
		(2, tstzrange('Sat Aug 02 00:00:00 2014 CEST'::timestamptz, 'Mon Aug 04 00:00:00 2014 CEST'::timestamptz), '{"[2,3]", "[20,30]"}'),
		(3, tstzrange('Fri Aug 01 00:00:00 2014 CEST'::timestamptz, 'Mon Aug 04 00:00:00 2014 CEST'::timestamptz), '{"[3,4]"}'),
		(4, tstzrange('Thu Jul 31 00:00:00 2014 CEST'::timestamptz, 'Mon Aug 04 00:00:00 2014 CEST'::timestamptz), '{"[4,5]", NULL, "[40,50]"}'),
		(5, NULL, NULL);

	-- tst_hstore
	INSERT INTO tst_hstore (a, b) VALUES
		(1, '"a"=>"1"'),
		(2, '"zzz"=>"foo"'),
		(3, '"123"=>"321"'),
		(4, '"yellow horse"=>"moaned"');

	-- tst_dom_constr
	INSERT INTO tst_dom_constr VALUES (10);
));

$node_publisher->wait_for_catchup('tap_sub');

# Check the data on subscriber
my $result = $node_subscriber->safe_psql(
	'postgres', qq(
	SET timezone = '+2';
	SELECT a, b FROM tst_one_array ORDER BY a;
	SELECT a, b, c, d FROM tst_arrays ORDER BY a;
	SELECT a, b FROM tst_one_enum ORDER BY a;
	SELECT a, b FROM tst_enums ORDER BY a;
	SELECT a, b FROM tst_one_comp ORDER BY a;
	SELECT a, b FROM tst_comps ORDER BY a;
	SELECT a, b FROM tst_comp_enum ORDER BY a;
	SELECT a, b FROM tst_comp_enum_array ORDER BY a;
	SELECT a, b FROM tst_comp_one_enum_array ORDER BY a;
	SELECT a, b FROM tst_comp_enum_what ORDER BY a;
	SELECT a, b FROM tst_comp_mix_array ORDER BY a;
	SELECT a, b FROM tst_range ORDER BY a;
	SELECT a, b, c FROM tst_range_array ORDER BY a;
	SELECT a, b FROM tst_hstore ORDER BY a;
));

is( $result, '1|{1,2,3}
2|{2,3,1}
3|{3,2,1}
4|{4,3,2}
5|{5,NULL,3}
{1,2,3}|{a,b,c}|{1.1,2.2,3.3}|{"1 day","2 days","3 days"}
{2,3,1}|{b,c,a}|{2.2,3.3,1.1}|{00:02:00,00:03:00,00:01:00}
{3,1,2}|{c,a,b}|{3.3,1.1,2.2}|{"3 years","1 year","2 years"}
{4,1,2}|{d,a,b}|{4.4,1.1,2.2}|{"4 years","1 year","2 years"}
{5,NULL,NULL}|{e,NULL,b}|{5.5,1.1,NULL}|{"5 years",NULL,NULL}
1|a
2|b
3|c
4|d
5|
a|{b,c}
b|{c,a}
c|{b,a}
d|{c,b}
e|{d,NULL}
1|(1,a,1)
2|(2,b,2)
3|(3,c,3)
4|(4,d,4)
5|(,,5)
(1,a,1)|{"(1,a,1)"}
(2,b,2)|{"(2,b,2)"}
(3,c,3)|{"(3,c,3)"}
(4,d,4)|{"(4,d,3)"}
(5,e,)|{NULL,"(5,,5)"}
1|(1,a,1)
2|(2,b,2)
3|(3,c,3)
4|(4,d,4)
5|(,e,)
(1,a,1)|{"(1,a,1)"}
(2,b,2)|{"(2,b,2)"}
(3,c,3)|{"(3,c,3)"}
(4,d,3)|{"(3,d,3)"}
(5,e,3)|{"(3,e,3)",NULL}
1|(1,"{a,b,c}",1)
2|(2,"{a,b,c}",2)
3|(3,"{a,b,c}",3)
4|(4,"{c,b,d}",4)
5|(5,"{NULL,e,NULL}",5)
(1,"{a,b,c}",1)|{"(1,\"{a,b,c}\",1)"}
(2,"{b,c,a}",2)|{"(2,\"{b,c,a}\",1)"}
(3,"{c,a,b}",1)|{"(3,\"{c,a,b}\",1)"}
(4,"{c,b,d}",4)|{"(4,\"{c,b,d}\",4)"}
(5,"{c,NULL,b}",)|{"(5,\"{c,e,b}\",1)"}
("(1,a,1)","{""(1,a,1)"",""(2,b,2)""}",a,"{a,b,NULL,c}")|{"(\"(1,a,1)\",\"{\"\"(1,a,1)\"\",\"\"(2,b,2)\"\",NULL}\",a,\"{a,b,c}\")"}
1|[1,11)
2|[2,21)
3|[3,31)
4|[4,41)
5|[5,51)
1|["2014-08-04 00:00:00+02",infinity)|{"[1,3)","[10,21)"}
2|["2014-08-02 00:00:00+02","2014-08-04 00:00:00+02")|{"[2,4)","[20,31)"}
3|["2014-08-01 00:00:00+02","2014-08-04 00:00:00+02")|{"[3,5)"}
4|["2014-07-31 00:00:00+02","2014-08-04 00:00:00+02")|{"[4,6)",NULL,"[40,51)"}
5||
1|"a"=>"1"
2|"zzz"=>"foo"
3|"123"=>"321"
4|"yellow horse"=>"moaned"',
	'check replicated inserts on subscriber');

# Run batch of updates
$node_publisher->safe_psql(
	'postgres', qq(
	UPDATE tst_one_array SET b = '{4, 5, 6}' WHERE a = 1;
	UPDATE tst_one_array SET b = '{4, 5, 6, 1}' WHERE a > 3;
	UPDATE tst_arrays SET b = '{"1a", "2b", "3c"}', c = '{1.0, 2.0, 3.0}', d = '{"1 day 1 second", "2 days 2 seconds", "3 days 3 second"}' WHERE a = '{1, 2, 3}';
	UPDATE tst_arrays SET b = '{"c", "d", "e"}', c = '{3.0, 4.0, 5.0}', d = '{"3 day 1 second", "4 days 2 seconds", "5 days 3 second"}' WHERE a[1] > 3;
	UPDATE tst_one_enum SET b = 'c' WHERE a = 1;
	UPDATE tst_one_enum SET b = NULL WHERE a > 3;
	UPDATE tst_enums SET b = '{e, NULL}' WHERE a = 'a';
	UPDATE tst_enums SET b = '{e, d}' WHERE a > 'c';
	UPDATE tst_one_comp SET b = ROW(1.0, 'A', 1) WHERE a = 1;
	UPDATE tst_one_comp SET b = ROW(NULL, 'x', -1) WHERE a > 3;
	UPDATE tst_comps SET b = ARRAY[ROW(9, 'x', -1)::tst_comp_basic_t] WHERE (a).a = 1.0;
	UPDATE tst_comps SET b = ARRAY[NULL, ROW(9, 'x', NULL)::tst_comp_basic_t] WHERE (a).a > 3.9;
	UPDATE tst_comp_enum SET b = ROW(1.0, NULL, NULL) WHERE a = 1;
	UPDATE tst_comp_enum SET b = ROW(4.0, 'd', 44) WHERE a > 3;
	UPDATE tst_comp_enum_array SET b = ARRAY[NULL, ROW(3, 'd', 3)::tst_comp_enum_t] WHERE a = ROW(1.0, 'a', 1)::tst_comp_enum_t;
	UPDATE tst_comp_enum_array SET b = ARRAY[ROW(1, 'a', 1)::tst_comp_enum_t, ROW(2, 'b', 2)::tst_comp_enum_t] WHERE (a).a > 3;
	UPDATE tst_comp_one_enum_array SET b = ROW(1.0, '{a, e, c}', NULL) WHERE a = 1;
	UPDATE tst_comp_one_enum_array SET b = ROW(4.0, '{c, b, d}', 4) WHERE a > 3;
	UPDATE tst_comp_enum_what SET b = ARRAY[NULL, ROW(1, '{a, b, c}', 1)::tst_comp_enum_array_t, ROW(NULL, '{a, e, c}', 2)::tst_comp_enum_array_t] WHERE (a).a = 1;
	UPDATE tst_comp_enum_what SET b = ARRAY[ROW(5, '{a, b, c}', 5)::tst_comp_enum_array_t] WHERE (a).a > 3;
	UPDATE tst_comp_mix_array SET b[2] = NULL WHERE ((a).a).a = 1;
	UPDATE tst_range SET b = '[100, 1000]' WHERE a = 1;
	UPDATE tst_range SET b = '(1, 90)' WHERE a > 3;
	UPDATE tst_range_array SET c = '{"[100, 1000]"}' WHERE a = 1;
	UPDATE tst_range_array SET b = tstzrange('Mon Aug 04 00:00:00 2014 CEST'::timestamptz, 'infinity'), c = '{NULL, "[11,9999999]"}' WHERE a > 3;
	UPDATE tst_hstore SET b = '"updated"=>"value"' WHERE a < 3;
	UPDATE tst_hstore SET b = '"also"=>"updated"' WHERE a = 3;
));

$node_publisher->wait_for_catchup('tap_sub');

# Check the data on subscriber
$result = $node_subscriber->safe_psql(
	'postgres', qq(
	SET timezone = '+2';
	SELECT a, b FROM tst_one_array ORDER BY a;
	SELECT a, b, c, d FROM tst_arrays ORDER BY a;
	SELECT a, b FROM tst_one_enum ORDER BY a;
	SELECT a, b FROM tst_enums ORDER BY a;
	SELECT a, b FROM tst_one_comp ORDER BY a;
	SELECT a, b FROM tst_comps ORDER BY a;
	SELECT a, b FROM tst_comp_enum ORDER BY a;
	SELECT a, b FROM tst_comp_enum_array ORDER BY a;
	SELECT a, b FROM tst_comp_one_enum_array ORDER BY a;
	SELECT a, b FROM tst_comp_enum_what ORDER BY a;
	SELECT a, b FROM tst_comp_mix_array ORDER BY a;
	SELECT a, b FROM tst_range ORDER BY a;
	SELECT a, b, c FROM tst_range_array ORDER BY a;
	SELECT a, b FROM tst_hstore ORDER BY a;
));

is( $result, '1|{4,5,6}
2|{2,3,1}
3|{3,2,1}
4|{4,5,6,1}
5|{4,5,6,1}
{1,2,3}|{1a,2b,3c}|{1,2,3}|{"1 day 00:00:01","2 days 00:00:02","3 days 00:00:03"}
{2,3,1}|{b,c,a}|{2.2,3.3,1.1}|{00:02:00,00:03:00,00:01:00}
{3,1,2}|{c,a,b}|{3.3,1.1,2.2}|{"3 years","1 year","2 years"}
{4,1,2}|{c,d,e}|{3,4,5}|{"3 days 00:00:01","4 days 00:00:02","5 days 00:00:03"}
{5,NULL,NULL}|{c,d,e}|{3,4,5}|{"3 days 00:00:01","4 days 00:00:02","5 days 00:00:03"}
1|c
2|b
3|c
4|
5|
a|{e,NULL}
b|{c,a}
c|{b,a}
d|{e,d}
e|{e,d}
1|(1,A,1)
2|(2,b,2)
3|(3,c,3)
4|(,x,-1)
5|(,x,-1)
(1,a,1)|{"(9,x,-1)"}
(2,b,2)|{"(2,b,2)"}
(3,c,3)|{"(3,c,3)"}
(4,d,4)|{NULL,"(9,x,)"}
(5,e,)|{NULL,"(9,x,)"}
1|(1,,)
2|(2,b,2)
3|(3,c,3)
4|(4,d,44)
5|(4,d,44)
(1,a,1)|{NULL,"(3,d,3)"}
(2,b,2)|{"(2,b,2)"}
(3,c,3)|{"(3,c,3)"}
(4,d,3)|{"(1,a,1)","(2,b,2)"}
(5,e,3)|{"(1,a,1)","(2,b,2)"}
1|(1,"{a,e,c}",)
2|(2,"{a,b,c}",2)
3|(3,"{a,b,c}",3)
4|(4,"{c,b,d}",4)
5|(4,"{c,b,d}",4)
(1,"{a,b,c}",1)|{NULL,"(1,\"{a,b,c}\",1)","(,\"{a,e,c}\",2)"}
(2,"{b,c,a}",2)|{"(2,\"{b,c,a}\",1)"}
(3,"{c,a,b}",1)|{"(3,\"{c,a,b}\",1)"}
(4,"{c,b,d}",4)|{"(5,\"{a,b,c}\",5)"}
(5,"{c,NULL,b}",)|{"(5,\"{a,b,c}\",5)"}
("(1,a,1)","{""(1,a,1)"",""(2,b,2)""}",a,"{a,b,NULL,c}")|{"(\"(1,a,1)\",\"{\"\"(1,a,1)\"\",\"\"(2,b,2)\"\",NULL}\",a,\"{a,b,c}\")",NULL}
1|[100,1001)
2|[2,21)
3|[3,31)
4|[2,90)
5|[2,90)
1|["2014-08-04 00:00:00+02",infinity)|{"[100,1001)"}
2|["2014-08-02 00:00:00+02","2014-08-04 00:00:00+02")|{"[2,4)","[20,31)"}
3|["2014-08-01 00:00:00+02","2014-08-04 00:00:00+02")|{"[3,5)"}
4|["2014-08-04 00:00:00+02",infinity)|{NULL,"[11,10000000)"}
5|["2014-08-04 00:00:00+02",infinity)|{NULL,"[11,10000000)"}
1|"updated"=>"value"
2|"updated"=>"value"
3|"also"=>"updated"
4|"yellow horse"=>"moaned"',
	'check replicated updates on subscriber');

# Run batch of deletes
$node_publisher->safe_psql(
	'postgres', qq(
	DELETE FROM tst_one_array WHERE a = 1;
	DELETE FROM tst_one_array WHERE b = '{2, 3, 1}';
	DELETE FROM tst_arrays WHERE a = '{1, 2, 3}';
	DELETE FROM tst_arrays WHERE a[1] = 2;
	DELETE FROM tst_one_enum WHERE a = 1;
	DELETE FROM tst_one_enum WHERE b = 'b';
	DELETE FROM tst_enums WHERE a = 'a';
	DELETE FROM tst_enums WHERE b[1] = 'b';
	DELETE FROM tst_one_comp WHERE a = 1;
	DELETE FROM tst_one_comp WHERE (b).a = 2.0;
	DELETE FROM tst_comps WHERE (a).b = 'a';
	DELETE FROM tst_comps WHERE ROW(3, 'c', 3)::tst_comp_basic_t = ANY(b);
	DELETE FROM tst_comp_enum WHERE a = 1;
	DELETE FROM tst_comp_enum WHERE (b).a = 2.0;
	DELETE FROM tst_comp_enum_array WHERE a = ROW(1.0, 'a', 1)::tst_comp_enum_t;
	DELETE FROM tst_comp_enum_array WHERE ROW(3, 'c', 3)::tst_comp_enum_t = ANY(b);
	DELETE FROM tst_comp_one_enum_array WHERE a = 1;
	DELETE FROM tst_comp_one_enum_array WHERE 'a' = ANY((b).b);
	DELETE FROM tst_comp_enum_what WHERE (a).a = 1;
	DELETE FROM tst_comp_enum_what WHERE (b[1]).b = '{c, a, b}';
	DELETE FROM tst_comp_mix_array WHERE ((a).a).a = 1;
	DELETE FROM tst_range WHERE a = 1;
	DELETE FROM tst_range WHERE '[10,20]' && b;
	DELETE FROM tst_range_array WHERE a = 1;
	DELETE FROM tst_range_array WHERE tstzrange('Mon Aug 04 00:00:00 2014 CEST'::timestamptz, 'Mon Aug 05 00:00:00 2014 CEST'::timestamptz) && b;
	DELETE FROM tst_hstore WHERE a = 1;
));

$node_publisher->wait_for_catchup('tap_sub');

# Check the data on subscriber
$result = $node_subscriber->safe_psql(
	'postgres', qq(
	SET timezone = '+2';
	SELECT a, b FROM tst_one_array ORDER BY a;
	SELECT a, b, c, d FROM tst_arrays ORDER BY a;
	SELECT a, b FROM tst_one_enum ORDER BY a;
	SELECT a, b FROM tst_enums ORDER BY a;
	SELECT a, b FROM tst_one_comp ORDER BY a;
	SELECT a, b FROM tst_comps ORDER BY a;
	SELECT a, b FROM tst_comp_enum ORDER BY a;
	SELECT a, b FROM tst_comp_enum_array ORDER BY a;
	SELECT a, b FROM tst_comp_one_enum_array ORDER BY a;
	SELECT a, b FROM tst_comp_enum_what ORDER BY a;
	SELECT a, b FROM tst_comp_mix_array ORDER BY a;
	SELECT a, b FROM tst_range ORDER BY a;
	SELECT a, b, c FROM tst_range_array ORDER BY a;
	SELECT a, b FROM tst_hstore ORDER BY a;
));

is( $result, '3|{3,2,1}
4|{4,5,6,1}
5|{4,5,6,1}
{3,1,2}|{c,a,b}|{3.3,1.1,2.2}|{"3 years","1 year","2 years"}
{4,1,2}|{c,d,e}|{3,4,5}|{"3 days 00:00:01","4 days 00:00:02","5 days 00:00:03"}
{5,NULL,NULL}|{c,d,e}|{3,4,5}|{"3 days 00:00:01","4 days 00:00:02","5 days 00:00:03"}
3|c
4|
5|
b|{c,a}
d|{e,d}
e|{e,d}
3|(3,c,3)
4|(,x,-1)
5|(,x,-1)
(2,b,2)|{"(2,b,2)"}
(4,d,4)|{NULL,"(9,x,)"}
(5,e,)|{NULL,"(9,x,)"}
3|(3,c,3)
4|(4,d,44)
5|(4,d,44)
(2,b,2)|{"(2,b,2)"}
(4,d,3)|{"(1,a,1)","(2,b,2)"}
(5,e,3)|{"(1,a,1)","(2,b,2)"}
4|(4,"{c,b,d}",4)
5|(4,"{c,b,d}",4)
(2,"{b,c,a}",2)|{"(2,\"{b,c,a}\",1)"}
(4,"{c,b,d}",4)|{"(5,\"{a,b,c}\",5)"}
(5,"{c,NULL,b}",)|{"(5,\"{a,b,c}\",5)"}
2|["2014-08-02 00:00:00+02","2014-08-04 00:00:00+02")|{"[2,4)","[20,31)"}
3|["2014-08-01 00:00:00+02","2014-08-04 00:00:00+02")|{"[3,5)"}
2|"updated"=>"value"
3|"also"=>"updated"
4|"yellow horse"=>"moaned"',
	'check replicated deletes on subscriber');

# Test a domain with a constraint backed by a SQL-language function,
# which needs an active snapshot in order to operate.
$node_publisher->safe_psql('postgres',
	"INSERT INTO tst_dom_constr VALUES (11)");

$node_publisher->wait_for_catchup('tap_sub');

$result =
  $node_subscriber->safe_psql('postgres',
	"SELECT sum(a) FROM tst_dom_constr");
is($result, '21', 'sql-function constraint on domain');

$node_subscriber->stop('fast');
$node_publisher->stop('fast');

done_testing();
