2 # Copyright (c) 2022-2025, PostgreSQL Global Development Group
5 use warnings FATAL
=> 'all';
7 use PostgreSQL
::Test
::Cluster
;
8 use PostgreSQL
::Test
::RecursiveCopy
;
9 use PostgreSQL
::Test
::Utils
;
12 my ($blocksize, $walfile_name);
14 # Function to extract the LSN from the given block structure
18 my $blocksize = shift;
21 open my $fh, '<', $path or die "couldn't open file: $path\n";
22 die "could not read block\n"
23 if $blocksize != read($fh, $block, $blocksize);
24 my ($lsn_hi, $lsn_lo) = unpack('LL', $block);
26 $lsn_hi = sprintf('%08X', $lsn_hi);
27 $lsn_lo = sprintf('%08X', $lsn_lo);
29 return ($lsn_hi, $lsn_lo);
32 my $node = PostgreSQL
::Test
::Cluster
->new('main');
41 # Generate data/WAL to examine that will have full pages in them.
44 "SELECT 'init' FROM pg_create_physical_replication_slot('regress_pg_waldump_slot', true, false);
45 CREATE TABLE test_table AS SELECT generate_series(1,100) a;
46 -- Force FPWs on the next writes.
48 UPDATE test_table SET a = a + 1;
51 ($walfile_name, $blocksize) = split '\|' => $node->safe_psql('postgres',
52 "SELECT pg_walfile_name(pg_switch_wal()), current_setting('block_size')");
54 # Get the relation node, etc for the new table
55 my $relation = $node->safe_psql(
59 CASE WHEN reltablespace = 0 THEN dattablespace ELSE reltablespace END,
61 pg_relation_filenode(pg_class.oid))
62 FROM pg_class, pg_database
63 WHERE relname = 'test_table' AND
64 datname = current_database()}
67 my $walfile = $node->data_dir . '/pg_wal/' . $walfile_name;
68 my $tmp_folder = PostgreSQL::Test::Utils::tempdir;
70 ok(-f $walfile, "Got a WAL file");
76 '--save-fullpage' => "$tmp_folder/raw",
77 '--relation' => $relation,
80 'pg_waldump with --save-fullpage runs');
82 # This regexp will match filenames formatted as:
83 # TLI-LSNh-LSNl.TBLSPCOID.DBOID.NODEOID.dd_fork with the components being:
84 # - Timeline ID in hex format.
85 # - WAL LSN in hex format, as two 8-character numbers.
86 # - Tablespace OID (0 for global).
90 # - Fork this block came from (vm, init, fsm, or main).
92 qr/^[0-9A-F]{8}-([0-9A-F]{8})-([0-9A-F]{8})[.][0-9]+[.][0-9]+[.][0-9]+[.][0-9]+(?:_vm|_init|_fsm|_main)?$/;
96 # Verify filename format matches --save-fullpage.
97 for my $fullpath (glob "$tmp_folder/raw/*")
99 my $file = File::Basename::basename($fullpath);
101 like($file, $file_re, "verify filename format for file $file");
104 my ($hi_lsn_fn, $lo_lsn_fn) = ($file =~ $file_re);
105 my ($hi_lsn_bk, $lo_lsn_bk) = get_block_lsn($fullpath, $blocksize);
107 # The LSN on the block comes before the file's LSN.
108 ok( $hi_lsn_fn . $lo_lsn_fn gt $hi_lsn_bk . $lo_lsn_bk,
109 'LSN stored in the file precedes the one stored in the block');
112 ok($file_count > 0, 'verify that at least one block has been saved');