From 542ff1da0f42ad21189418f33db68bf618a873e0 Mon Sep 17 00:00:00 2001
From: Rahul Yadav <rahul@rhyadav.dev>
Date: Thu, 1 Oct 2026 07:46:25 +0100
Subject: [PATCH v1 1/2] Report the decoded record's LSN in DecodeXLogRecord()
 errors

DecodeXLogRecord() is passed the LSN of the record it decodes, but its
error messages printed state->ReadRecPtr instead.  Before 3f1ce97346
added the circular WAL decoding buffer, the two were the same, since
XLogReadRecord() set ReadRecPtr before decoding.  Now records are
decoded ahead of the one the reader last returned, so these messages
named an earlier record: in pg_waldump the record just before the
failing one, and in crash recovery, which reads further ahead, one
several records back.

Use the lsn argument instead.  The only other caller, the WAL_DEBUG
code in XLogInsertRecord(), passes the end of the record it has just
inserted, which matches the LSN that code logs for it.

Noticed while testing a fix for bug #19599.

Author: Rahul Yadav <rahul@rhyadav.dev>
Backpatch-through: 15
---
 src/backend/access/transam/xlogreader.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 7db7c273b0..6573270dab 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -1818,7 +1818,7 @@ DecodeXLogRecord(XLogReaderState *state,
 				report_invalid_record(state,
 									  "out-of-order block_id %u at %X/%08X",
 									  block_id,
-									  LSN_FORMAT_ARGS(state->ReadRecPtr));
+									  LSN_FORMAT_ARGS(lsn));
 				goto err;
 			}
 			decoded->max_block_id = block_id;
@@ -1841,7 +1841,7 @@ DecodeXLogRecord(XLogReaderState *state,
 			{
 				report_invalid_record(state,
 									  "BKPBLOCK_HAS_DATA set, but no data included at %X/%08X",
-									  LSN_FORMAT_ARGS(state->ReadRecPtr));
+									  LSN_FORMAT_ARGS(lsn));
 				goto err;
 			}
 			if (!blk->has_data && blk->data_len != 0)
@@ -1849,7 +1849,7 @@ DecodeXLogRecord(XLogReaderState *state,
 				report_invalid_record(state,
 									  "BKPBLOCK_HAS_DATA not set, but data length is %d at %X/%08X",
 									  blk->data_len,
-									  LSN_FORMAT_ARGS(state->ReadRecPtr));
+									  LSN_FORMAT_ARGS(lsn));
 				goto err;
 			}
 			datatotal += blk->data_len;
@@ -1887,7 +1887,7 @@ DecodeXLogRecord(XLogReaderState *state,
 										  blk->hole_offset,
 										  blk->hole_length,
 										  blk->bimg_len,
-										  LSN_FORMAT_ARGS(state->ReadRecPtr));
+										  LSN_FORMAT_ARGS(lsn));
 					goto err;
 				}
 
@@ -1902,7 +1902,7 @@ DecodeXLogRecord(XLogReaderState *state,
 										  "BKPIMAGE_HAS_HOLE not set, but hole offset %d length %d at %X/%08X",
 										  blk->hole_offset,
 										  blk->hole_length,
-										  LSN_FORMAT_ARGS(state->ReadRecPtr));
+										  LSN_FORMAT_ARGS(lsn));
 					goto err;
 				}
 
@@ -1915,7 +1915,7 @@ DecodeXLogRecord(XLogReaderState *state,
 					report_invalid_record(state,
 										  "BKPIMAGE_COMPRESSED set, but block image length %d at %X/%08X",
 										  blk->bimg_len,
-										  LSN_FORMAT_ARGS(state->ReadRecPtr));
+										  LSN_FORMAT_ARGS(lsn));
 					goto err;
 				}
 
@@ -1930,7 +1930,7 @@ DecodeXLogRecord(XLogReaderState *state,
 					report_invalid_record(state,
 										  "neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image length is %d at %X/%08X",
 										  blk->bimg_len,
-										  LSN_FORMAT_ARGS(state->ReadRecPtr));
+										  LSN_FORMAT_ARGS(lsn));
 					goto err;
 				}
 			}
@@ -1945,7 +1945,7 @@ DecodeXLogRecord(XLogReaderState *state,
 				{
 					report_invalid_record(state,
 										  "BKPBLOCK_SAME_REL set but no previous rel at %X/%08X",
-										  LSN_FORMAT_ARGS(state->ReadRecPtr));
+										  LSN_FORMAT_ARGS(lsn));
 					goto err;
 				}
 
@@ -1957,7 +1957,7 @@ DecodeXLogRecord(XLogReaderState *state,
 		{
 			report_invalid_record(state,
 								  "invalid block_id %u at %X/%08X",
-								  block_id, LSN_FORMAT_ARGS(state->ReadRecPtr));
+								  block_id, LSN_FORMAT_ARGS(lsn));
 			goto err;
 		}
 	}
@@ -2024,7 +2024,7 @@ DecodeXLogRecord(XLogReaderState *state,
 shortdata_err:
 	report_invalid_record(state,
 						  "record with invalid length at %X/%08X",
-						  LSN_FORMAT_ARGS(state->ReadRecPtr));
+						  LSN_FORMAT_ARGS(lsn));
 err:
 	*errormsg = state->errormsg_buf;
 
-- 
2.50.1 (Apple Git-155)

