diff --git a/Lib/dbm/sqlite3.py b/Lib/dbm/sqlite3.py index b296a1bcd1bbfa..42c04878d2f85c 100644 --- a/Lib/dbm/sqlite3.py +++ b/Lib/dbm/sqlite3.py @@ -60,6 +60,9 @@ def __init__(self, path, /, *, flag, mode): # We use the URI format when opening the database. uri = _normalize_uri(path) uri = f"{uri}?mode={flag}" + if flag == "ro": + # Add immutable=1 to allow read-only SQLite access even if wal/shm missing + uri += "&immutable=1" try: self._cx = sqlite3.connect(uri, autocommit=True, uri=True) @@ -67,11 +70,12 @@ def __init__(self, path, /, *, flag, mode): raise error(str(exc)) # This is an optimization only; it's ok if it fails. - with suppress(sqlite3.OperationalError): - self._cx.execute("PRAGMA journal_mode = wal") + if flag != "ro": + with suppress(sqlite3.OperationalError): + self._cx.execute("PRAGMA journal_mode = OFF") - if flag == "rwc": - self._execute(BUILD_TABLE) + if flag == "rwc": + self._execute(BUILD_TABLE) def _execute(self, *args, **kwargs): if not self._cx: diff --git a/Lib/test/test_dbm_sqlite3.py b/Lib/test/test_dbm_sqlite3.py index 9216da8a63f957..686ce9f1e015b5 100644 --- a/Lib/test/test_dbm_sqlite3.py +++ b/Lib/test/test_dbm_sqlite3.py @@ -1,3 +1,4 @@ +import os import sys import unittest from contextlib import closing @@ -89,6 +90,30 @@ def test_readonly_keys(self): def test_readonly_iter(self): self.assertEqual([k for k in self.db], [b"key1", b"key2"]) +class Immutable(unittest.TestCase): + def setUp(self): + self.filename = os_helper.TESTFN + + db = dbm_sqlite3.open(self.filename, "c") + db[b"key"] = b"value" + db.close() + + self.db = dbm_sqlite3.open(self.filename, "r") + + def tearDown(self): + self.db.close() + for suffix in "", "-wal", "-shm": + os_helper.unlink(self.filename + suffix) + + def test_readonly_open_without_wal_shm(self): + wal_path = self.filename + "-wal" + shm_path = self.filename + "-shm" + + self.assertFalse(os.path.exists(wal_path)) + self.assertFalse(os.path.exists(shm_path)) + + self.assertEqual(self.db[b"key"], b"value") + class ReadWrite(_SQLiteDbmTests): diff --git a/Misc/NEWS.d/next/Library/2025-06-16-15-00-13.gh-issue-135386.lNrxLc.rst b/Misc/NEWS.d/next/Library/2025-06-16-15-00-13.gh-issue-135386.lNrxLc.rst new file mode 100644 index 00000000000000..d3f81cb9201aaf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-06-16-15-00-13.gh-issue-135386.lNrxLc.rst @@ -0,0 +1 @@ +Fix :exc:`sqlite3.OperationalError` error when using :func:`dbm.open` with a read-only file object.