raven/base/pglogical/alternative_regression_outputs.patch
2024-02-21 13:47:54 +06:00

750 lines
22 KiB
Diff

Index: pglogical/expected/row_filter_2.out
===================================================================
--- /dev/null
+++ pglogical/expected/row_filter_2.out
@@ -0,0 +1,744 @@
+-- row based filtering
+SELECT * FROM pglogical_regress_variables()
+\gset
+\c :provider_dsn
+SELECT pglogical.replicate_ddl_command($$
+ CREATE TABLE public.basic_dml (
+ id serial primary key,
+ other integer,
+ data text,
+ "SomeThing" interval,
+ insert_xid bigint DEFAULT txid_current()
+ );
+$$);
+ replicate_ddl_command
+-----------------------
+ t
+(1 row)
+
+-- used to check if initial copy does row filtering
+\COPY basic_dml(id, other, data, "SomeThing") FROM STDIN WITH CSV
+-- create some functions:
+CREATE FUNCTION funcn_add(integer, integer) RETURNS integer
+ AS 'select $1 + $2;'
+ LANGUAGE SQL
+ IMMUTABLE
+ RETURNS NULL ON NULL INPUT;
+create function funcn_nochange(text) returns text
+ as 'select $1 limit 1' language sql stable;
+create or replace function funcn_get_curr_decade() returns integer as
+$$ (SELECT EXTRACT(DECADE FROM NOW()):: integer); $$
+language sql volatile;
+-- we allow volatile functions, it's user's responsibility to not do writes
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false, row_filter := 'current_user = data');
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+-- fail -- subselect
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false, row_filter := '(SELECT count(*) FROM pg_class) > 1');
+ERROR: cannot use subquery in check constraint
+-- fail -- SELECT
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false, row_filter := 'SELECT true');
+ERROR: syntax error at or near "SELECT"
+CONTEXT: invalid row_filter expression "SELECT true"
+-- fail -- nonexisting column
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false, row_filter := 'foobar');
+ERROR: column "foobar" does not exist
+-- fail -- not coercable to bool
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false, row_filter := 'data');
+ERROR: argument of row_filter must be type boolean, not type text
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false, row_filter := $rf$id between 2 AND 4$rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false, row_filter := NULL);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false, row_filter := $rf$id > funcn_add(1,2) $rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false, row_filter := $rf$data = funcn_nochange('baz') $rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false, row_filter := $rf$ other > funcn_get_curr_decade() $rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+-- use this filter for rest of the test
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', true, row_filter := $rf$id > 1 AND data IS DISTINCT FROM 'baz' AND data IS DISTINCT FROM 'bbb'$rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+SELECT nspname, relname, set_name FROM pglogical.tables WHERE relname = 'basic_dml';
+ nspname | relname | set_name
+---------+-----------+----------
+ public | basic_dml | default
+(1 row)
+
+-- fail, the membership in repset depends on data column
+\set VERBOSITY terse
+ALTER TABLE basic_dml DROP COLUMN data;
+ERROR: cannot drop table basic_dml column data because other objects depend on it
+\set VERBOSITY default
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+-- wait for the initial data to copy
+BEGIN;
+SET LOCAL statement_timeout = '60s';
+SELECT pglogical.wait_for_subscription_sync_complete('test_subscription');
+ wait_for_subscription_sync_complete
+-------------------------------------
+
+(1 row)
+
+COMMIT;
+SELECT id, other, data, "SomeThing" FROM basic_dml ORDER BY id;
+ id | other | data | SomeThing
+------+-------+------+-----------
+ 5000 | 1 | aaa | @ 1 hour
+ 5002 | 3 | ccc | @ 3 mins
+ 5003 | 4 | ddd | @ 4 days
+(3 rows)
+
+ALTER TABLE public.basic_dml ADD COLUMN subonly integer;
+ALTER TABLE public.basic_dml ADD COLUMN subonly_def integer DEFAULT 99;
+ALTER TABLE public.basic_dml ADD COLUMN subonly_def_ts timestamptz DEFAULT current_timestamp;
+\c :provider_dsn
+TRUNCATE basic_dml;
+-- check basic insert replication
+INSERT INTO basic_dml(other, data, "SomeThing")
+VALUES (5, 'foo', '1 minute'::interval),
+ (4, 'bar', '12 weeks'::interval),
+ (3, 'baz', '2 years 1 hour'::interval),
+ (2, 'qux', '8 months 2 days'::interval),
+ (1, NULL, NULL);
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT id, other, data, "SomeThing" FROM basic_dml ORDER BY id;
+ id | other | data | SomeThing
+----+-------+------+-----------------
+ 2 | 4 | bar | @ 84 days
+ 4 | 2 | qux | @ 8 mons 2 days
+ 5 | 1 | |
+(3 rows)
+
+-- update one row
+\c :provider_dsn
+UPDATE basic_dml SET other = '4', data = NULL, "SomeThing" = '3 days'::interval WHERE id = 4;
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT id, other, data, "SomeThing" FROM basic_dml ORDER BY id;
+ id | other | data | SomeThing
+----+-------+------+-----------
+ 2 | 4 | bar | @ 84 days
+ 4 | 4 | | @ 3 days
+ 5 | 1 | |
+(3 rows)
+
+-- update multiple rows
+\c :provider_dsn
+UPDATE basic_dml SET other = id, data = data || id::text;
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT id, other, data, "SomeThing" FROM basic_dml ORDER BY id;
+ id | other | data | SomeThing
+----+-------+------+-----------
+ 2 | 2 | bar2 | @ 84 days
+ 4 | 4 | | @ 3 days
+ 5 | 5 | |
+(3 rows)
+
+\c :provider_dsn
+UPDATE basic_dml SET other = id, "SomeThing" = "SomeThing" - '10 seconds'::interval WHERE id < 3;
+UPDATE basic_dml SET other = id, "SomeThing" = "SomeThing" + '10 seconds'::interval WHERE id > 3;
+DELETE FROM basic_dml WHERE id = 3;
+INSERT INTO basic_dml VALUES (3, 99, 'bazbaz', '2 years 1 hour'::interval);
+INSERT INTO basic_dml VALUES (7, 100, 'bazbaz', '2 years 1 hour'::interval);
+UPDATE basic_dml SET data = 'baz' WHERE id in (3,7);
+-- This update would be filtered at subscriber
+SELECT id, other, data, "SomeThing" from basic_dml ORDER BY id;
+ id | other | data | SomeThing
+----+-------+------+--------------------
+ 1 | 1 | foo1 | @ 50 secs
+ 2 | 2 | bar2 | @ 84 days -10 secs
+ 3 | 99 | baz | @ 2 years 1 hour
+ 4 | 4 | | @ 3 days 10 secs
+ 5 | 5 | |
+ 7 | 100 | baz | @ 2 years 1 hour
+(6 rows)
+
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT id, other, data, "SomeThing", subonly, subonly_def FROM basic_dml ORDER BY id;
+ id | other | data | SomeThing | subonly | subonly_def
+----+-------+--------+--------------------+---------+-------------
+ 2 | 2 | bar2 | @ 84 days -10 secs | | 99
+ 3 | 99 | bazbaz | @ 2 years 1 hour | | 99
+ 4 | 4 | | @ 3 days 10 secs | | 99
+ 5 | 5 | | | | 99
+ 7 | 100 | bazbaz | @ 2 years 1 hour | | 99
+(5 rows)
+
+\c :provider_dsn
+UPDATE basic_dml SET data = 'bar' WHERE id = 3;
+-- This update would again start to be received at subscriber
+DELETE FROM basic_dml WHERE data = 'baz';
+-- Delete reaches the subscriber for a filtered row
+INSERT INTO basic_dml VALUES (6, 100, 'baz', '2 years 1 hour'::interval);
+-- insert would be filtered
+SELECT id, other, data, "SomeThing" from basic_dml ORDER BY id;
+ id | other | data | SomeThing
+----+-------+------+--------------------
+ 1 | 1 | foo1 | @ 50 secs
+ 2 | 2 | bar2 | @ 84 days -10 secs
+ 3 | 99 | bar | @ 2 years 1 hour
+ 4 | 4 | | @ 3 days 10 secs
+ 5 | 5 | |
+ 6 | 100 | baz | @ 2 years 1 hour
+(6 rows)
+
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT id, other, data, "SomeThing", subonly, subonly_def FROM basic_dml ORDER BY id;
+ id | other | data | SomeThing | subonly | subonly_def
+----+-------+------+--------------------+---------+-------------
+ 2 | 2 | bar2 | @ 84 days -10 secs | | 99
+ 3 | 99 | bar | @ 2 years 1 hour | | 99
+ 4 | 4 | | @ 3 days 10 secs | | 99
+ 5 | 5 | | | | 99
+(4 rows)
+
+\c :provider_dsn
+UPDATE basic_dml SET data = 'bar' WHERE id = 6;
+UPDATE basic_dml SET data = 'abcd' WHERE id = 6;
+-- These updates would continue to be missed on subscriber
+-- as it does not have the primary key
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT id, other, data, "SomeThing" FROM basic_dml ORDER BY id;
+ id | other | data | SomeThing
+----+-------+------+--------------------
+ 2 | 2 | bar2 | @ 84 days -10 secs
+ 3 | 99 | bar | @ 2 years 1 hour
+ 4 | 4 | | @ 3 days 10 secs
+ 5 | 5 | |
+(4 rows)
+
+-- transaction timestamp should be updated for each row (see #148)
+SELECT count(DISTINCT subonly_def_ts) = count(DISTINCT insert_xid) FROM basic_dml;
+ ?column?
+----------
+ t
+(1 row)
+
+-- delete multiple rows
+\c :provider_dsn
+DELETE FROM basic_dml WHERE id < 4;
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT id, other, data, "SomeThing" FROM basic_dml ORDER BY id;
+ id | other | data | SomeThing
+----+-------+------+------------------
+ 4 | 4 | | @ 3 days 10 secs
+ 5 | 5 | |
+(2 rows)
+
+-- truncate
+\c :provider_dsn
+TRUNCATE basic_dml;
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT id, other, data, "SomeThing" FROM basic_dml ORDER BY id;
+ id | other | data | SomeThing
+----+-------+------+-----------
+(0 rows)
+
+-- copy
+\c :provider_dsn
+\COPY basic_dml(id, other, data, "SomeThing") FROM STDIN WITH CSV
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT id, other, data, "SomeThing" FROM basic_dml ORDER BY id;
+ id | other | data | SomeThing
+------+-------+------+-----------
+ 9000 | 1 | aaa | @ 1 hour
+ 9002 | 3 | ccc | @ 3 mins
+ 9003 | 4 | ddd | @ 4 days
+(3 rows)
+
+\c :provider_dsn
+SELECT pglogical.replicate_ddl_command($$
+ CREATE TABLE public.test_jsonb (
+ json_type text primary key,
+ test_json jsonb
+ );
+$$);
+ replicate_ddl_command
+-----------------------
+ t
+(1 row)
+
+INSERT INTO test_jsonb VALUES
+('scalar','"a scalar"'),
+('array','["zero", "one","two",null,"four","five", [1,2,3],{"f1":9}]'),
+('object','{"field1":"val1","field2":"val2","field3":null, "field4": 4, "field5": [1,2,3], "field6": {"f1":9}}');
+SELECT * FROM pglogical.replication_set_add_table('default', 'test_jsonb', true, row_filter := $rf$(test_json ->> 'field2') IS DISTINCT FROM 'val2' $rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+DO $$
+BEGIN
+ FOR i IN 1..100 LOOP
+ IF NOT EXISTS (SELECT 1 FROM pglogical.local_sync_status WHERE sync_status != 'r') THEN
+ EXIT;
+ END IF;
+ PERFORM pg_sleep(0.1);
+ END LOOP;
+END;$$;
+SELECT * FROM test_jsonb ORDER BY json_type;
+ json_type | test_json
+-----------+--------------------------------------------------------------------
+ array | ["zero", "one", "two", null, "four", "five", [1, 2, 3], {"f1": 9}]
+ scalar | "a scalar"
+(2 rows)
+
+\c :provider_dsn
+-- Filter may refer to not-replicated columns
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false, columns := ARRAY['id', 'data'], row_filter := $rf$other = 2$rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+INSERT INTO basic_dml(other, data, "SomeThing") VALUES (2, 'itstwo', '1 second'::interval);
+SELECT other, data, "SomeThing" FROM basic_dml WHERE data = 'itstwo';
+ other | data | SomeThing
+-------+--------+-----------
+ 2 | itstwo | @ 1 sec
+(1 row)
+
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+-- 'other' will be NULL as it wasn't in the repset
+-- even though we filtered on it. So will SomeThing.
+SELECT other, data, "SomeThing" FROM basic_dml WHERE data = 'itstwo';
+ other | data | SomeThing
+-------+--------+-----------
+ | itstwo |
+(1 row)
+
+\c :provider_dsn
+---------------------------------------------------
+-- Enhanced function tests covering basic plpgsql
+---------------------------------------------------
+CREATE FUNCTION func_plpgsql_simple(arg integer)
+RETURNS integer
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ RETURN arg;
+END;
+$$;
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false,
+ row_filter := $rf$ func_plpgsql_simple(other) = 100 $rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+-- Should FAIL due to dependency
+--
+-- FIXME: Succeeds incorrectly (RM#5880) leading to
+-- cache lookup failed for function" errors in logs if allowed to commit
+--
+BEGIN;
+DROP FUNCTION func_plpgsql_simple(integer);
+ROLLBACK;
+INSERT INTO basic_dml (other) VALUES (100), (101);
+SELECT other FROM basic_dml WHERE other IN (100,101);
+ other
+-------
+ 100
+ 101
+(2 rows)
+
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT other FROM basic_dml WHERE other IN (100,101);
+ other
+-------
+ 100
+(1 row)
+
+\c :provider_dsn
+CREATE FUNCTION func_plpgsql_logic(arg integer)
+RETURNS integer
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ IF arg = 200 THEN
+ RETURN arg;
+ ELSE
+ RETURN 0;
+ END IF;
+END;
+$$;
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false,
+ row_filter := $rf$ func_plpgsql_logic(other) = other $rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+INSERT INTO basic_dml (other) VALUES (200), (201);
+SELECT other FROM basic_dml WHERE other IN (200,201);
+ other
+-------
+ 200
+ 201
+(2 rows)
+
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT other FROM basic_dml WHERE other IN (200,201);
+ other
+-------
+ 200
+(1 row)
+
+\c :provider_dsn
+CREATE FUNCTION func_plpgsql_security_definer(arg integer)
+RETURNS integer
+LANGUAGE plpgsql
+SECURITY DEFINER
+AS $$
+BEGIN
+ RAISE NOTICE 'c_u: %, s_u: %', current_user, session_user;
+ RETURN arg;
+END;
+$$;
+CREATE ROLE temp_owner;
+ALTER FUNCTION func_plpgsql_security_definer(integer) OWNER TO temp_owner;
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false,
+ row_filter := $rf$ func_plpgsql_security_definer(other) = 300 $rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+INSERT INTO basic_dml (other) VALUES (300), (301);
+SELECT other FROM basic_dml WHERE other IN (300,301);
+ other
+-------
+ 300
+ 301
+(2 rows)
+
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT other FROM basic_dml WHERE other IN (300,301);
+ other
+-------
+ 300
+(1 row)
+
+\c :provider_dsn
+CREATE FUNCTION func_plpgsql_exception(arg integer)
+RETURNS integer
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ BEGIN
+ SELECT arg/0;
+ EXCEPTION
+ WHEN division_by_zero THEN
+ RETURN arg;
+ END;
+ RAISE EXCEPTION 'should be unreachable';
+END;
+$$;
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false,
+ row_filter := $rf$ func_plpgsql_exception(other) = 400 $rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+INSERT INTO basic_dml (other) VALUES (400), (401);
+SELECT other FROM basic_dml WHERE other IN (400,401);
+ other
+-------
+ 400
+ 401
+(2 rows)
+
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT other FROM basic_dml WHERE other IN (400,401);
+ other
+-------
+ 400
+(1 row)
+
+\c :provider_dsn
+-- Should not be able to use a SETOF or TABLE func directly
+-- but we can do it via a wrapper:
+CREATE FUNCTION func_plpgsql_srf_retq(arg integer)
+RETURNS TABLE (result integer, dummy boolean)
+LANGUAGE plpgsql
+SECURITY DEFINER
+AS $$
+BEGIN
+ RETURN QUERY SELECT arg * x, true FROM generate_series(1,2) x;
+ RETURN;
+END;
+$$;
+-- fails with SRF context error
+BEGIN;
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false,
+ row_filter := $rf$ (func_plpgsql_srf_retq(other)).result = 500 $rf$);
+ERROR: argument of row_filter must not return a set
+ROLLBACK;
+CREATE FUNCTION func_plpgsql_call_set(arg integer)
+RETURNS boolean
+LANGUAGE plpgsql
+AS $$
+BEGIN
+ RETURN (SELECT true FROM func_plpgsql_srf_retq(arg) WHERE result = arg * 2);
+END;
+$$;
+SELECT * FROM pglogical.replication_set_remove_table('default', 'basic_dml');
+ replication_set_remove_table
+------------------------------
+ t
+(1 row)
+
+SELECT * FROM pglogical.replication_set_add_table('default', 'basic_dml', false,
+ row_filter := $rf$ func_plpgsql_call_set(other) $rf$);
+ replication_set_add_table
+---------------------------
+ t
+(1 row)
+
+INSERT INTO basic_dml (other) VALUES (500), (501);
+SELECT other FROM basic_dml WHERE other IN (500,501);
+ other
+-------
+ 500
+ 501
+(2 rows)
+
+SELECT pglogical.wait_slot_confirm_lsn(NULL, NULL);
+ wait_slot_confirm_lsn
+-----------------------
+
+(1 row)
+
+\c :subscriber_dsn
+SELECT other FROM basic_dml WHERE other IN (500,501);
+ other
+-------
+ 500
+ 501
+(2 rows)
+
+\c :provider_dsn
+DROP FUNCTION func_plpgsql_simple(integer);
+DROP FUNCTION func_plpgsql_logic(integer);
+DROP FUNCTION func_plpgsql_security_definer(integer);
+DROP FUNCTION func_plpgsql_exception(integer);
+DROP FUNCTION func_plpgsql_srf_retq(integer);
+DROP FUNCTION func_plpgsql_call_set(integer);
+DROP ROLE temp_owner;
+---------------------------------------------------
+-- ^^^ End plpgsql tests
+---------------------------------------------------
+\c :provider_dsn
+\set VERBOSITY terse
+DROP FUNCTION funcn_add(integer, integer);
+DROP FUNCTION funcn_nochange(text);
+DROP FUNCTION funcn_get_curr_decade();
+SELECT pglogical.replicate_ddl_command($$
+ DROP TABLE public.basic_dml CASCADE;
+ DROP TABLE public.test_jsonb CASCADE;
+$$);
+NOTICE: drop cascades to table public.basic_dml membership in replication set default
+NOTICE: drop cascades to table public.test_jsonb membership in replication set default
+ replicate_ddl_command
+-----------------------
+ t
+(1 row)
+