1 # SPDX-License-Identifier: GPL-3.0-or-later
3 # This file is part of Nominatim. (https://nominatim.org)
5 # Copyright (C) 2024 by the Nominatim developer community.
6 # For a full list of authors see the git log.
8 Helper functions for handling DB accesses.
10 from typing import IO, Optional, Union
14 from pathlib import Path
16 from .connection import get_pg_env
17 from ..errors import UsageError
19 LOG = logging.getLogger()
22 def _pipe_to_proc(proc: 'subprocess.Popen[bytes]',
23 fdesc: Union[IO[bytes], gzip.GzipFile]) -> int:
24 assert proc.stdin is not None
25 chunk = fdesc.read(2048)
26 while chunk and proc.poll() is None:
28 proc.stdin.write(chunk)
29 except BrokenPipeError as exc:
30 raise UsageError("Failed to execute SQL file.") from exc
31 chunk = fdesc.read(2048)
36 def execute_file(dsn: str, fname: Path,
37 ignore_errors: bool = False,
38 pre_code: Optional[str] = None,
39 post_code: Optional[str] = None) -> None:
40 """ Read an SQL file and run its contents against the given database
41 using psql. Use `pre_code` and `post_code` to run extra commands
42 before or after executing the file. The commands are run within the
43 same session, so they may be used to wrap the file execution in a
48 cmd.extend(('-v', 'ON_ERROR_STOP=1'))
49 if not LOG.isEnabledFor(logging.INFO):
52 with subprocess.Popen(cmd, env=get_pg_env(dsn), stdin=subprocess.PIPE) as proc:
53 assert proc.stdin is not None
55 if not LOG.isEnabledFor(logging.INFO):
56 proc.stdin.write('set client_min_messages to WARNING;'.encode('utf-8'))
59 proc.stdin.write((pre_code + ';').encode('utf-8'))
61 if fname.suffix == '.gz':
62 with gzip.open(str(fname), 'rb') as fdesc:
63 remain = _pipe_to_proc(proc, fdesc)
65 with fname.open('rb') as fdesc:
66 remain = _pipe_to_proc(proc, fdesc)
68 if remain == 0 and post_code:
69 proc.stdin.write((';' + post_code).encode('utf-8'))
74 if ret != 0 or remain > 0:
75 raise UsageError("Failed to execute SQL file.")