Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 866e24d

Browse files
committed
Extend amcheck to check heap pages.
Mark Dilger, reviewed by Peter Geoghegan, Andres Freund, Álvaro Herrera, Michael Paquier, Amul Sul, and by me. Some last-minute cosmetic revisions by me. Discussion: http://postgr.es/m/12ED3DA8-25F0-4B68-937D-D907CFBF08E7@enterprisedb.com
1 parent f8721bd commit 866e24d

File tree

12 files changed

+2299
-9
lines changed

12 files changed

+2299
-9
lines changed

contrib/amcheck/Makefile

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
MODULE_big = amcheck
44
OBJS = \
55
$(WIN32RES) \
6+
verify_heapam.o \
67
verify_nbtree.o
78

89
EXTENSION = amcheck
9-
DATA = amcheck--1.1--1.2.sql amcheck--1.0--1.1.sql amcheck--1.0.sql
10+
DATA = amcheck--1.2--1.3.sql amcheck--1.1--1.2.sql amcheck--1.0--1.1.sql amcheck--1.0.sql
1011
PGFILEDESC = "amcheck - function for verifying relation integrity"
1112

12-
REGRESS = check check_btree
13+
REGRESS = check check_btree check_heap
14+
15+
TAP_TESTS = 1
1316

1417
ifdef USE_PGXS
1518
PG_CONFIG = pg_config

contrib/amcheck/amcheck--1.2--1.3.sql

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* contrib/amcheck/amcheck--1.2--1.3.sql */
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use "ALTER EXTENSION amcheck UPDATE TO '1.3'" to load this file. \quit
5+
6+
--
7+
-- verify_heapam()
8+
--
9+
CREATE FUNCTION verify_heapam(relation regclass,
10+
on_error_stop boolean default false,
11+
check_toast boolean default false,
12+
skip text default 'none',
13+
startblock bigint default null,
14+
endblock bigint default null,
15+
blkno OUT bigint,
16+
offnum OUT integer,
17+
attnum OUT integer,
18+
msg OUT text)
19+
RETURNS SETOF record
20+
AS 'MODULE_PATHNAME', 'verify_heapam'
21+
LANGUAGE C;
22+
23+
-- Don't want this to be available to public
24+
REVOKE ALL ON FUNCTION verify_heapam(regclass,
25+
boolean,
26+
boolean,
27+
text,
28+
bigint,
29+
bigint)
30+
FROM PUBLIC;

