From: Amit Kapila Date: Tue, 21 Jul 2026 03:53:11 +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=d774576f6f05f65e3a944eb509ef0620ea6b107e;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/worker.c b/src/backend/replication/logical/worker.c index 7799266c614..0ff5cef63cd 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -5809,6 +5809,14 @@ InitializeLogRepWorker(void) */ SetConfigOption("search_path", "", PGC_SUSET, PGC_S_OVERRIDE); + /* + * Ignore default_transaction_read_only for logical replication workers, + * as they need to be able to modify subscriber-side state regardless of + * that setting. + */ + SetConfigOption("default_transaction_read_only", "off", PGC_SUSET, + PGC_S_OVERRIDE); + ApplyContext = AllocSetContextCreate(TopMemoryContext, "ApplyContext", ALLOCSET_DEFAULT_SIZES); 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