Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Don't forget to remove deprecated code on each major release!
- Fix SQLite `index`/`trigger`/`view` `<NAME> already exists` errors.
- Fixed `pg_dump` error when backing up PostgreSQL databases with row-level security policies enabled.
- Fix PostgreSQL restore errors with identity columns by automatically enabling `--if-exists` when using `--clean` in `PgDumpBinaryConnector`.
- Fix PostgreSQL permission errors when restoring with non-superuser accounts by automatically adding `--no-owner` flag to `pg_restore` in `PgDumpBinaryConnector`.

### Security

Expand Down
4 changes: 4 additions & 0 deletions dbbackup/db/postgresql.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class PgDumpBinaryConnector(PgDumpConnector):
single_transaction = True
drop = True
if_exists = False
no_owner = True
enable_row_security = False
pg_options = None

Expand Down Expand Up @@ -177,6 +178,9 @@ def _restore_dump(self, dump: str):
if self.if_exists or self.drop:
cmd.extend(["--if-exists"])

if self.no_owner:
cmd.extend(["--no-owner"])

if self.restore_suffix:
cmd.extend(self.restore_suffix if isinstance(self.restore_suffix, list) else [self.restore_suffix])

Expand Down
3 changes: 3 additions & 0 deletions docs/src/databases.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ All PostgreSQL connectors have the following settings:
| SINGLE_TRANSACTION | Wrap restore in a single transaction so errors cause full rollback (`--single-transaction` for `psql` / `pg_restore`). | `True` |
| DROP | Include / execute drop statements when restoring (`--clean` with `pg_dump` / `pg_restore`). In binary mode drops happen during restore. | `True` |
| IF_EXISTS | Add `IF EXISTS` to destructive statements in clean mode. Automatically enabled when `DROP=True` to prevent identity column errors. | `False` |
| NO_OWNER | Skip restoration of object ownership (`--no-owner` with `pg_restore`). Prevents permission errors when restoring with non-superuser accounts. Binary mode only. | `True` |
| ENABLE_ROW_SECURITY | Enable row-level security for dumping data (`--enable-row-security` with `pg_dump`). Required for databases with row-level security policies. | `False` |

Example configuration for databases with row-level security:
Expand All @@ -138,6 +139,8 @@ The `dbbackup.db.postgresql.PgDumpBinaryConnector` is similar to PgDumpConnector

This allows for faster and parallel-capable restores. It may still invoke `psql` for administrative tasks.

**Permission Handling**: By default, this connector uses `NO_OWNER=True` to prevent permission errors when restoring with non-superuser database accounts. This adds the `--no-owner` flag to `pg_restore`, allowing any database user to restore backups without needing ownership of system extensions or objects.

### PostGIS

Set in `dbbackup.db.postgresql.PgDumpGisConnector`, it does the same as
Expand Down
13 changes: 13 additions & 0 deletions tests/test_connectors/test_postgresql.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,19 @@ def test_restore_suffix(self, mock_run_command):
cmd_args = mock_run_command.call_args[0][0]
self.assertTrue(cmd_args.endswith(" foo"))

def test_no_owner_default_behavior(self, mock_run_command):
"""Test that --no-owner is added by default to prevent permission issues."""
dump = self.connector.create_dump()
self.connector.restore_dump(dump)
cmd_args = mock_run_command.call_args[0][0]
self.assertIn(" --no-owner", cmd_args)

# Test that no_owner can be disabled
self.connector.no_owner = False
self.connector.restore_dump(dump)
cmd_args = mock_run_command.call_args[0][0]
self.assertNotIn(" --no-owner", cmd_args)

@patch(
"dbbackup.db.postgresql.PgDumpBinaryConnector.run_command",
return_value=(BytesIO(), BytesIO()),
Expand Down
Loading