From 7409192b88854df4ad2490cb8efa65bc6097ef2c Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Mon, 19 Jan 2026 18:25:23 +0530
Subject: [PATCH v1] Handle concurrent sequence drop during sequence sync

pg_get_sequence_data() may return NULL values when a sequence is dropped concurrently,
as it uses try_relation_open() internally. The sequence sync worker previously assumed
non-NULL values for sequence state fields, leading to assertion failures when concurrent
DDL occurred.

Fix it by checking NULL sequence state values and skip the affected sequence gracefully.
---
 .../replication/logical/sequencesync.c        | 25 +++++++++++++------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/src/backend/replication/logical/sequencesync.c b/src/backend/replication/logical/sequencesync.c
index 509388d1bf4..14e47d3b2d5 100644
--- a/src/backend/replication/logical/sequencesync.c
+++ b/src/backend/replication/logical/sequencesync.c
@@ -233,6 +233,7 @@ get_and_validate_seq_info(TupleTableSlot *slot, Relation *sequence_rel,
 {
 	bool		isnull;
 	int			col = 0;
+	Datum		datum;
 	Oid			remote_typid;
 	int64		remote_start;
 	int64		remote_increment;
@@ -251,14 +252,24 @@ get_and_validate_seq_info(TupleTableSlot *slot, Relation *sequence_rel,
 	*seqinfo = seqinfo_local =
 		(LogicalRepSequenceInfo *) list_nth(seqinfos, *seqidx);
 
-	seqinfo_local->last_value = DatumGetInt64(slot_getattr(slot, ++col, &isnull));
-	Assert(!isnull);
+	/*
+	 * If the sequence was dropped concurrently, pg_get_sequence_data() can
+	 * return NULLs.
+	 */
+	datum = slot_getattr(slot, ++col, &isnull);
+	if (isnull)
+		return COPYSEQ_SKIPPED;
+	seqinfo_local->last_value = DatumGetInt64(datum);
 
-	seqinfo_local->is_called = DatumGetBool(slot_getattr(slot, ++col, &isnull));
-	Assert(!isnull);
+	datum = slot_getattr(slot, ++col, &isnull);
+	if (isnull)
+		return COPYSEQ_SKIPPED;
+	seqinfo_local->is_called = DatumGetBool(datum);
 
-	seqinfo_local->page_lsn = DatumGetLSN(slot_getattr(slot, ++col, &isnull));
-	Assert(!isnull);
+	datum = slot_getattr(slot, ++col, &isnull);
+	if (isnull)
+		return COPYSEQ_SKIPPED;
+	seqinfo_local->page_lsn = DatumGetLSN(datum);
 
 	remote_typid = DatumGetObjectId(slot_getattr(slot, ++col, &isnull));
 	Assert(!isnull);
@@ -400,7 +411,7 @@ copy_sequences(WalReceiverConn *conn)
 		int			batch_skipped_count = 0;
 		int			batch_insuffperm_count = 0;
 		int			batch_missing_count;
-		Relation	sequence_rel;
+		Relation	sequence_rel = NULL;
 
 		WalRcvExecResult *res;
 		TupleTableSlot *slot;
-- 
2.43.0