contrib/amcheck/amcheck.control

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# amcheck extension
22
comment = 'functions for verifying relation integrity'
3-
default_version = '1.2'
3+
default_version = '1.3'
44
module_pathname = '$libdir/amcheck'
55
relocatable = true
+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
CREATE TABLE heaptest (a integer, b text);
2+
REVOKE ALL ON heaptest FROM PUBLIC;
3+
-- Check that invalid skip option is rejected
4+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'rope');
5+
ERROR: invalid skip option
6+
HINT: Valid skip options are "all-visible", "all-frozen", and "none".
7+
-- Check specifying invalid block ranges when verifying an empty table
8+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 0, endblock := 0);
9+
blkno | offnum | attnum | msg
10+
-------+--------+--------+-----
11+
(0 rows)
12+
13+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 5, endblock := 8);
14+
blkno | offnum | attnum | msg
15+
-------+--------+--------+-----
16+
(0 rows)
17+
18+
-- Check that valid options are not rejected nor corruption reported
19+
-- for an empty table, and that skip enum-like parameter is case-insensitive
20+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'none');
21+
blkno | offnum | attnum | msg
22+
-------+--------+--------+-----
23+
(0 rows)
24+
25+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-frozen');
26+
blkno | offnum | attnum | msg
27+
-------+--------+--------+-----
28+
(0 rows)
29+
30+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-visible');
31+
blkno | offnum | attnum | msg
32+
-------+--------+--------+-----
33+
(0 rows)
34+
35+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'None');
36+
blkno | offnum | attnum | msg
37+
-------+--------+--------+-----
38+
(0 rows)
39+
40+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'All-Frozen');
41+
blkno | offnum | attnum | msg
42+
-------+--------+--------+-----
43+
(0 rows)
44+
45+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'All-Visible');
46+
blkno | offnum | attnum | msg
47+
-------+--------+--------+-----
48+
(0 rows)
49+
50+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'NONE');
51+
blkno | offnum | attnum | msg
52+
-------+--------+--------+-----
53+
(0 rows)
54+
55+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'ALL-FROZEN');
56+
blkno | offnum | attnum | msg
57+
-------+--------+--------+-----
58+
(0 rows)
59+
60+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'ALL-VISIBLE');
61+
blkno | offnum | attnum | msg
62+
-------+--------+--------+-----
63+
(0 rows)
64+
65+
-- Add some data so subsequent tests are not entirely trivial
66+
INSERT INTO heaptest (a, b)
67+
(SELECT gs, repeat('x', gs)
68+
FROM generate_series(1,50) gs);
69+
-- Check that valid options are not rejected nor corruption reported
70+
-- for a non-empty table
71+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'none');
72+
blkno | offnum | attnum | msg
73+
-------+--------+--------+-----
74+
(0 rows)
75+
76+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-frozen');
77+
blkno | offnum | attnum | msg
78+
-------+--------+--------+-----
79+
(0 rows)
80+
81+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-visible');
82+
blkno | offnum | attnum | msg
83+
-------+--------+--------+-----
84+
(0 rows)
85+
86+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 0, endblock := 0);
87+
blkno | offnum | attnum | msg
88+
-------+--------+--------+-----
89+
(0 rows)
90+
91+
CREATE ROLE regress_heaptest_role;
92+
-- verify permissions are checked (error due to function not callable)
93+
SET ROLE regress_heaptest_role;
94+
SELECT * FROM verify_heapam(relation := 'heaptest');
95+
ERROR: permission denied for function verify_heapam
96+
RESET ROLE;
97+
GRANT EXECUTE ON FUNCTION verify_heapam(regclass, boolean, boolean, text, bigint, bigint) TO regress_heaptest_role;
98+
-- verify permissions are now sufficient
99+
SET ROLE regress_heaptest_role;
100+
SELECT * FROM verify_heapam(relation := 'heaptest');
101+
blkno | offnum | attnum | msg
102+
-------+--------+--------+-----
103+
(0 rows)
104+
105+
RESET ROLE;
106+
-- Check specifying invalid block ranges when verifying a non-empty table.
107+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 0, endblock := 10000);
108+
ERROR: ending block number must be between 0 and 0
109+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 10000, endblock := 11000);
110+
ERROR: starting block number must be between 0 and 0
111+
-- Vacuum freeze to change the xids encountered in subsequent tests
112+
VACUUM FREEZE heaptest;
113+
-- Check that valid options are not rejected nor corruption reported
114+
-- for a non-empty frozen table
115+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'none');
116+
blkno | offnum | attnum | msg
117+
-------+--------+--------+-----
118+
(0 rows)
119+
120+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-frozen');
121+
blkno | offnum | attnum | msg
122+
-------+--------+--------+-----
123+
(0 rows)
124+
125+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-visible');
126+
blkno | offnum | attnum | msg
127+
-------+--------+--------+-----
128+
(0 rows)
129+
130+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 0, endblock := 0);
131+
blkno | offnum | attnum | msg
132+
-------+--------+--------+-----
133+
(0 rows)
134+
135+
-- Check that partitioned tables (the parent ones) which don't have visibility
136+
-- maps are rejected
137+
CREATE TABLE test_partitioned (a int, b text default repeat('x', 5000))
138+
PARTITION BY list (a);
139+
SELECT * FROM verify_heapam('test_partitioned',
140+
startblock := NULL,
141+
endblock := NULL);
142+
ERROR: "test_partitioned" is not a table, materialized view, or TOAST table
143+
-- Check that valid options are not rejected nor corruption reported
144+
-- for an empty partition table (the child one)
145+
CREATE TABLE test_partition partition OF test_partitioned FOR VALUES IN (1);
146+
SELECT * FROM verify_heapam('test_partition',
147+
startblock := NULL,
148+
endblock := NULL);
149+
blkno | offnum | attnum | msg
150+
-------+--------+--------+-----
151+
(0 rows)
152+
153+
-- Check that valid options are not rejected nor corruption reported
154+
-- for a non-empty partition table (the child one)
155+
INSERT INTO test_partitioned (a) (SELECT 1 FROM generate_series(1,1000) gs);
156+
SELECT * FROM verify_heapam('test_partition',
157+
startblock := NULL,
158+
endblock := NULL);
159+
blkno | offnum | attnum | msg
160+
-------+--------+--------+-----
161+
(0 rows)
162+
163+
-- Check that indexes are rejected
164+
CREATE INDEX test_index ON test_partition (a);
165+
SELECT * FROM verify_heapam('test_index',
166+
startblock := NULL,
167+
endblock := NULL);
168+
ERROR: "test_index" is not a table, materialized view, or TOAST table
169+
-- Check that views are rejected
170+
CREATE VIEW test_view AS SELECT 1;
171+
SELECT * FROM verify_heapam('test_view',
172+
startblock := NULL,
173+
endblock := NULL);
174+
ERROR: "test_view" is not a table, materialized view, or TOAST table
175+
-- Check that sequences are rejected
176+
CREATE SEQUENCE test_sequence;
177+
SELECT * FROM verify_heapam('test_sequence',
178+
startblock := NULL,
179+
endblock := NULL);
180+
ERROR: "test_sequence" is not a table, materialized view, or TOAST table
181+
-- Check that foreign tables are rejected
182+
CREATE FOREIGN DATA WRAPPER dummy;
183+
CREATE SERVER dummy_server FOREIGN DATA WRAPPER dummy;
184+
CREATE FOREIGN TABLE test_foreign_table () SERVER dummy_server;
185+
SELECT * FROM verify_heapam('test_foreign_table',
186+
startblock := NULL,
187+
endblock := NULL);
188+
ERROR: "test_foreign_table" is not a table, materialized view, or TOAST table
189+
-- cleanup
190+
DROP TABLE heaptest;
191+
DROP TABLE test_partition;
192+
DROP TABLE test_partitioned;
193+
DROP OWNED BY regress_heaptest_role; -- permissions
194+
DROP ROLE regress_heaptest_role;

