# Copyright (c) 2021-2023, PostgreSQL Global Development Group # Test collations, in particular nondeterministic ones # (only works with ICU) use strict; use warnings; use PostgreSQL::Test::Cluster; use PostgreSQL::Test::Utils; use Test::More; if ($ENV{with_icu} ne 'yes') { plan skip_all => 'ICU not supported by this build'; } my $node_publisher = PostgreSQL::Test::Cluster->new('publisher'); $node_publisher->init( allows_streaming => 'logical', extra => [ '--locale=C', '--encoding=UTF8' ]); $node_publisher->start; my $node_subscriber = PostgreSQL::Test::Cluster->new('subscriber'); $node_subscriber->init( allows_streaming => 'logical', extra => [ '--locale=C', '--encoding=UTF8' ]); $node_subscriber->start; my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres'; # Test plan: Create a table with a nondeterministic collation in the # primary key column. Pre-insert rows on the publisher and subscriber # that are collation-wise equal but byte-wise different. (We use a # string in different normal forms for that.) Set up publisher and # subscriber. Update the row on the publisher, but don't change the # primary key column. The subscriber needs to find the row to be # updated using the nondeterministic collation semantics. We need to # test for both a replica identity index and for replica identity # full, since those have different code paths internally. $node_subscriber->safe_psql('postgres', q{CREATE COLLATION ctest_nondet (provider = icu, locale = 'und', deterministic = false)} ); # table with replica identity index $node_publisher->safe_psql('postgres', q{CREATE TABLE tab1 (a text PRIMARY KEY, b text)}); $node_publisher->safe_psql('postgres', q{INSERT INTO tab1 VALUES (U&'\00E4bc', 'foo')}); $node_subscriber->safe_psql('postgres', q{CREATE TABLE tab1 (a text COLLATE ctest_nondet PRIMARY KEY, b text)}); $node_subscriber->safe_psql('postgres', q{INSERT INTO tab1 VALUES (U&'\0061\0308bc', 'foo')}); # table with replica identity full $node_publisher->safe_psql('postgres', q{CREATE TABLE tab2 (a text, b text)}); $node_publisher->safe_psql('postgres', q{ALTER TABLE tab2 REPLICA IDENTITY FULL}); $node_publisher->safe_psql('postgres', q{INSERT INTO tab2 VALUES (U&'\00E4bc', 'foo')}); $node_subscriber->safe_psql('postgres', q{CREATE TABLE tab2 (a text COLLATE ctest_nondet, b text)}); $node_subscriber->safe_psql('postgres', q{ALTER TABLE tab2 REPLICA IDENTITY FULL}); $node_subscriber->safe_psql('postgres', q{INSERT INTO tab2 VALUES (U&'\0061\0308bc', 'foo')}); # set up publication, subscription $node_publisher->safe_psql('postgres', q{CREATE PUBLICATION pub1 FOR ALL TABLES}); $node_subscriber->safe_psql('postgres', qq{CREATE SUBSCRIPTION sub1 CONNECTION '$publisher_connstr' PUBLICATION pub1 WITH (copy_data = false)} ); $node_publisher->wait_for_catchup('sub1'); # test with replica identity index $node_publisher->safe_psql('postgres', q{UPDATE tab1 SET b = 'bar' WHERE b = 'foo'}); $node_publisher->wait_for_catchup('sub1'); is($node_subscriber->safe_psql('postgres', q{SELECT b FROM tab1}), qq(bar), 'update with primary key with nondeterministic collation'); # test with replica identity full $node_publisher->safe_psql('postgres', q{UPDATE tab2 SET b = 'bar' WHERE b = 'foo'}); $node_publisher->wait_for_catchup('sub1'); is($node_subscriber->safe_psql('postgres', q{SELECT b FROM tab2}), qq(bar), 'update with replica identity full with nondeterministic collation'); done_testing();