Dev build 2026-06-01 21:24
This commit is contained in:
parent
6df47a8161
commit
40c8525691
@ -756,12 +756,39 @@ def _psql_base_args() -> list[str]:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Session-GUC SET statements a dump may carry that an OLDER server doesn't know.
|
||||||
|
# These are emitted in the pg_dump header and are harmless to skip — they only
|
||||||
|
# affect the restoring session, not the data. (e.g. `transaction_timeout` was
|
||||||
|
# introduced in PostgreSQL 17; restoring such a dump into a <17 server errors on
|
||||||
|
# that line.) We must not let these abort an otherwise valid restore, but any
|
||||||
|
# OTHER error still fails the restore.
|
||||||
|
_BENIGN_RESTORE_ERROR_MARKERS = (
|
||||||
|
"unrecognized configuration parameter",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _real_restore_errors(stderr: str) -> list[str]:
|
||||||
|
errors = []
|
||||||
|
for line in (stderr or "").splitlines():
|
||||||
|
if "ERROR:" not in line:
|
||||||
|
continue
|
||||||
|
if any(marker in line for marker in _BENIGN_RESTORE_ERROR_MARKERS):
|
||||||
|
continue
|
||||||
|
errors.append(line.strip())
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
def _run_pg_restore(dump_bytes: bytes) -> None:
|
def _run_pg_restore(dump_bytes: bytes) -> None:
|
||||||
"""Restore a full PostgreSQL dump.
|
"""Restore a full PostgreSQL dump.
|
||||||
|
|
||||||
Resets the public schema first so any plain pg_dump (with or without
|
Resets the public schema first so any plain pg_dump (with or without
|
||||||
--clean) restores cleanly into an empty schema. This is destructive: it
|
--clean) restores cleanly into an empty schema. This is destructive: it
|
||||||
drops and recreates the entire public schema before applying the dump.
|
drops and recreates the entire public schema before applying the dump.
|
||||||
|
|
||||||
|
The dump is applied WITHOUT ON_ERROR_STOP so that benign header SETs the
|
||||||
|
target server doesn't recognize (e.g. a newer pg_dump emitting
|
||||||
|
`transaction_timeout` against an older server) don't abort the restore.
|
||||||
|
stderr is then inspected: any non-benign `ERROR:` line fails the restore.
|
||||||
"""
|
"""
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["PGPASSWORD"] = os.environ.get("POSTGRES_PASSWORD", "")
|
env["PGPASSWORD"] = os.environ.get("POSTGRES_PASSWORD", "")
|
||||||
@ -782,13 +809,14 @@ def _run_pg_restore(dump_bytes: bytes) -> None:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
proc = subprocess.run(
|
proc = subprocess.run(
|
||||||
["psql", *base, "-v", "ON_ERROR_STOP=1", "-f", str(tmp_path)],
|
["psql", *base, "-f", str(tmp_path)],
|
||||||
env=env,
|
env=env,
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
)
|
)
|
||||||
if proc.returncode != 0:
|
real_errors = _real_restore_errors(proc.stderr)
|
||||||
raise RuntimeError(f"psql restore failed: {(proc.stderr or '').strip()[:500] or 'unknown error'}")
|
if real_errors:
|
||||||
|
raise RuntimeError("psql restore failed: " + " | ".join(real_errors)[:500])
|
||||||
finally:
|
finally:
|
||||||
tmp_path.unlink(missing_ok=True)
|
tmp_path.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from changelog import CHANGELOG
|
from changelog import CHANGELOG
|
||||||
|
|
||||||
BUILD = 1
|
BUILD = 2
|
||||||
|
|
||||||
|
|
||||||
def _release_version() -> str:
|
def _release_version() -> str:
|
||||||
|
|||||||
@ -1,5 +1,11 @@
|
|||||||
# Develop Changelog
|
# Develop Changelog
|
||||||
|
|
||||||
|
## 2026-06-01 — Full Database Restore: tolerate PostgreSQL version mismatch
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Full Database Restore failed with `ERROR: unrecognized configuration parameter "transaction_timeout"` when the dump was produced by a newer `pg_dump` (PostgreSQL 17+, which emits `SET transaction_timeout = 0;` in the header) but restored into an older server (<17) that doesn't know that session parameter. The restore ran with `ON_ERROR_STOP=1` and aborted on that harmless header line.
|
||||||
|
- `routers/backup.py` (`_run_pg_restore`): the dump is now applied without `ON_ERROR_STOP`; stderr is inspected afterwards via `_real_restore_errors`, which ignores benign "unrecognized configuration parameter" errors but still fails the restore on any other `ERROR:` line. The schema-reset step keeps `ON_ERROR_STOP=1` (it is our own controlled SQL).
|
||||||
|
|
||||||
## 2026-06-01 — Backup/Restore: database-stored books are now restorable
|
## 2026-06-01 — Backup/Restore: database-stored books are now restorable
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user