简体   繁体   中英

If a table is dropped from pg_class accidentally then how to restore it from backup?

I accidentally dropped a table from pg_class and I have the same table present in a different server inside a schema. How do I restore it?

I have tried this

psql -U {user-name} -d {desintation_db} -f {dumpfilename.sql}`

This is what i'm getting -

ERROR:  type "food_ingredients" already exists`
HINT:  A relation has an associated type of the same name, so you must use a name that doesn't conflict with any existing type.`
ERROR:  relation "food_ingredients" does not exist`
ERROR:  syntax error at or near "19411"`
LINE 1: 19411 10405 2074 45.3333333333 0.17550085492131515 NULL NULL...`
ERROR:  relation "food_ingredients" does not exist`

food_ingredients is the table which I dropped from the pg_class.

That's what you get from messing with system catalogs.

The simple and correct answer is “restore from a backup”, but something tells me that that's not the answer you were looking for.

You could drop the type that belongs to the table, all indexes on the table, all constraints, toast tables and so on, but you'd probably forget to drop something or drop something you shouldn't and end up with a bigger mess than before.
Moreover, the table file would be left behind and it would be hard to identify and delete it.

It would be appealing to try and recreate the pg_class row that you dropped, but you wouldn't be able to create it with the correct oid since you cannot directly insert a certain oid or update that column.

You could dump the whole database cluster with pg_dumpall , create a new cluster with initdb and restore the backup there, but this might fail because of the data inconsistencies.

Really, the best thing is to restore a backup.

I was able to perform a partial restore using the pg_dirtyread extension.

Initial situation was:

relation "messed_table" does not exist`

The following query provided me the values I had dropped:

SELECT * FROM pg_dirtyread('pg_class'::regclass)
as t(relname name, relnamespace oid, reltype oid, reloftype oid, relowner oid, relam oid, relfilenode oid, reltablespace oid, relpages integer, reltuples real, relallvisible integer, reltoastrelid oid, relhasindex boolean, relisshared boolean, relpersistence "char", relkind "char", relnatts smallint, relchecks smallint, relhasoids boolean, relhaspkey boolean, relhasrules boolean, relhastriggers boolean, relhassubclass boolean, relrowsecurity boolean, relforcerowsecurity boolean, relispopulated boolean, relreplident "char", relispartition boolean, relfrozenxid xid, relminmxid xid, relacl aclitem[], reloptions text[], relpartbound pg_node_tree)
WHERE relname = 'messed_table';

I used the result for performing an INSERT:

INSERT INTO pg_class
(relname,relnamespace,reltype,reloftype,relowner,relam,relfilenode,reltablespace,relpages,reltuples,relallvisible,reltoastrelid,relhasindex,relisshared,relpersistence,relkind,relnatts,relchecks,relhasoids,relhaspkey,relhasrules,relhastriggers,relhassubclass,relrowsecurity,relforcerowsecurity,relispopulated,relreplident,relispartition,relfrozenxid,relminmxid,relacl,reloptions,relpartbound)
VALUES('messed_table',16447,17863,0,10,0,17861,0,0,0,0,0,false,false,'p','r',78,0,false,false,false,false,false,false,false,true,'d',false,1129231::text::xid,1::text::xid,null,null,null);

At this stage executing a SELECT * from messed_table returned

catalog is missing 78 attribute(s) for relid 26130

So I created a new table messed_table_copy having the same structure of the messed table.

I exported to a file the pg_attribute content for the messed_table_copy table using this query:

Copy (SELECT * FROM pg_attribute WHERE attrelid = (SELECT oid from pg_class WHERE relname LIKE 'messed_table_copy') and attnum > 0) To '/tmp/recover.csv' With CSV DELIMITER ',' HEADER;

I changed the attrelid value to the relid value pointed out in the error message and I imported the data from the file again:

COPY pg_attribute(attrelid,attname,atttypid,attstattarget,attlen,attnum,attndims,attcacheoff,atttypmod,attbyval,attstorage,attalign,attnotnull,atthasdef,attidentity,attisdropped,attislocal,attinhcount,attcollation,attacl,attoptions,attfdwoptions) FROM '/tmp/recover.csv' DELIMITER ',' CSV HEADER;

At this stage SELECT count(*) FROM messed_table worked but a SELECT * FROM messed_table crashed the database with the following error:

server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.
The connection to the server was lost. Attempting reset: Failed.

Performing some queries specifying only a subset of all the available columns I noticed that only selecting certain columns a crash happened. I had been able to recover about 90% of the data, losing the content of some columns. Good luck and remember to never play with the pg_class table again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM