From 878905788911e1cf6fea0e0b24f1d688343f245b Mon Sep 17 00:00:00 2001 From: Khanna Date: Fri, 16 Aug 2024 16:04:30 +0530 Subject: [PATCH v28 2/2] Tap tests for 'include-generated-columns' Tap tests for for all combinations of replication related to generated columns, i.e. both with and without 'include_generated_columns' option enabled. --- src/test/subscription/t/011_generated.pl | 334 +++++++++++++++++++++-- 1 file changed, 313 insertions(+), 21 deletions(-) diff --git a/src/test/subscription/t/011_generated.pl b/src/test/subscription/t/011_generated.pl index 8b2e5f4708..493c0d12dc 100644 --- a/src/test/subscription/t/011_generated.pl +++ b/src/test/subscription/t/011_generated.pl @@ -20,35 +20,29 @@ $node_subscriber->start; my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres'; -$node_publisher->safe_psql('postgres', - "CREATE TABLE tab1 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 2) STORED)" -); - -$node_subscriber->safe_psql('postgres', - "CREATE TABLE tab1 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 22) STORED, c int)" -); - -# data for initial sync +$node_publisher->safe_psql( + 'postgres', qq( + CREATE TABLE tab1 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 2) STORED); + INSERT INTO tab1 (a) VALUES (1), (2), (3); + CREATE PUBLICATION pub1 FOR ALL TABLES; +)); -$node_publisher->safe_psql('postgres', - "INSERT INTO tab1 (a) VALUES (1), (2), (3)"); - -$node_publisher->safe_psql('postgres', - "CREATE PUBLICATION pub1 FOR ALL TABLES"); -$node_subscriber->safe_psql('postgres', - "CREATE SUBSCRIPTION sub1 CONNECTION '$publisher_connstr' PUBLICATION pub1" -); +$node_subscriber->safe_psql( + 'postgres', qq( + CREATE TABLE tab1 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 22) STORED, c int); + CREATE SUBSCRIPTION sub1 CONNECTION '$publisher_connstr' PUBLICATION pub1; +)); -# Wait for initial sync of all subscriptions +# Wait for initial sync of node_subscriber $node_subscriber->wait_for_subscription_sync; +# Check initial sync data is synchronized after initial sync. my $result = $node_subscriber->safe_psql('postgres', "SELECT a, b FROM tab1"); is( $result, qq(1|22 2|44 3|66), 'generated columns initial sync'); -# data to replicate - +# Insert data to verify incremental sync $node_publisher->safe_psql('postgres', "INSERT INTO tab1 VALUES (4), (5)"); $node_publisher->safe_psql('postgres', "UPDATE tab1 SET a = 6 WHERE a = 5"); @@ -75,7 +69,7 @@ END $$; CREATE TRIGGER test1 BEFORE INSERT OR UPDATE ON tab1 FOR EACH ROW - EXECUTE PROCEDURE tab1_trigger_func(); + EXECUTE PROCEDURE tab1_trigger_func(); ALTER TABLE tab1 ENABLE REPLICA TRIGGER test1; }); @@ -96,4 +90,302 @@ is( $result, qq(1|22| 8|176|18 9|198|19), 'generated columns replicated with trigger'); +$node_subscriber->safe_psql('postgres', "CREATE DATABASE test"); + +# ============================================================================= +# Testcase start: Publisher table with a generated column (b) and subscriber +# table a with regular column (b). + +# Create table and publication. +$node_publisher->safe_psql( + 'postgres', qq( + CREATE TABLE tab_gen_to_nogen (a int, b int GENERATED ALWAYS AS (a * 2) STORED); + INSERT INTO tab_gen_to_nogen (a) VALUES (1), (2), (3); + CREATE PUBLICATION regress_pub_gen_to_nogen FOR TABLE tab_gen_to_nogen; +)); + +# Create subscription with include_generated_columns as false. +$node_subscriber->safe_psql( + 'postgres', qq( + CREATE TABLE tab_gen_to_nogen (a int, b int); + CREATE SUBSCRIPTION regress_sub1_gen_to_nogen CONNECTION '$publisher_connstr' + PUBLICATION regress_pub_gen_to_nogen WITH (include_generated_columns = false, copy_data = true); +)); + +# Create subscription with include_generated_columns as true. +$node_subscriber->safe_psql( + 'test', qq( + CREATE TABLE tab_gen_to_nogen (a int, b int); + CREATE SUBSCRIPTION regress_sub2_gen_to_nogen CONNECTION '$publisher_connstr' + PUBLICATION regress_pub_gen_to_nogen WITH (include_generated_columns = true, copy_data = false); +)); + +# Wait for initial sync. +$node_subscriber->wait_for_subscription_sync; + +# Verify that column 'b' is not replicated for the subscription +# regress_sub1_gen_to_nogen when include_generated_columns is set to false +# during initial sync. +$result = $node_subscriber->safe_psql('postgres', + "SELECT a, b FROM tab_gen_to_nogen"); +is( $result, qq(1| +2| +3|), 'tab_gen_to_nogen, when include_generated_columns=false'); + +# Insert data to verify incremental sync +$node_publisher->safe_psql('postgres', + "INSERT INTO tab_gen_to_nogen VALUES (4), (5)"); + +# Verify that column 'b' is not replicated for the subscription +# regress_sub1_gen_to_nogen when include_generated_columns is set to false +# during incremental sync. +$node_publisher->wait_for_catchup('regress_sub1_gen_to_nogen'); +$result = + $node_subscriber->safe_psql('postgres', + "SELECT a, b FROM tab_gen_to_nogen ORDER BY a"); +is( $result, qq(1| +2| +3| +4| +5|), + 'confirm generated columns are not replicated when the subscriber-side column is not generated' +); + +# Verify that column 'b' is replicated for the subscription +# regress_sub2_gen_to_nogen when include_generated_columns is set to true. +$node_publisher->wait_for_catchup('regress_sub2_gen_to_nogen'); +$result = + $node_subscriber->safe_psql('test', + "SELECT a, b FROM tab_gen_to_nogen ORDER BY a"); +is( $result, qq(4|8 +5|10), + 'confirm generated columns are replicated when the subscriber-side column is not generated' +); + +# cleanup +$node_subscriber->safe_psql('postgres', + "DROP SUBSCRIPTION regress_sub1_gen_to_nogen"); +$node_subscriber->safe_psql('test', + "DROP SUBSCRIPTION regress_sub2_gen_to_nogen"); +$node_publisher->safe_psql('postgres', + "DROP PUBLICATION regress_pub_gen_to_nogen"); + +# Testcase end: Publisher table with a generated column (b) and subscriber +# table a with regular column (b). +# ============================================================================= + +# ============================================================================= +# Testcase start: Publisher table with a generated column (b) on the publisher, +# where column (b) is not present on the subscriber. + +# Create table and publication. +$node_publisher->safe_psql( + 'postgres', qq( + CREATE TABLE tab_gen_to_missing (a int, b int GENERATED ALWAYS AS (a * 2) STORED); + INSERT INTO tab_gen_to_missing (a) VALUES (1), (2), (3); + CREATE PUBLICATION regress_pub_gen_to_missing FOR TABLE tab_gen_to_missing; +)); + +# Create subscription with include_generated_columns as false. +$node_subscriber->safe_psql( + 'postgres', qq( + CREATE TABLE tab_gen_to_missing (a int); + CREATE SUBSCRIPTION regress_sub1_gen_to_missing CONNECTION '$publisher_connstr' + PUBLICATION regress_pub_gen_to_missing WITH (include_generated_columns = false, copy_data = true); +)); + +# Create subscription with include_generated_columns as true. +$node_subscriber->safe_psql( + 'test', qq( + CREATE TABLE tab_gen_to_missing (a int); + CREATE SUBSCRIPTION regress_sub2_gen_to_missing CONNECTION '$publisher_connstr' + PUBLICATION regress_pub_gen_to_missing WITH (include_generated_columns = true, copy_data = false); +)); + +# Wait for initial sync. +$node_subscriber->wait_for_subscription_sync; + +# Verify that initial sync data is correctly synchronized to the subscription +# regress_sub1_gen_to_missing with copy_data set to true after the initial sync. +$result = + $node_subscriber->safe_psql('postgres', "SELECT a FROM tab_gen_to_missing"); +is( $result, qq(1 +2 +3), 'tab_gen_to_missing initial sync, when include_generated_columns=false'); + +# Insert data to verify incremental sync. +$node_publisher->safe_psql('postgres', + "INSERT INTO tab_gen_to_missing VALUES (4), (5)"); + +# Verify that column 'b' is not replicated for the subscription +# regress_sub1_gen_to_missing when include_generated_columns is set to false. +$node_publisher->wait_for_catchup('regress_sub1_gen_to_missing'); +$result = + $node_subscriber->safe_psql('postgres', + "SELECT a FROM tab_gen_to_missing ORDER BY a"); +is( $result, qq(1 +2 +3 +4 +5), 'missing generated column, include_generated_columns = false'); + +my $offset = -s $node_subscriber->logfile; + +# Verify that an error is thrown during incremental data sync for the +# subscription regress_sub2_gen_to_missing when include_generated_columns is +# set to true. +$node_subscriber->wait_for_log( + qr/ERROR: ( [A-Z0-9]+:)? logical replication target relation "public.tab_gen_to_missing" is missing replicated column: "b"/, + $offset); + +# cleanup +$node_subscriber->safe_psql('postgres', + "DROP SUBSCRIPTION regress_sub1_gen_to_missing"); +$node_publisher->safe_psql('postgres', + "DROP PUBLICATION regress_pub_gen_to_missing"); + +# Testcase end: Publisher table with a generated column (b) on the publisher, +# where column (b) is not present on the subscriber. +# ============================================================================= + +# ============================================================================= +# Testcase start: Subscriber table with a generated column (b) on the +# subscriber, where column (b) is not present on the publisher. + +# Create table and publication. +$node_publisher->safe_psql( + 'postgres', qq( + CREATE TABLE tab_missing_to_gen (a int); + INSERT INTO tab_missing_to_gen (a) VALUES (1), (2), (3); + CREATE PUBLICATION regress_pub_missing_to_gen FOR TABLE tab_missing_to_gen; +)); + +# Create subscription with include_generated_columns as false. +$node_subscriber->safe_psql( + 'postgres', qq( + CREATE TABLE tab_missing_to_gen (a int, b int GENERATED ALWAYS AS (a * 22) STORED); + CREATE SUBSCRIPTION regress_sub1_missing_to_gen CONNECTION '$publisher_connstr' + PUBLICATION regress_pub_missing_to_gen WITH (include_generated_columns = false, copy_data = true); +)); + +# Create subscription with include_generated_columns as true. +$node_subscriber->safe_psql( + 'test', qq( + CREATE TABLE tab_missing_to_gen (a int, b int GENERATED ALWAYS AS (a * 22) STORED); + CREATE SUBSCRIPTION regress_sub2_missing_to_gen CONNECTION '$publisher_connstr' + PUBLICATION regress_pub_missing_to_gen WITH (include_generated_columns = true, copy_data = false); +)); + +# Wait for initial sync. +$node_subscriber->wait_for_subscription_sync; + +# Verify that initial sync data is correctly synchronized to the subscription +# regress_sub1_gen_to_missing with copy_data set to true following the initial +# sync. +$result = $node_subscriber->safe_psql('postgres', + "SELECT a, b FROM tab_missing_to_gen"); +is( $result, qq(1|22 +2|44 +3|66), 'tab_missing_to_gen initial sync, when include_generated_columns=false' +); + +# Insert data to verify incremental sync. +$node_publisher->safe_psql('postgres', + "INSERT INTO tab_missing_to_gen VALUES (4), (5)"); + +# Verify that column 'b' is not replicated but is generated as usual for the +# subscription regress_sub1_gen_to_missing when include_generated_columns is +# set to false. +$node_publisher->wait_for_catchup('regress_sub1_missing_to_gen'); +$result = + $node_subscriber->safe_psql('postgres', + "SELECT a, b FROM tab_missing_to_gen ORDER BY a"); +is( $result, qq(1|22 +2|44 +3|66 +4|88 +5|110), + 'confirm when publisher col is missing, subscriber generated columns are generated as normal' +); + +# Verify that column 'b' is not replicated but is generated as expected for the +# subscription regress_sub1_gen_to_missing when include_generated_columns is set +# to true. +$node_publisher->wait_for_catchup('regress_sub2_missing_to_gen'); +$result = + $node_subscriber->safe_psql('test', + "SELECT a, b FROM tab_missing_to_gen ORDER BY a"); +is( $result, qq(4|88 +5|110), + 'confirm when publisher col is missing, subscriber generated columns are generated as normal' +); + +# cleanup +$node_subscriber->safe_psql('postgres', + "DROP SUBSCRIPTION regress_sub1_missing_to_gen"); +$node_publisher->safe_psql('postgres', + "DROP PUBLICATION regress_pub_missing_to_gen"); + +# Testcase end: Subscriber table with a generated column (b) on the +# subscriber, where column (b) is not present on the publisher. +# ============================================================================= + +# ============================================================================= +# Testcase start: Publisher table with a non-generated column (b) on the +# publisher and generated column(b) on subscriber. + +# Create table and publication. +$node_publisher->safe_psql( + 'postgres', qq( + CREATE TABLE tab_nogen_to_gen (a int, b int); + INSERT INTO tab_nogen_to_gen (a, b) VALUES (1, 1), (2, 2), (3, 3); + CREATE PUBLICATION regress_pub_nogen_to_gen FOR TABLE tab_nogen_to_gen; +)); + +$offset = -s $node_subscriber->logfile; + +# Create subscription with include_generated_columns as false. +$node_subscriber->safe_psql( + 'postgres', qq( + CREATE TABLE tab_nogen_to_gen (a int, b int GENERATED ALWAYS AS (a * 22) STORED); + CREATE SUBSCRIPTION regress_sub1_nogen_to_gen CONNECTION '$publisher_connstr' + PUBLICATION regress_pub_nogen_to_gen WITH (include_generated_columns = false, copy_data = true); +)); + +# Verify that an error occurs during the initial sync of data from a +# non-generated to a generated column for the subscription +# regress_sub1_nogen_to_gen when include_generated_columns is set to false. +$node_subscriber->wait_for_log( + qr/ERROR: ( [A-Z0-9]:)? logical replication target relation "public.tab_nogen_to_gen" is missing replicated column: "b"/, + $offset); +$node_subscriber->safe_psql('postgres', + "DROP SUBSCRIPTION regress_sub1_nogen_to_gen"); + +# Create subscription with include_generated_columns as true. +$node_subscriber->safe_psql( + 'test', qq( + CREATE TABLE tab_nogen_to_gen (a int, b int GENERATED ALWAYS AS (a * 22) STORED); + CREATE SUBSCRIPTION regress_sub2_nogen_to_gen CONNECTION '$publisher_connstr' + PUBLICATION regress_pub_nogen_to_gen WITH (include_generated_columns = true, copy_data = false); +)); + +$offset = -s $node_subscriber->logfile; + +# Verify that an error occurs during incremental sync of data from a +# non-generated to a generated column for the subscription +# regress_sub2_nogen_to_gen when include_generated_columns is set to true. +$node_publisher->safe_psql('postgres', + "INSERT INTO tab_nogen_to_gen VALUES (4), (5)"); +$node_subscriber->wait_for_log( + qr/ERROR: ( [A-Z0-9]:)? logical replication target relation "public.tab_nogen_to_gen" is missing replicated column: "b"/, + $offset); + +# cleanup +$node_publisher->safe_psql('postgres', + "DROP PUBLICATION regress_pub_nogen_to_gen"); + +# Testcase end: Replication of table with non-generated column(b) on publisher +# and generated column(b) on subscriber. +# ============================================================================= + done_testing(); -- 2.34.1