Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork34.1k
gh-135386: Fix "unable to open database file" errors on readonly DB#135566
gh-135386: Fix "unable to open database file" errors on readonly DB#135566serhiy-storchaka merged 17 commits intopython:mainfrom
Conversation
…M errors on readonly DB
python-cla-botbot commentedJun 16, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Most changes to Pythonrequire a NEWS entry. Add one using theblurb_it web app or theblurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
ZeroIntensity left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Please add a test case. You can refer to thedevguide for how to do that.
Misc/NEWS.d/next/Library/2025-06-16-15-00-13.gh-issue-135386.lNrxLc.rst OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
707f4a3 to779faf2CompareZeroIntensity commentedJun 17, 2025
No need to force-push, we squash at the end. |
GeneralK1ng commentedJun 17, 2025
Got it, thanks for the reminder! |
ZeroIntensity commentedJun 17, 2025
FYI, tests are failing on Windows. |
GeneralK1ng commentedJun 17, 2025
Thanks for the suggestion. I've skipped the test on Windows using |
tomasr8 left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks for the PR!
I've skipped the test on Windows
I think we should be testing this on all platforms if possible. Maybe we can figure out why the test is failing on Windows and adapt it?
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Co-authored-by: Tomas R. <tomas.roun8@gmail.com>
Co-authored-by: Tomas R. <tomas.roun8@gmail.com>
GeneralK1ng commentedJun 23, 2025
Sure, that makes sense — I'd be happy to look into making the test work on Windows as well. Also, thanks for the suggestions — I've adopted the URI change and simplified the flag check as suggested. : ) |
GeneralK1ng commentedJun 23, 2025
I've updated the test so it no longer skips on Windows — instead, it now explicitly closes the database before setting read-only permissions, and restores the original permissions after the test. |
Uh oh!
There was an error while loading.Please reload this page.
Lib/test/test_dbm_sqlite3.py Outdated
| def test_readonly_open_without_wal_shm(self): | ||
| wal_path = self.filename + "-wal" | ||
| shm_path = self.filename + "-shm" | ||
| for suffix in wal_path, shm_path: | ||
| os_helper.unlink(suffix) | ||
| try: | ||
| self.db.close() | ||
| except Exception: | ||
| pass | ||
| os.chmod(self.filename, stat.S_IREAD) | ||
| db = dbm_sqlite3.open(self.filename, "r") | ||
| try: | ||
| self.assertEqual(db[b"key1"], b"value1") | ||
| self.assertEqual(db[b"key2"], b"value2") | ||
| finally: | ||
| db.close() | ||
| os.chmod(self.filename, stat.S_IWRITE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
IIUC correctly, this change makes it so that the WAL/SHM files are no longer created in read-only mode? In that case, we could simplify the test to simply open the database in read-only mode and check that the auxiliary files are not written. I'm thinking something like this:
classImmutable(unittest.TestCase):defsetUp(self):self.filename=os_helper.TESTFNself.db=dbm_sqlite3.open(self.filename,"r")deftearDown(self):self.db.close()deftest_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))
Or does this also affect the database file itself? i.e. does passingimmutable=1 allow opening read-only files whereas otherwise it would be impossible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks, I’ve replaced the original test with your suggested version in a new Immutable test class. It’s much cleaner and focused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Or does this also affect the database file itself? i.e. does passing
immutable=1allow opening read-only files whereas otherwise it would be impossible?
Yes, exactly — withoutimmutable=1, even inmode=ro, SQLite may still attempt operations that require write access (like writing lock files or checking for journal/WAL state), and will fail if the database file is read-only or in a read-only directory.
Passingimmutable=1 tells SQLite to treat the database as entirely static and read-only, which avoids those operations and allows the file to be opened successfully even with 0444 permissions or from a read-only mount.
toslunar commentedJun 25, 2025
In order to use https://www.sqlite.org/uri.html#recognized_query_parameters says
|
erlend-aasland left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
With Serhiy's amendments, this is good to go. Thank you so much for fixing this,@GeneralK1ng!
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
GeneralK1ng commentedAug 22, 2025
Thanks everyone for the reviews and help polishing this! Really appreciate the guidance. |
c0ae92b intopython:mainUh oh!
There was an error while loading.Please reload this page.
Thanks@GeneralK1ng for the PR, and@serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 3.14. |
…y DB (pythonGH-135566)Add immutable=1 flag for read-only SQLite access to avoid WAL/SHM errors on readonly DB.(cherry picked from commitc0ae92b)Co-authored-by: General_K1ng <generak1ng0@gmail.com>Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
GH-138056 is a backport of this pull request to the3.14 branch. |
Thanks@GeneralK1ng for the PR, and@serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13. |
…y DB (pythonGH-135566)Add immutable=1 flag for read-only SQLite access to avoid WAL/SHM errors on readonly DB.(cherry picked from commitc0ae92b)Co-authored-by: General_K1ng <generak1ng0@gmail.com>Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
GH-138057 is a backport of this pull request to the3.13 branch. |
bedevere-bot commentedAug 22, 2025
|
…y DB (pythonGH-135566)Add immutable=1 flag for read-only SQLite access to avoid WAL/SHM errors on readonly DB.(cherry picked from commitc0ae92b)Co-authored-by: General_K1ng <generak1ng0@gmail.com>Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
serhiy-storchaka commentedAug 22, 2025
I forgot to test this under the root user.#138058 skips tests for that case. |
bedevere-bot commentedAug 22, 2025
|
toslunar commentedAug 25, 2025
Looking at the PR diff, it seems my concerns haven't been addressed. |
serhiy-storchaka commentedAug 25, 2025
Support for concurrent write/read access was not promised. |
toslunar commentedAug 25, 2025
It's a bit surprising to me that |
…ly DB (GH-135566) (GH-138056)Add immutable=1 flag for read-only SQLite access to avoid WAL/SHM errors on readonly DB.(cherry picked from commitc0ae92b)Co-authored-by: General_K1ng <generak1ng0@gmail.com>Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>Co-authored-by: Petr Viktorin <encukou@gmail.com>
Uh oh!
There was an error while loading.Please reload this page.
What
This PR adds the SQLite URI parameter
immutable=1when opening a database in read-only mode inLib/dbm/sqlite3.py. This explicitly informs SQLite that the database is read-only and avoids attempts to create or write to auxiliary WAL/SHM files.Why
Without this flag, opening a read-only SQLite database may fail with errors such as "unable to open database file" when the WAL or SHM files cannot be created due to filesystem permissions or other restrictions. This is especially common when the database file is read-only and the environment prevents creation of additional files.
Adding
immutable=1allows SQLite to operate correctly without needing to create WAL/SHM files, thus preventing these errors.Where
The change is made in the
_Database.__init__constructor inLib/dbm/sqlite3.py. The URI used to open the database connection is appended with&immutable=1only if theflagis"ro"(read-only).Related issue
#135386
This is my first contribution to CPython. I appreciate the opportunity and look forward to feedback from the community. Thank you!