The Odyssey of a PostgreSQL restore

4 min. read Published: Updated at:

Maybe I’m too naive, but I thought that clicking “Backup” and then clicking “Restore” in Tableplus would be enough to move the content of a production database to my local dev environment. The schema is exactly the same, just the data is different and I wanted to have some production data locally to play and test with. However, I’ve spent almost an hour trying to copy the database data. This is the odyssey of restoring a PostgreSQL database from a backup.

Tableplus, my database management GUI of choice, is a powerful tool and I love it. It comes with backup and restore functionality for all major database systems. When creating the backup of a PostgreSQL database, there is only one option present: --format=custom. According to the PostgreSQL documentation, this means Postgres is exporting the data in a proprietary archive format. You can open the file, but it’s not human-readable.
The dump of the production database with the standard options is done in a couple of seconds.

The dialog to restore a database looks exactly the same and has --single-transation as the default option. However, after trying to restore the dump created a second before, I get the following error:

restore_pg_14.0: error: 
could not execute query: 
ERROR:  relation "health_metrics" already exists

Uh. Okay. I guess that Postgres does not drop the database schema before doing a restore. A quick look into the documentation reveals that the archive format includes everything by default.

Therefore, I tried using the --data-only option. According to the docs, it only dumps the data but not the schema. There should be no duplicates, right? After running the backup with said option, I get the next error:

restore_pg_14.0: error: could not execute query: 
ERROR:  permission denied for table health_metrics

Oh. I first thought I had accidentally changed database permissions or passwords, but after reading this Stack Overflow thread it sounded like the user must be the same for dumping and restoring a database? Another approach could be to dump regular SQL and restore it.
I dumped the database content and the size of the dump increased from 12MB to 74MB of raw SQL. While trying to restore the SQL dump, I get another error.

ERROR:  syntax error at or near "1"
LINE 677: 1 active_energy 2022-08-24 06:05:00 0.88700800000000013

Looks like that’s not going to work. I guess the dump is just too large.

I am frustrated. Why can’t this just work? Why does Postgres need to take care of permissions when dumping data and restoring it? I’m running out of patience, so I switch to the postgres superuser that must have access to everything. I don’t like it, but it seems the only way.
Again, I run the restore of the backup I created with the --data-only option:

restore_pg_14.0: error: COPY failed for table "health_metrics": 
ERROR:  duplicate key value violates unique constraint "health_metrics_pkey"
DETAIL:  Key (user_id, name, date)=(1, active_energy, 2022-08-24 06:05:00) already exists.

Okay. Sure. There is data present in the database, and pg_restore just tries to push new data into it. The pg_restore docs list a --clean option which drops all existing data. I get the same error as before. Maybe pg_restore can’t drop the data if it does not know about the tables? Let’s try the --clean option while doing the export.

dump_pg_14.0: error: options -c/--clean and -a/--data-only cannot be used together

One last try. The docs about the archive format state that it contains all the data and “then pg_restore can be used to examine the archive and/or select which parts of the database are to be restored”. Maybe try the archive format and tell pg_restore to clean up before doing the restore? I ran the restore of a regular archive backup with --clean and… FINALLY!
The database restore went through and I have the production data in my local database - after almost 40 minutes and a lot of headache.

TLDR: Export the database into the archive format (--format=custom) and then import it into the other database with the --clean flag. Make sure, that the importing user has sufficient rights, like the postgres user.

However, I still would like to know how to restore a PostgreSQL database dump without having to take care of user permissions…


0 Mentions