regress.patch.WIP
application/octet-stream
Filename: regress.patch.WIP
Type: application/octet-stream
Part: 0
Message:
Re: new heapcheck contrib module
diff --git a/contrib/amcheck/t/001_verify_heapam.pl b/contrib/amcheck/t/001_verify_heapam.pl
index e7526c17b8..9d93ad197c 100644
--- a/contrib/amcheck/t/001_verify_heapam.pl
+++ b/contrib/amcheck/t/001_verify_heapam.pl
@@ -4,7 +4,7 @@ use warnings;
use PostgresNode;
use TestLib;
-use Test::More tests => 65;
+use Test::More tests => 55;
my ($node, $result);
@@ -28,19 +28,19 @@ check_all_options_uncorrupted('test', 'plain');
#
fresh_test_table('test');
corrupt_first_page('test');
-detects_corruption(
+detects_heap_corruption(
"verify_heapam('test')",
"plain corrupted table");
-detects_corruption(
+detects_heap_corruption(
"verify_heapam('test', skip := 'all-visible')",
"plain corrupted table skipping all-visible");
-detects_corruption(
+detects_heap_corruption(
"verify_heapam('test', skip := 'all-frozen')",
"plain corrupted table skipping all-frozen");
-detects_corruption(
+detects_heap_corruption(
"verify_heapam('test', check_toast := false)",
"plain corrupted table skipping toast");
-detects_corruption(
+detects_heap_corruption(
"verify_heapam('test', startblock := 0, endblock := 0)",
"plain corrupted table checking only block zero");
@@ -50,71 +50,13 @@ detects_corruption(
fresh_test_table('test');
$node->safe_psql('postgres', q(VACUUM FREEZE test));
corrupt_first_page('test');
-detects_corruption(
+detects_heap_corruption(
"verify_heapam('test')",
"all-frozen corrupted table");
detects_no_corruption(
"verify_heapam('test', skip := 'all-frozen')",
"all-frozen corrupted table skipping all-frozen");
-#
-# Check a corrupt table with corrupt page header
-#
-fresh_test_table('test');
-corrupt_first_page_and_header('test');
-detects_corruption(
- "verify_heapam('test')",
- "corrupted test table with bad page header");
-
-#
-# Check an uncorrupted table with corrupt toast page header
-#
-fresh_test_table('test');
-my $toast = get_toast_for('test');
-corrupt_first_page_and_header($toast);
-detects_corruption(
- "verify_heapam('test', check_toast := true)",
- "table with corrupted toast page header checking toast");
-detects_no_corruption(
- "verify_heapam('test', check_toast := false)",
- "table with corrupted toast page header skipping toast");
-detects_corruption(
- "verify_heapam('$toast')",
- "corrupted toast page header");
-
-#
-# Check an uncorrupted table with corrupt toast
-#
-fresh_test_table('test');
-$toast = get_toast_for('test');
-corrupt_first_page($toast);
-detects_corruption(
- "verify_heapam('test', check_toast := true)",
- "table with corrupted toast checking toast");
-detects_no_corruption(
- "verify_heapam('test', check_toast := false)",
- "table with corrupted toast skipping toast");
-detects_corruption(
- "verify_heapam('$toast')",
- "corrupted toast table");
-
-#
-# Check an uncorrupted all-frozen table with corrupt toast
-#
-fresh_test_table('test');
-$node->safe_psql('postgres', q(VACUUM FREEZE test));
-$toast = get_toast_for('test');
-corrupt_first_page($toast);
-detects_corruption(
- "verify_heapam('test', check_toast := true)",
- "all-frozen table with corrupted toast checking toast");
-detects_no_corruption(
- "verify_heapam('test', check_toast := false)",
- "all-frozen table with corrupted toast skipping toast");
-detects_corruption(
- "verify_heapam('$toast')",
- "corrupted toast table of all-frozen table");
-
# Returns the filesystem path for the named relation.
sub relation_filepath
{
@@ -154,46 +96,43 @@ sub fresh_test_table
# Stops the test node, corrupts the first page of the named relation, and
# restarts the node.
-sub corrupt_first_page_internal
+sub corrupt_first_page
{
- my ($relname, $corrupt_header) = @_;
+ my ($relname) = @_;
my $relpath = relation_filepath($relname);
$node->stop;
my $fh;
- open($fh, '+<', $relpath);
+ open($fh, '+<', $relpath)
+ or BAIL_OUT("open failed: $!");;
binmode $fh;
- # If we corrupt the header, postgres won't allow the page into the buffer.
- syswrite($fh, '\xFF\xFF\xFF\xFF', 8) if ($corrupt_header);
-
- # Corrupt at least the line pointers. Exactly what this corrupts will
- # depend on the page, as it may run past the line pointers into the user
- # data. We stop short of writing 2048 bytes (2k), the smallest supported
- # page size, as we don't want to corrupt the next page.
- seek($fh, 32, 0);
- syswrite($fh, '\x77\x77\x77\x77', 500);
- close($fh);
+ # Corrupt the first two line pointers. To be stable across platforms,
+ # we use 0x77777777 and 0xAAAAAAAA for the first two, which are bitwise
+ # reverses of each other.
+ seek($fh, 24, 0)
+ or BAIL_OUT("seek failed: $!");;
+ syswrite($fh, pack("L*", 0x77777777, 0xAAAAAAAA))
+ or BAIL_OUT("syswrite failed: $!");
+ close($fh)
+ or BAIL_OUT("close failed: $!");
$node->start;
}
-sub corrupt_first_page
-{
- corrupt_first_page_internal($_[0], undef);
-}
-
-sub corrupt_first_page_and_header
+sub detects_heap_corruption
{
- corrupt_first_page_internal($_[0], 1);
+ my ($function, $testname) = @_;
+ detects_corruption($function, $testname,
+ qr/line pointer redirection to item at offset \d+ exceeds maximum offset \d+/);
}
sub detects_corruption
{
- my ($function, $testname) = @_;
+ my ($function, $testname, $re) = @_;
my $result = $node->safe_psql('postgres',
- qq(SELECT COUNT(*) > 0 FROM $function));
- is($result, 't', $testname);
+ qq(SELECT * FROM $function));
+ like($result, $re, $testname);
}
sub detects_no_corruption
@@ -201,8 +140,8 @@ sub detects_no_corruption
my ($function, $testname) = @_;
my $result = $node->safe_psql('postgres',
- qq(SELECT COUNT(*) = 0 FROM $function));
- is($result, 't', $testname);
+ qq(SELECT * FROM $function));
+ is($result, '', $testname);
}
# Check various options are stable (don't abort) and do not report corruption