-
Notifications
You must be signed in to change notification settings - Fork 59
/
sqlite.py
51 lines (39 loc) 路 1.71 KB
/
sqlite.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from .common import assert_subpackage; assert_subpackage(__name__)
from pathlib import Path
import shutil
import sqlite3
from tempfile import TemporaryDirectory
from .common import PathIsh
def sqlite_connect_immutable(db: PathIsh) -> sqlite3.Connection:
# https://www.sqlite.org/draft/uri.html#uriimmutable
return sqlite3.connect(f'file:{db}?immutable=1', uri=True)
def test_sqlite_connect_immutable(tmp_path: Path) -> None:
db = str(tmp_path / 'db.sqlite')
with sqlite3.connect(db) as conn:
conn.execute('CREATE TABLE testtable (col)')
import pytest # type: ignore
with pytest.raises(sqlite3.OperationalError, match='readonly database'):
with sqlite_connect_immutable(db) as conn:
conn.execute('DROP TABLE testtable')
# succeeds without immutable
with sqlite3.connect(db) as conn:
conn.execute('DROP TABLE testtable')
# TODO come up with a better name?
# NOTE: this is tested by tests/sqlite.py::test_sqlite_read_with_wal
def sqlite_copy_and_open(db: PathIsh) -> sqlite3.Connection:
"""
'Snapshots' database and opens by making a deep copy of it including journal/WAL files
"""
dp = Path(db)
# TODO make atomic/check mtimes or something
dest = sqlite3.connect(':memory:')
with TemporaryDirectory() as td:
tdir = Path(td)
# shm should be recreated from scratch -- safer not to copy perhaps
tocopy = [dp] + [p for p in dp.parent.glob(dp.name + '-*') if not p.name.endswith('-shm')]
for p in tocopy:
shutil.copy(p, tdir / p.name)
with sqlite3.connect(str(tdir / dp.name)) as conn:
from .compat import sqlite_backup
sqlite_backup(source=conn, dest=dest)
return dest