From 94040b08d3bbde56e8816eaa1f93f950f5b618eb Mon Sep 17 00:00:00 2001 From: Zsolt Parragi Date: Thu, 15 Oct 2026 11:29:50 +0000 Subject: [PATCH v1] Fix sequence synchronization when the sequence owner can't be assumed. With run_as_owner = false, the sequencesync worker switches to the sequence owner before updating a sequence. If the subscription owner cannot SET ROLE to that owner, SwitchToUntrustedUser() raises an ERROR that aborts the whole batch. So, none of the other sequences in this or the later batches are marked READY, and the worker restarts repeatedly with 'role "x" cannot SET ROLE to "y"', which doesn't even name the sequence. A sequence owner lacking UPDATE on the sequence is instead reported as a WARNING that names the sequence, and the remaining sequences are still synchronized. The comment above that WARNING already assumed the switch to the sequence owner can't fail. To fix this, we check that the subscription owner can SET ROLE to the sequence owner before switching, and report the sequence as having insufficient privileges on the subscriber when it can't. Author: Zsolt Parragi Backpatch-through: 19, where it was introduced Discussion: https://postgr.es/m/ --- .../replication/logical/sequencesync.c | 14 +++++- src/test/subscription/t/036_sequences.pl | 47 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/backend/replication/logical/sequencesync.c b/src/backend/replication/logical/sequencesync.c index 8d6b0cfef19..325eb049209 100644 --- a/src/backend/replication/logical/sequencesync.c +++ b/src/backend/replication/logical/sequencesync.c @@ -208,7 +208,9 @@ report_sequence_errors(List *mismatched_seqs_idx, * With run_as_owner enabled, sequence synchronization runs as the * subscription owner, so a missing UPDATE privilege should be granted * to that role. Otherwise, the worker switches to the sequence owner - * before checking privileges, so no useful GRANT hint can be + * before checking privileges, and the problem can be either that the + * subscription owner cannot SET ROLE to the sequence owner or that + * the sequence owner lacks UPDATE, so no useful GRANT hint can be * provided. */ ereport(WARNING, @@ -449,9 +451,19 @@ copy_sequence(LogicalRepSequenceInfo *seqinfo, Oid seqowner) /* * If the user did not opt to run as the owner of the subscription * ('run_as_owner'), then copy the sequence as the owner of the sequence. + * + * Check that we can switch to the sequence owner first, so that this is + * reported like a missing privilege rather than raising an error in + * SwitchToUntrustedUser() that would stop the synchronization of all the + * other sequences too. */ if (!run_as_owner) + { + if (!member_can_set_role(GetUserId(), seqowner)) + return COPYSEQ_SUBSCRIBER_INSUFFICIENT_PERM; + SwitchToUntrustedUser(seqowner, &ucxt); + } aclresult = pg_class_aclcheck(seqoid, GetUserId(), ACL_UPDATE); diff --git a/src/test/subscription/t/036_sequences.pl b/src/test/subscription/t/036_sequences.pl index dd6fa515df3..361b32f950b 100644 --- a/src/test/subscription/t/036_sequences.pl +++ b/src/test/subscription/t/036_sequences.pl @@ -382,4 +382,51 @@ $node_subscriber->wait_for_log( qr/WARNING: ( [A-Z0-9]+:)? missing sequence on publisher \("public.regress_s2"\)/, $log_offset); +########## +# Ensure that a subscriber sequence owned by a role the subscription owner +# cannot SET ROLE to is reported as a permission issue, and does not prevent +# the other sequences from being synchronized. +########## + +$node_subscriber->safe_psql( + 'postgres', qq( + ALTER SUBSCRIPTION regress_seq_sub CONNECTION '$publisher_connstr'; + ALTER SUBSCRIPTION regress_seq_sub REFRESH PUBLICATION WITH (copy_data = false); + ALTER SUBSCRIPTION regress_seq_sub SET (password_required = false); + CREATE ROLE regress_seq_sub_owner LOGIN; + CREATE ROLE regress_seq_other; + GRANT CREATE ON DATABASE postgres TO regress_seq_sub_owner; + ALTER SEQUENCE regress_s1 OWNER TO regress_seq_sub_owner; + ALTER SEQUENCE regress_s3 OWNER TO regress_seq_sub_owner; + ALTER SEQUENCE "regress'quote" OWNER TO regress_seq_sub_owner; + ALTER SEQUENCE regress_s4 OWNER TO regress_seq_other; + ALTER SUBSCRIPTION regress_seq_sub OWNER TO regress_seq_sub_owner; +)); + +$node_publisher->safe_psql( + 'postgres', qq( + SELECT setval('regress_s1', 500); + SELECT setval('regress_s4', 500); +)); + +$log_offset = -s $node_subscriber->logfile; + +$node_subscriber->safe_psql('postgres', + "ALTER SUBSCRIPTION regress_seq_sub REFRESH SEQUENCES"); + +$node_subscriber->wait_for_log( + qr/WARNING: ( [A-Z0-9]+:)? insufficient privileges on subscriber sequence \("public.regress_s4"\)/, + $log_offset); + +# Check - the other sequences are synced and marked as ready +$result = $node_subscriber->safe_psql( + 'postgres', qq( + SELECT srrelid::regclass, srsubstate FROM pg_subscription_rel + WHERE srsubstate <> 'r'; + SELECT last_value, is_called FROM regress_s1; +)); +is( $result, "regress_s4|i\n500|t", + 'sequence owned by a role that cannot be switched to does not block the others' +); + done_testing(); -- 2.56.0