From aa376f4ab17142516b19de6aa0b990b6d097b2f2 Mon Sep 17 00:00:00 2001 From: Ben Radford Date: Tue, 16 May 2023 15:29:29 +0100 Subject: [PATCH] Need to open database using immutable parameter. This requires switching on SQLITE_OPEN_URI because there is no open flag to make the database immutable. Without immutable, sqlite will still attempt to create journal and wal files, even when the database is opened read-only. https://www.sqlite.org/c3ref/open.html The immutable parameter is a boolean query parameter that indicates that the database file is stored on read-only media. When immutable is set, SQLite assumes that the database file cannot be changed, even by a process with higher privilege, and so the database is opened read-only and all locking and change detection is disabled. --- src/libstore/sqlite.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstore/sqlite.cc b/src/libstore/sqlite.cc index 8159744b7..4166cc2cd 100644 --- a/src/libstore/sqlite.cc +++ b/src/libstore/sqlite.cc @@ -1,6 +1,7 @@ #include "sqlite.hh" #include "globals.hh" #include "util.hh" +#include "url.hh" #include @@ -52,14 +53,16 @@ static void traceSQL(void * x, const char * sql) SQLite::SQLite(const Path & path, SQLiteOpenMode mode) { + bool readOnly = mode == SQLiteOpenMode::ReadOnly; + // useSQLiteWAL also indicates what virtual file system we need. Using // `unix-dotfile` is needed on NFS file systems and on Windows' Subsystem // for Linux (WSL) where useSQLiteWAL should be false by default. const char *vfs = settings.useSQLiteWAL ? 0 : "unix-dotfile"; - int flags = mode == SQLiteOpenMode::ReadOnly - ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE; + int flags = readOnly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE; if (mode == SQLiteOpenMode::Normal) flags |= SQLITE_OPEN_CREATE; - int ret = sqlite3_open_v2(path.c_str(), &db, flags, vfs); + auto uri = "file:" + percentEncode(path) + "?immutable=" + (readOnly ? "1" : "0"); + int ret = sqlite3_open_v2(uri.c_str(), &db, SQLITE_OPEN_URI | flags, vfs); if (ret != SQLITE_OK) { const char * err = sqlite3_errstr(ret); throw Error("cannot open SQLite database '%s': %s", path, err);