From: Amit Kapila Date: Tue, 21 Jul 2026 03:42:52 +0000 (+0530) Subject: Allow logical replication workers to ignore default_transaction_read_only. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4cd02d552263ed8d4b148aaefd24cd9dd8af57ed;p=thirdparty%2Fpostgresql.git Allow logical replication workers to ignore default_transaction_read_only. Sequence synchronization updates sequence state via setval(), which explicitly calls PreventCommandIfReadOnly(). If default_transaction_read_only is enabled on the subscriber, this causes sequencesync workers to fail with "cannot execute setval() in a read-only transaction". Apply and tablesync workers are not affected, since they write via direct heap access rather than through these read-only-checked functions. Rather than special-casing sequencesync, override default_transaction_read_only to "off" for all logical replication workers in InitializeLogRepWorker(), the same way session_replication_role and search_path are already forced there. This keeps the initialization uniform. For PG-19, we kept the fix narrow by overriding default_transaction_read_only to "off" only for sequencesync workers. Reported-by: Noah Misch Author: vignesh C Reviewed-by: Amit Kapila Backpatch-through: 19 Discussion: https://postgr.es/m/20260710045217.f0.noahmisch@microsoft.com --- diff --git a/src/backend/replication/logical/sequencesync.c b/src/backend/replication/logical/sequencesync.c index 63ad46d7fd7..82f503f1c00 100644 --- a/src/backend/replication/logical/sequencesync.c +++ b/src/backend/replication/logical/sequencesync.c @@ -835,6 +835,14 @@ SequenceSyncWorkerMain(Datum main_arg) { int worker_slot = DatumGetInt32(main_arg); + /* + * Ignore default_transaction_read_only for sequence synchronization + * workers, as they need to be able to modify sequences regardless of that + * setting. + */ + SetConfigOption("default_transaction_read_only", "off", PGC_SUSET, + PGC_S_OVERRIDE); + SetupApplyOrSyncWorker(worker_slot); start_sequence_sync(); diff --git a/src/test/subscription/t/036_sequences.pl b/src/test/subscription/t/036_sequences.pl index 77ac9386cd8..dd6fa515df3 100644 --- a/src/test/subscription/t/036_sequences.pl +++ b/src/test/subscription/t/036_sequences.pl @@ -188,6 +188,57 @@ is($result, '1|f', 'REFRESH PUBLICATION will not sync newly published sequence with copy_data as false' ); +########## +# Ensure that ALTER SUBSCRIPTION ... REFRESH SEQUENCES can still update +# sequence values and mark the sequence as ready even when +# default_transaction_read_only is enabled on the subscriber. +########## + +$node_subscriber->safe_psql( + 'postgres', qq( + ALTER SYSTEM SET default_transaction_read_only = on; + SELECT pg_reload_conf(); +)); + +# Update the existing sequence 'regress_s3' on the publisher +$node_publisher->safe_psql( + 'postgres', qq( + INSERT INTO regress_seq_test SELECT nextval('regress_s3') FROM generate_series(1,100); +)); + +$node_subscriber->safe_psql( + 'postgres', qq( + set default_transaction_read_only = off; + ALTER SUBSCRIPTION regress_seq_sub REFRESH SEQUENCES; +)); +$node_subscriber->poll_query_until('postgres', $synced_query) + or die "Timed out while waiting for subscriber to synchronize data"; + +# Check - sequence value is updated despite default_transaction_read_only +# being enabled on the subscriber +$result = $node_subscriber->safe_psql( + 'postgres', qq( + SELECT last_value, is_called FROM regress_s3; +)); +is($result, '200|t', + 'REFRESH SEQUENCES updates sequence value with default_transaction_read_only enabled' +); + +# Check - sequence is marked as ready ('r') +$result = $node_subscriber->safe_psql( + 'postgres', qq( + SELECT srsubstate FROM pg_subscription_rel WHERE srrelid = 'regress_s3'::regclass; +)); +is($result, 'r', + 'sequence is marked as ready after REFRESH SEQUENCES with default_transaction_read_only enabled' +); + +$node_subscriber->safe_psql( + 'postgres', qq( + ALTER SYSTEM SET default_transaction_read_only = off; + SELECT pg_reload_conf(); +)); + ########## # A sequence dropped concurrently on the publisher, while the sequencesync # worker's batch query is executing, must be treated the same as any other