]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Allow logical replication workers to ignore default_transaction_read_only.
authorAmit Kapila <akapila@postgresql.org>
Tue, 21 Jul 2026 03:53:11 +0000 (09:23 +0530)
committerAmit Kapila <akapila@postgresql.org>
Tue, 21 Jul 2026 03:53:11 +0000 (09:23 +0530)
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 <noah@leadboat.com>
Author: vignesh C <vignesh21@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Backpatch-through: 19
Discussion: https://postgr.es/m/20260710045217.f0.noahmisch@microsoft.com

src/backend/replication/logical/worker.c
src/test/subscription/t/036_sequences.pl

index 7799266c61409c984780b9134100f823ae09415b..0ff5cef63cddac0ca51a33164ae116c7655b97d4 100644 (file)
@@ -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);
index 77ac9386cd86ebdf85e7c57adcc98cf4ffbd68c2..dd6fa515df3feb97fbf1975bd5ec835432034785 100644 (file)
@@ -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