From 2a808c27c6c1ed444e6667d0e8eb1f8dde24fa3b Mon Sep 17 00:00:00 2001 From: Vignesh C Date: Mon, 13 Jul 2026 18:09:25 +0530 Subject: [PATCH v1] Fix sequence synchronization for concurrently dropped sequences A sequence can be dropped concurrently after the sequence synchronization worker has collected its metadata but before it reads the sequence data. In this case, 'has_sequence_privilege()' returns NULL rather than false. 'get_and_validate_seq_info()' assumed the privilege value was never NULL, causing an assertion failure in assert-enabled builds. Treat a NULL privilege value as indicating that the sequence no longer exists and report it using the existing "missing sequence on publisher" path. --- .../replication/logical/sequencesync.c | 11 ++-- src/test/subscription/t/036_sequences.pl | 50 ++++++++++++++++++- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/backend/replication/logical/sequencesync.c b/src/backend/replication/logical/sequencesync.c index 770fa5de10b..0b34403569c 100644 --- a/src/backend/replication/logical/sequencesync.c +++ b/src/backend/replication/logical/sequencesync.c @@ -290,12 +290,15 @@ get_and_validate_seq_info(TupleTableSlot *slot, Relation *sequence_rel, (LogicalRepSequenceInfo *) list_nth(seqinfos, *seqidx); /* - * The remote sequence state can be NULL if the publisher lacks the - * required privileges or if the sequence was dropped concurrently after - * it was identified in the catalog snapshot (see pg_get_sequence_data()). + * has_sequence_privilege() itself returns NULL, rather than false, when + * the sequence has been dropped concurrently after it was identified in + * the catalog snapshot (see has_sequence_privilege_id()). Treat that the + * same as the concurrent-drop case detected via the data columns below, + * rather than misreporting it as an insufficient-privilege failure. */ remote_has_select_priv = DatumGetBool(slot_getattr(slot, ++col, &isnull)); - Assert(!isnull); + if (isnull) + return COPYSEQ_SKIPPED; datum = slot_getattr(slot, ++col, &isnull); if (isnull) diff --git a/src/test/subscription/t/036_sequences.pl b/src/test/subscription/t/036_sequences.pl index 2a0819aaf01..58384d1f710 100644 --- a/src/test/subscription/t/036_sequences.pl +++ b/src/test/subscription/t/036_sequences.pl @@ -188,6 +188,54 @@ is($result, '1|f', 'REFRESH PUBLICATION will not sync newly published sequence with copy_data as false' ); +########## +# A sequence dropped concurrently on the publisher, while the sequencesync +# worker's batch query is executing, must be treated the same as any other +# concurrently-dropped sequence (reported as "missing sequence on publisher"). +########## + +my $log_offset = -s $node_subscriber->logfile; + +# Block the sequencesync worker's batch query on the publisher: an +# uncommitted DROP SEQUENCE holds AccessExclusiveLock, on which the +# pg_get_sequence_data() call in the batch query will wait. +my $pub_session = $node_publisher->background_psql('postgres'); +$pub_session->query_safe( + qq( + BEGIN; + DROP SEQUENCE regress_s3; +)); + +$node_subscriber->safe_psql('postgres', + "ALTER SUBSCRIPTION regress_seq_sub REFRESH SEQUENCES"); + +# Wait until the worker's batch query is blocked on the still uncommitted +# DROP. +$node_publisher->poll_query_until( + 'postgres', qq( + SELECT EXISTS ( + SELECT 1 FROM pg_locks + WHERE relation = 'regress_s3'::regclass AND NOT granted); +)) or die "timed out waiting for sequencesync worker to block on publisher"; + +# Commit the DROP while the batch query is blocked inside it, so the query +# resumes against a sequence that no longer exists. +$pub_session->query_safe("COMMIT"); +$pub_session->quit; + +$node_subscriber->wait_for_log( + qr/WARNING: ( [A-Z0-9]+:)? missing sequence on publisher \("public.regress_s3"\)/, + $log_offset); + +$node_publisher->safe_psql( + 'postgres', qq( + create sequence regress_s3; +)); + +# Wait for the missing sequence added to be synced +$node_subscriber->poll_query_until('postgres', $synced_query) + or die "Timed out while waiting for subscriber to synchronize data"; + ########## # ALTER SUBSCRIPTION ... REFRESH PUBLICATION should report an error when: # a) sequence definitions differ between the publisher and subscriber, or @@ -206,7 +254,7 @@ $node_subscriber->safe_psql( CREATE SEQUENCE regress_s4 START 10 INCREMENT 2; )); -my $log_offset = -s $node_subscriber->logfile; +$log_offset = -s $node_subscriber->logfile; # Do ALTER SUBSCRIPTION ... REFRESH PUBLICATION $node_subscriber->safe_psql('postgres', -- 2.50.1 (Apple Git-155)