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()
21 def _pipe_to_proc(proc: 'subprocess.Popen[bytes]',
22 fdesc: Union[IO[bytes], gzip.GzipFile]) -> int:
23 assert proc.stdin is not None
24 chunk = fdesc.read(2048)
25 while chunk and proc.poll() is None:
27 proc.stdin.write(chunk)
28 except BrokenPipeError as exc:
29 raise UsageError("Failed to execute SQL file.") from exc
30 chunk = fdesc.read(2048)
34 def execute_file(dsn: str, fname: Path,
35 ignore_errors: bool = False,
36 pre_code: Optional[str] = None,
37 post_code: Optional[str] = None) -> None:
38 """ Read an SQL file and run its contents against the given database
39 using psql. Use `pre_code` and `post_code` to run extra commands
40 before or after executing the file. The commands are run within the
41 same session, so they may be used to wrap the file execution in a
46 cmd.extend(('-v', 'ON_ERROR_STOP=1'))
47 if not LOG.isEnabledFor(logging.INFO):
50 with subprocess.Popen(cmd, env=get_pg_env(dsn), stdin=subprocess.PIPE) as proc:
51 assert proc.stdin is not None
53 if not LOG.isEnabledFor(logging.INFO):
54 proc.stdin.write('set client_min_messages to WARNING;'.encode('utf-8'))
57 proc.stdin.write((pre_code + ';').encode('utf-8'))
59 if fname.suffix == '.gz':
60 with gzip.open(str(fname), 'rb') as fdesc:
61 remain = _pipe_to_proc(proc, fdesc)
63 with fname.open('rb') as fdesc:
64 remain = _pipe_to_proc(proc, fdesc)
66 if remain == 0 and post_code:
67 proc.stdin.write((';' + post_code).encode('utf-8'))
72 if ret != 0 or remain > 0:
73 raise UsageError("Failed to execute SQL file.")