From 084d71f81143f0462caf03569722b5f0b2a147e6 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Mon, 30 Mar 2026 18:20:09 +1300
Subject: [PATCH] Add a pg_waldump test with GNU tar PAX format.

XXX Update this to test for a new improved error message!

XXX Should this test run for all the scenarios?  Doesn't seem like
compression is relevant to this problem so I just added it as a
standalone test...

XXX No doubt the perl isn't the greatest...
---
 src/bin/pg_waldump/t/001_basic.pl | 73 +++++++++++++++++++++++++++++--
 1 file changed, 69 insertions(+), 4 deletions(-)

diff --git a/src/bin/pg_waldump/t/001_basic.pl b/src/bin/pg_waldump/t/001_basic.pl
index ce1f6aa30c0..7f8a319c85d 100644
--- a/src/bin/pg_waldump/t/001_basic.pl
+++ b/src/bin/pg_waldump/t/001_basic.pl
@@ -6,6 +6,7 @@ use warnings FATAL => 'all';
 use Cwd;
 use File::Copy;
 use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::RecursiveCopy;
 use PostgreSQL::Test::Utils;
 use Test::More;
 use List::Util qw(shuffle);
@@ -212,9 +213,13 @@ $node->safe_psql('postgres',
 	qq{SELECT pg_logical_emit_message(true, 'test 026', repeat('xyzxz', 123456))}
 );
 
-my ($end_lsn, $end_walfile) = split /\|/,
+my ($end_lsn, $end_walfile, $wal_segsize) = split /\|/,
   $node->safe_psql('postgres',
-	q{SELECT pg_current_wal_insert_lsn(), pg_walfile_name(pg_current_wal_insert_lsn())}
+	q{SELECT pg_current_wal_insert_lsn(),
+			 pg_walfile_name(pg_current_wal_insert_lsn()),
+			 setting
+        FROM pg_settings
+       WHERE name = 'wal_segment_size'}
   );
 
 my $default_ts_oid = $node->safe_psql('postgres',
@@ -339,7 +344,7 @@ sub test_pg_waldump
 # Create a tar archive, shuffle the file order
 sub generate_archive
 {
-	my ($archive, $directory, $compression_flags) = @_;
+	my ($archive, $directory, $compression_flags, @extra_flags) = @_;
 
 	my @files;
 	opendir my $dh, $directory or die "opendir: $!";
@@ -350,12 +355,17 @@ sub generate_archive
 	}
 	closedir $dh;
 
+	if (!@extra_flags)
+	{
+		@extra_flags = @tar_c_flags;
+	}
+
 	@files = shuffle @files;
 
 	# move into the WAL directory before archiving files
 	my $cwd = getcwd;
 	chdir($directory) || die "chdir: $!";
-	command_ok([$tar, @tar_c_flags, $compression_flags, $archive, @files]);
+	command_ok([$tar, @extra_flags, $compression_flags, $archive, @files]);
 	chdir($cwd) || die "chdir: $!";
 }
 
@@ -477,4 +487,59 @@ for my $scenario (@scenarios)
 	}
 }
 
+SKIP:
+	skip "tar command is not available", 1
+		if !defined $tar;
+
+	my @sparse_flags;
+
+	# Tell $TAR to use GNU tar's PAX sparse file archive format, so we can test
+	# our handling of that.
+
+	# GNU tar
+	@sparse_flags = ("--sparse", "--format=pax")
+		if system("$tar --sparse --format=pax -c " .
+				  $node->data_dir . "/pg_wal/* /dev/null > /dev/null") == 0;
+	# BSD tar (this is the default, but we still need to detect BSD tar)
+	@sparse_flags = ("--read-sparse", "--format=pax")
+		if system("$tar --read-sparse --format=pax -c " .
+				  $node->data_dir . "/pg_wal/* /dev/null > /dev/null") == 0;
+
+	skip "tar command doesn't support GNU PAX format for sparse files", 1
+		if !@sparse_flags;
+
+	PostgreSQL::Test::RecursiveCopy::copypath($node->data_dir . '/pg_wal',
+											  $tmp_dir . '/pg_wal_sparse');
+
+	# truncate the unused part of final WAL file
+	my $end_byte = $end_lsn;
+	$end_byte =~ s/\///;
+	$end_byte = hex($end_byte);
+	$end_byte %= $wal_segsize;
+	truncate $tmp_dir . '/pg_wal_sparse/' . $end_walfile, $end_byte;
+
+	# now re-extend it to create a hole
+	truncate $tmp_dir . '/pg_wal_sparse/' . $end_walfile, $wal_segsize;
+
+	# XXX maybe we should detect sparse files with stat (size > blocks * block
+	# size?), and skip the test if truncate failed to make one... that
+	# might happen on eg windows I think?  otherwise we'd have to tolerate
+	# the pg_waldump command succeeding OR failing with a certain message
+
+	generate_archive($tmp_dir . '/pg_wal_sparse.tar',
+					 $tmp_dir . '/pg_wal_sparse',
+					 '-cf',
+					 @sparse_flags);
+
+	# XXX change this to check for new improved error message
+	command_fails_like(
+		[
+			'pg_waldump',
+			'--path' => $tmp_dir . '/pg_wal_sparse.tar',
+			'--start' => $start_lsn,
+			'--end' => $end_lsn,
+		],
+		qr/error: could not find WAL/,
+		'fails with GNU tar PAX-format sparse files');
+
 done_testing();
-- 
2.53.0

