4
4
use PostgresNode;
5
5
use TestLib;
6
6
7
- use Test::More tests => 65 ;
7
+ use Test::More tests => 55 ;
8
8
9
9
my ($node , $result );
10
10
28
28
#
29
29
fresh_test_table(' test' );
30
30
corrupt_first_page(' test' );
31
- detects_corruption(
32
- " verify_heapam('test')" ,
33
- " plain corrupted table" );
34
- detects_corruption(
31
+ detects_heap_corruption(" verify_heapam('test')" , " plain corrupted table" );
32
+ detects_heap_corruption(
35
33
" verify_heapam('test', skip := 'all-visible')" ,
36
34
" plain corrupted table skipping all-visible" );
37
- detects_corruption (
35
+ detects_heap_corruption (
38
36
" verify_heapam('test', skip := 'all-frozen')" ,
39
37
" plain corrupted table skipping all-frozen" );
40
- detects_corruption (
38
+ detects_heap_corruption (
41
39
" verify_heapam('test', check_toast := false)" ,
42
40
" plain corrupted table skipping toast" );
43
- detects_corruption (
41
+ detects_heap_corruption (
44
42
" verify_heapam('test', startblock := 0, endblock := 0)" ,
45
43
" plain corrupted table checking only block zero" );
46
44
50
48
fresh_test_table(' test' );
51
49
$node -> safe_psql(' postgres' , q( VACUUM FREEZE test) );
52
50
corrupt_first_page(' test' );
53
- detects_corruption(
54
- " verify_heapam('test')" ,
51
+ detects_heap_corruption(" verify_heapam('test')" ,
55
52
" all-frozen corrupted table" );
56
53
detects_no_corruption(
57
54
" verify_heapam('test', skip := 'all-frozen')" ,
58
55
" all-frozen corrupted table skipping all-frozen" );
59
56
60
- #
61
- # Check a corrupt table with corrupt page header
62
- #
63
- fresh_test_table(' test' );
64
- corrupt_first_page_and_header(' test' );
65
- detects_corruption(
66
- " verify_heapam('test')" ,
67
- " corrupted test table with bad page header" );
68
-
69
- #
70
- # Check an uncorrupted table with corrupt toast page header
71
- #
72
- fresh_test_table(' test' );
73
- my $toast = get_toast_for(' test' );
74
- corrupt_first_page_and_header($toast );
75
- detects_corruption(
76
- " verify_heapam('test', check_toast := true)" ,
77
- " table with corrupted toast page header checking toast" );
78
- detects_no_corruption(
79
- " verify_heapam('test', check_toast := false)" ,
80
- " table with corrupted toast page header skipping toast" );
81
- detects_corruption(
82
- " verify_heapam('$toast ')" ,
83
- " corrupted toast page header" );
84
-
85
- #
86
- # Check an uncorrupted table with corrupt toast
87
- #
88
- fresh_test_table(' test' );
89
- $toast = get_toast_for(' test' );
90
- corrupt_first_page($toast );
91
- detects_corruption(
92
- " verify_heapam('test', check_toast := true)" ,
93
- " table with corrupted toast checking toast" );
94
- detects_no_corruption(
95
- " verify_heapam('test', check_toast := false)" ,
96
- " table with corrupted toast skipping toast" );
97
- detects_corruption(
98
- " verify_heapam('$toast ')" ,
99
- " corrupted toast table" );
100
-
101
- #
102
- # Check an uncorrupted all-frozen table with corrupt toast
103
- #
104
- fresh_test_table(' test' );
105
- $node -> safe_psql(' postgres' , q( VACUUM FREEZE test) );
106
- $toast = get_toast_for(' test' );
107
- corrupt_first_page($toast );
108
- detects_corruption(
109
- " verify_heapam('test', check_toast := true)" ,
110
- " all-frozen table with corrupted toast checking toast" );
111
- detects_no_corruption(
112
- " verify_heapam('test', check_toast := false)" ,
113
- " all-frozen table with corrupted toast skipping toast" );
114
- detects_corruption(
115
- " verify_heapam('$toast ')" ,
116
- " corrupted toast table of all-frozen table" );
117
-
118
57
# Returns the filesystem path for the named relation.
119
58
sub relation_filepath
120
59
{
121
60
my ($relname ) = @_ ;
122
61
123
62
my $pgdata = $node -> data_dir;
124
- my $rel = $node -> safe_psql(' postgres' ,
125
- qq( SELECT pg_relation_filepath('$relname ')) );
63
+ my $rel = $node -> safe_psql(' postgres' ,
64
+ qq( SELECT pg_relation_filepath('$relname ')) );
126
65
die " path not found for relation $relname " unless defined $rel ;
127
66
return " $pgdata /$rel " ;
128
67
}
@@ -131,7 +70,9 @@ sub relation_filepath
131
70
sub get_toast_for
132
71
{
133
72
my ($relname ) = @_ ;
134
- $node -> safe_psql(' postgres' , qq(
73
+
74
+ return $node -> safe_psql(
75
+ ' postgres' , qq(
135
76
SELECT 'pg_toast.' || t.relname
136
77
FROM pg_catalog.pg_class c, pg_catalog.pg_class t
137
78
WHERE c.relname = '$relname '
@@ -142,7 +83,9 @@ sub get_toast_for
142
83
sub fresh_test_table
143
84
{
144
85
my ($relname ) = @_ ;
145
- $node -> safe_psql(' postgres' , qq(
86
+
87
+ return $node -> safe_psql(
88
+ ' postgres' , qq(
146
89
DROP TABLE IF EXISTS $relname CASCADE;
147
90
CREATE TABLE $relname (a integer, b text);
148
91
ALTER TABLE $relname SET (autovacuum_enabled=false);
@@ -154,55 +97,54 @@ sub fresh_test_table
154
97
155
98
# Stops the test node, corrupts the first page of the named relation, and
156
99
# restarts the node.
157
- sub corrupt_first_page_internal
100
+ sub corrupt_first_page
158
101
{
159
- my ($relname , $corrupt_header ) = @_ ;
102
+ my ($relname ) = @_ ;
160
103
my $relpath = relation_filepath($relname );
161
104
162
105
$node -> stop;
106
+
163
107
my $fh ;
164
- open ($fh , ' +<' , $relpath );
108
+ open ($fh , ' +<' , $relpath )
109
+ or BAIL_OUT(" open failed: $! " );
165
110
binmode $fh ;
166
111
167
- # If we corrupt the header, postgres won't allow the page into the buffer.
168
- syswrite ($fh , ' \xFF\xFF\xFF\xFF' , 8) if ($corrupt_header );
112
+ # Corrupt two line pointers. To be stable across platforms, we use
113
+ # 0x55555555 and 0xAAAAAAAA for the two, which are bitwise reverses of each
114
+ # other.
115
+ seek ($fh , 32, 0)
116
+ or BAIL_OUT(" seek failed: $! " );
117
+ syswrite ($fh , pack (" L*" , 0x55555555, 0xAAAAAAAA))
118
+ or BAIL_OUT(" syswrite failed: $! " );
119
+ close ($fh )
120
+ or BAIL_OUT(" close failed: $! " );
169
121
170
- # Corrupt at least the line pointers. Exactly what this corrupts will
171
- # depend on the page, as it may run past the line pointers into the user
172
- # data. We stop short of writing 2048 bytes (2k), the smallest supported
173
- # page size, as we don't want to corrupt the next page.
174
- seek ($fh , 32, 0);
175
- syswrite ($fh , ' \x77\x77\x77\x77' , 500);
176
- close ($fh );
177
122
$node -> start;
178
123
}
179
124
180
- sub corrupt_first_page
125
+ sub detects_heap_corruption
181
126
{
182
- corrupt_first_page_internal($_ [0], undef );
183
- }
127
+ my ($function , $testname ) = @_ ;
184
128
185
- sub corrupt_first_page_and_header
186
- {
187
- corrupt_first_page_internal( $_ [0], 1 );
129
+ detects_corruption( $function , $testname ,
130
+ qr / line pointer redirection to item at offset \d + exceeds maximum offset \d + /
131
+ );
188
132
}
189
133
190
134
sub detects_corruption
191
135
{
192
- my ($function , $testname ) = @_ ;
136
+ my ($function , $testname , $re ) = @_ ;
193
137
194
- my $result = $node -> safe_psql(' postgres' ,
195
- qq( SELECT COUNT(*) > 0 FROM $function ) );
196
- is($result , ' t' , $testname );
138
+ my $result = $node -> safe_psql(' postgres' , qq( SELECT * FROM $function ) );
139
+ like($result , $re , $testname );
197
140
}
198
141
199
142
sub detects_no_corruption
200
143
{
201
144
my ($function , $testname ) = @_ ;
202
145
203
- my $result = $node -> safe_psql(' postgres' ,
204
- qq( SELECT COUNT(*) = 0 FROM $function ) );
205
- is($result , ' t' , $testname );
146
+ my $result = $node -> safe_psql(' postgres' , qq( SELECT * FROM $function ) );
147
+ is($result , ' ' , $testname );
206
148
}
207
149
208
150
# Check various options are stable (don't abort) and do not report corruption
@@ -215,6 +157,7 @@ sub detects_no_corruption
215
157
sub check_all_options_uncorrupted
216
158
{
217
159
my ($relname , $prefix ) = @_ ;
160
+
218
161
for my $stop (qw( true false) )
219
162
{
220
163
for my $check_toast (qw( true false) )
@@ -225,11 +168,12 @@ sub check_all_options_uncorrupted
225
168
{
226
169
for my $endblock (qw( NULL 0) )
227
170
{
228
- my $opts = " on_error_stop := $stop , " .
229
- " check_toast := $check_toast , " .
230
- " skip := $skip , " .
231
- " startblock := $startblock , " .
232
- " endblock := $endblock " ;
171
+ my $opts =
172
+ " on_error_stop := $stop , "
173
+ . " check_toast := $check_toast , "
174
+ . " skip := $skip , "
175
+ . " startblock := $startblock , "
176
+ . " endblock := $endblock " ;
233
177
234
178
detects_no_corruption(
235
179
" verify_heapam('$relname ', $opts )" ,
0 commit comments