contrib/amcheck/sql/check_heap.sql

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
CREATE TABLE heaptest (a integer, b text);
2+
REVOKE ALL ON heaptest FROM PUBLIC;
3+
4+
-- Check that invalid skip option is rejected
5+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'rope');
6+
7+
-- Check specifying invalid block ranges when verifying an empty table
8+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 0, endblock := 0);
9+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 5, endblock := 8);
10+
11+
-- Check that valid options are not rejected nor corruption reported
12+
-- for an empty table, and that skip enum-like parameter is case-insensitive
13+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'none');
14+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-frozen');
15+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-visible');
16+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'None');
17+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'All-Frozen');
18+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'All-Visible');
19+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'NONE');
20+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'ALL-FROZEN');
21+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'ALL-VISIBLE');
22+
23+
-- Add some data so subsequent tests are not entirely trivial
24+
INSERT INTO heaptest (a, b)
25+
(SELECT gs, repeat('x', gs)
26+
FROM generate_series(1,50) gs);
27+
28+
-- Check that valid options are not rejected nor corruption reported
29+
-- for a non-empty table
30+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'none');
31+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-frozen');
32+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-visible');
33+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 0, endblock := 0);
34+
35+
CREATE ROLE regress_heaptest_role;
36+
37+
-- verify permissions are checked (error due to function not callable)
38+
SET ROLE regress_heaptest_role;
39+
SELECT * FROM verify_heapam(relation := 'heaptest');
40+
RESET ROLE;
41+
42+
GRANT EXECUTE ON FUNCTION verify_heapam(regclass, boolean, boolean, text, bigint, bigint) TO regress_heaptest_role;
43+
44+
-- verify permissions are now sufficient
45+
SET ROLE regress_heaptest_role;
46+
SELECT * FROM verify_heapam(relation := 'heaptest');
47+
RESET ROLE;
48+
49+
-- Check specifying invalid block ranges when verifying a non-empty table.
50+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 0, endblock := 10000);
51+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 10000, endblock := 11000);
52+
53+
-- Vacuum freeze to change the xids encountered in subsequent tests
54+
VACUUM FREEZE heaptest;
55+
56+
-- Check that valid options are not rejected nor corruption reported
57+
-- for a non-empty frozen table
58+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'none');
59+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-frozen');
60+
SELECT * FROM verify_heapam(relation := 'heaptest', skip := 'all-visible');
61+
SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 0, endblock := 0);
62+
63+
-- Check that partitioned tables (the parent ones) which don't have visibility
64+
-- maps are rejected
65+
CREATE TABLE test_partitioned (a int, b text default repeat('x', 5000))
66+
PARTITION BY list (a);
67+
SELECT * FROM verify_heapam('test_partitioned',
68+
startblock := NULL,
69+
endblock := NULL);
70+
71+
-- Check that valid options are not rejected nor corruption reported
72+
-- for an empty partition table (the child one)
73+
CREATE TABLE test_partition partition OF test_partitioned FOR VALUES IN (1);
74+
SELECT * FROM verify_heapam('test_partition',
75+
startblock := NULL,
76+
endblock := NULL);
77+
78+
-- Check that valid options are not rejected nor corruption reported
79+
-- for a non-empty partition table (the child one)
80+
INSERT INTO test_partitioned (a) (SELECT 1 FROM generate_series(1,1000) gs);
81+
SELECT * FROM verify_heapam('test_partition',
82+
startblock := NULL,
83+
endblock := NULL);
84+
85+
-- Check that indexes are rejected
86+
CREATE INDEX test_index ON test_partition (a);
87+
SELECT * FROM verify_heapam('test_index',
88+
startblock := NULL,
89+
endblock := NULL);
90+
91+
-- Check that views are rejected
92+
CREATE VIEW test_view AS SELECT 1;
93+
SELECT * FROM verify_heapam('test_view',
94+
startblock := NULL,
95+
endblock := NULL);
96+
97+
-- Check that sequences are rejected
98+
CREATE SEQUENCE test_sequence;
99+
SELECT * FROM verify_heapam('test_sequence',
100+
startblock := NULL,
101+
endblock := NULL);
102+
103+
-- Check that foreign tables are rejected
104+
CREATE FOREIGN DATA WRAPPER dummy;
105+
CREATE SERVER dummy_server FOREIGN DATA WRAPPER dummy;
106+
CREATE FOREIGN TABLE test_foreign_table () SERVER dummy_server;
107+
SELECT * FROM verify_heapam('test_foreign_table',
108+
startblock := NULL,
109+
endblock := NULL);
110+
111+
-- cleanup
112+
DROP TABLE heaptest;
113+
DROP TABLE test_partition;
114+
DROP TABLE test_partitioned;
115+
DROP OWNED BY regress_heaptest_role; -- permissions
116+
DROP ROLE regress_heaptest_role;

0 commit comments

Comments
 (0)