From b3e48f4724c1db83ef1ee1b9b9cbd413d0075a0d Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <lic@highgo.com>
Date: Sun, 20 Sep 2026 10:45:27 +0800
Subject: [PATCH v1 2/2] Handle empty LSN ranges in pg_walinspect

The pg_walinspect range functions accept equal start and end LSNs.
Such a range cannot contain a complete WAL record, but the functions
still initialized a WAL reader and searched for the next valid record.
Consequently, an empty range could either raise an error or return an
empty result depending on whether later WAL was available.

Skip WAL reader initialization for empty ranges. Return no rows from
the record and block information functions, while preserving the
existing zero-valued aggregate output from pg_get_wal_stats().

Author: Chao Li <lic@highgo.com>
---
 .../pg_walinspect/expected/pg_walinspect.out  | 27 +++++++++++++++++
 contrib/pg_walinspect/pg_walinspect.c         | 30 +++++++++++++------
 contrib/pg_walinspect/sql/pg_walinspect.sql   |  8 +++++
 3 files changed, 56 insertions(+), 9 deletions(-)

diff --git a/contrib/pg_walinspect/expected/pg_walinspect.out b/contrib/pg_walinspect/expected/pg_walinspect.out
index b9abeeebdfd..e62af64014d 100644
--- a/contrib/pg_walinspect/expected/pg_walinspect.out
+++ b/contrib/pg_walinspect/expected/pg_walinspect.out
@@ -34,6 +34,33 @@ SELECT * FROM pg_get_wal_stats(:'wal_lsn2', :'wal_lsn1');
 ERROR:  WAL start LSN must be less than or equal to end LSN
 SELECT * FROM pg_get_wal_block_info(:'wal_lsn2', :'wal_lsn1');
 ERROR:  WAL start LSN must be less than or equal to end LSN
+-- Empty ranges.
+SELECT pg_current_wal_flush_lsn() AS wal_lsn_end \gset
+SELECT COUNT(*) = 0 AS ok FROM pg_get_wal_records_info(:'wal_lsn_end', :'wal_lsn_end');
+ ok 
+----
+ t
+(1 row)
+
+SELECT COUNT(*) >= 1 AND SUM(count) = 0 AS ok
+  FROM pg_get_wal_stats(:'wal_lsn_end', :'wal_lsn_end');
+ ok 
+----
+ t
+(1 row)
+
+SELECT COUNT(*) = 0 AS ok FROM pg_get_wal_stats(:'wal_lsn_end', :'wal_lsn_end', true);
+ ok 
+----
+ t
+(1 row)
+
+SELECT COUNT(*) = 0 AS ok FROM pg_get_wal_block_info(:'wal_lsn_end', :'wal_lsn_end');
+ ok 
+----
+ t
+(1 row)
+
 -- LSNs with the highest value possible.
 SELECT * FROM pg_get_wal_record_info('FFFFFFFF/FFFFFFFF');
 ERROR:  WAL input LSN must be less than or equal to current LSN
diff --git a/contrib/pg_walinspect/pg_walinspect.c b/contrib/pg_walinspect/pg_walinspect.c
index 6edd6f8cb35..2e129bee9e2 100644
--- a/contrib/pg_walinspect/pg_walinspect.c
+++ b/contrib/pg_walinspect/pg_walinspect.c
@@ -435,6 +435,10 @@ pg_get_wal_block_info(PG_FUNCTION_ARGS)
 
 	InitMaterializedSRF(fcinfo, 0);
 
+	/* An empty range cannot contain any WAL records. */
+	if (start_lsn == end_lsn)
+		PG_RETURN_VOID();
+
 	xlogreader = InitXLogReaderState(start_lsn);
 
 	tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
@@ -560,6 +564,10 @@ GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
 
 	InitMaterializedSRF(fcinfo, 0);
 
+	/* An empty range cannot contain any WAL records. */
+	if (start_lsn == end_lsn)
+		return;
+
 	xlogreader = InitXLogReaderState(start_lsn);
 
 	tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
@@ -787,18 +795,22 @@ GetWalStats(FunctionCallInfo fcinfo, XLogRecPtr start_lsn, XLogRecPtr end_lsn,
 
 	InitMaterializedSRF(fcinfo, 0);
 
-	xlogreader = InitXLogReaderState(start_lsn);
-
-	while (ReadNextXLogRecord(xlogreader) &&
-		   xlogreader->EndRecPtr <= end_lsn)
+	/* An empty range cannot contain any WAL records. */
+	if (start_lsn < end_lsn)
 	{
-		XLogRecStoreStats(&stats, xlogreader);
+		xlogreader = InitXLogReaderState(start_lsn);
 
-		CHECK_FOR_INTERRUPTS();
-	}
+		while (ReadNextXLogRecord(xlogreader) &&
+			   xlogreader->EndRecPtr <= end_lsn)
+		{
+			XLogRecStoreStats(&stats, xlogreader);
 
-	pfree(xlogreader->private_data);
-	XLogReaderFree(xlogreader);
+			CHECK_FOR_INTERRUPTS();
+		}
+
+		pfree(xlogreader->private_data);
+		XLogReaderFree(xlogreader);
+	}
 
 	GetXLogSummaryStats(&stats, rsinfo, values, nulls,
 						PG_GET_WAL_STATS_COLS,
diff --git a/contrib/pg_walinspect/sql/pg_walinspect.sql b/contrib/pg_walinspect/sql/pg_walinspect.sql
index 1e64a22d29a..903fdfe0554 100644
--- a/contrib/pg_walinspect/sql/pg_walinspect.sql
+++ b/contrib/pg_walinspect/sql/pg_walinspect.sql
@@ -31,6 +31,14 @@ SELECT * FROM pg_get_wal_records_info(:'wal_lsn2', :'wal_lsn1');
 SELECT * FROM pg_get_wal_stats(:'wal_lsn2', :'wal_lsn1');
 SELECT * FROM pg_get_wal_block_info(:'wal_lsn2', :'wal_lsn1');
 
+-- Empty ranges.
+SELECT pg_current_wal_flush_lsn() AS wal_lsn_end \gset
+SELECT COUNT(*) = 0 AS ok FROM pg_get_wal_records_info(:'wal_lsn_end', :'wal_lsn_end');
+SELECT COUNT(*) >= 1 AND SUM(count) = 0 AS ok
+  FROM pg_get_wal_stats(:'wal_lsn_end', :'wal_lsn_end');
+SELECT COUNT(*) = 0 AS ok FROM pg_get_wal_stats(:'wal_lsn_end', :'wal_lsn_end', true);
+SELECT COUNT(*) = 0 AS ok FROM pg_get_wal_block_info(:'wal_lsn_end', :'wal_lsn_end');
+
 -- LSNs with the highest value possible.
 SELECT * FROM pg_get_wal_record_info('FFFFFFFF/FFFFFFFF');
 -- Success with end LSNs.
-- 
2.50.1 (Apple Git-155)

