The way I started the title might be confusing, "I corrupted my table", so everyone starts with "Crap !! why did you do that !!, ...", so just to justify it.......
I see many customers coming for recovering the corrupted tables without any backup. In such cases, hard to recover the tables completely and it needs lot of work, however we can recover salvaged data if they dont care about corrupted rows.
Let me corrupt the table first.. :-)
I created a million-row table called "damaged"
postgres=# select count(*) from to_be_damaged ;I've used "hexedit" to damage it. Open relfilenode file from OS level using hexedit and try picking a line which is the start of an 8K boundary and typing hex DE AD BE EF across it.
count
---------
1000000
(1 row)
postgres=# select relfilenode,relname from pg_class where relname='to_be_damaged';
relfilenode | relname
-------------+---------------
461257 | to_be_damaged
(1 row)
postgres=# select count(*) from to_be_damaged ;
ERROR: invalid page in block 0 of relation base/12896/461257
Now create an identical table "salvaged" to recover salvaged data from "to_be_damaged" table.
postgres=# create table salvaged(t int);Prepared below function which copies the rows which are still salvageable:
CREATE TABLE
create or replace function salvage_damaged()
returns void
language plpgsql
as $$
declare
pageno int;
tupno int;
pos tid;
begin
<<pageloop>>
for pageno in 0..35930 loop -- pg_class.relpages for the damaged table
for tupno in 1..1000 loop
pos = ('(' || pageno || ',' || tupno || ')')::tid;
begin
insert into salvaged select * from damaged where ctid = pos;
exception
when sqlstate 'XX001' then
raise warning 'skipping page %', pageno;
continue pageloop;
when others then
raise warning 'skipping row %', pos;
end;
end loop;
end loop;
end;
$$;
Now run the function to copy salvagable rows:
postgres# select salvage_damaged();
WARNING: skipping page 0
salvage_damaged
-----------------
(1 row)
postgres=# select count(*) from salvaged ;
count
----------
12999815
(1 row)
postgres=# select 13000000-12999815;
?column?
----------
185
(1 row)
I hope it helps someone. Thanks for reading.