Can I get a callback / do I know when SQLite has created write-ahead log files? I want to chmod them - sqlite

I have an elevated process and I want to make sure the SQLite files that it creates are readable by other processes. For some reason umask doesn't seem to do what I want (set permissions of sqlite file created by process).
I'm using write-ahead logging, so -wal and -shm files are created in addition to the database file. I want all 3 to be chmodded correctly.
I wonder if it's possible to get in after the SQLite file is created and chmod it.
Possible approaches:
touch all 3 files before SQLite tries to create them, then chmod and hope the mask stays the same
Intercept when the files are created and chmod them.
Work out how to get umask to work for the process.
Mystery option four.
What's the best way to go?
Questions for approaches:
Will SQLite be OK with this?
Do we know when all 3 files are created? Is there some kind of callback I can give a function pointer to? Do we know if the same wal and shm files are around forever? Or are they deleted and re-created?

You can touch the database file before opening it. (When you use the sqlite3 command-line tool to open a new file, but do nothing but begin; and commit;, SQLite itself will create a zero-sized file.)
If you want to intercept file operations, you can register your own VFS.
The -wal and -shm files are created dynamically, but SQLite will give them the same permission bits as the main database file. The comments for robust_open() in os_unix.c say:
If the file creation mode "m" is 0 then set it to the default for
SQLite. The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
0644) as modified by the system umask. If m is not 0, then
make the file creation mode be exactly m ignoring the umask.
The m parameter will be non-zero only when creating -wal, -journal,
and -shm files. We want those files to have exactly the same
permissions as their original database, unadulterated by the umask.
In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
transaction crashes and leaves behind hot journals, then any
process that is able to write to the database will also be able to
recover the hot journals.

Related

How to set globally writable permissions on SQLite WAL and SHM files?

SQLite creates WAL and SHM files when in WAL mode. These files seem to be created with 644 permissions (r/w for creator only, and read for everyone else)
I want to use the same database file with two different OS users. When trying to write to the database with a WAL file created by another user, SQLite gives an error: attempt to write a readonly database [8]. This error seems to be because the WAL is not writable by the second user.
The question is therefore: how do I change the permissions on these files, given that they are created and deleted by SQLite itself so can't just be changed manually?
Newly created files by SQLite will follow the system defaults for created files.
Ensure that the parent directory has the correct world-writable permission, and that the umask allows this. (parent dir should have 777 permissions, and umask should be 000).
All processes accessing the DB must have the correct umask. It is possible to work around this for exactly one process without the correct umask, if all the other processes run as root (and thus can access an incorrectly permissioned WAL file).
Theoretically, it should also be possible to enable WAL persistence and avoid this issue.

SQLite database files

I want to know why SQLite create two file inside the path.and what is the diffrence these files.
I have a database name mydatabase.
when i see in given path there are two files.
data/data/pack name/databases/....
1- mydatabase
2- mydatabase-journal
mydatabase is main database file, which contains everything about that database.
mydatabase-journal is journal file. It does not exist by default, and only gets created by SQLite when necessary to keep intent log of what SQLite wants to do with database. Basically, this is intent of what should be done to main database file after transaction is properly finished. If you finish all transactions normally and disconnect from database gracefully, -journal file will be normally removed automatically.
If disconnect was abrupt - like process killed or crashed, -journal file will remain and should NOT be deleted. When next time SQLite opens this database once again, it will notice presence of -journal file and will replay or rollback unfinished transactions, such that main database file is consistent and not corrupted.
If you remove -journal file manually, recovery is not guaranteed and database may be completely corrupted - so, DO NOT remove -journal files.
Probably easiest way to properly get rid of -journal files is to do this command:
sqlite3 mysqlitedatabase.db VACUUM
It will VACUUM (optimize) your database and should leave only main file as a result.

Write-Ahead Logging and Read-Only mode compatible in SQLite3?

Open read-only
I have a sqlite3 file on a filesystem that belongs to a different user than is running the reading process. I want the reading process to be able to read the file in read-only mode, so I'm passing SQLITE_OPEN_READONLY. I would expect that to work. Surely the idea is that read-only mode works on files that we don't want to write to?
When I prepare my first statement I get
unable to open database file
Similarly if I run the sqlite3 command line tool I get the same result unless I sudo. Which seems to confirm to me that the issue is writeability rather than anything else.
Journal files
The answer to this question seems to suggest that if there are journal files around then read-only access isn't possible.
Why are there journal files? Because another process is writing the file, my user process is trying to open it in read-only. To do this I am using Write-Ahead Logging, which produces two journal files, -shm and -wal. True enough, if I stop the writing process and remove the journal files, my user process can open it in read-only mode.
Incompatibility?
So I have two situations:
If the file belongs to the writing process and also the read-only process, write-ahead logging enables process A to write and process B to read-only
If the file belongs to the writing process but does not belong to the read-only process, the read-only process is blocked from opening read-only.
How do I achieve both of these? To spell it out, I want:
Writing process owns database
Read-only process does not own database
Read-only process cannot write to database
Write-ahead logging is enabled on database
Seems like a simple set of requirements, but I can't see an obvious solution.
**EDIT: ** Going by this documentation, it looks like this isn't possible. Can you suggest any alternative ways to achieve the above?
Yes WAL-journaled databases cannot be opened read-only, explicitly or otherwise (i.e. in the case where the database file is read-only to the process).
If you require that the read-only process absolutely not be allowed to modify the database file, then the only thing that comes to mind is that the write process maintains a not WAL-journal additional copy of the database.
Bottom line: to the best of my knowledge, WAL and read-only can't be done.
I think what the documentation is saying is that the WAL database itself may not be present on a readonly media, which does not necessarily mean you cannot use SQLITE_OPEN_READONLY. In fact, I have successfully opened two connections, a read-write as well as one with SQLITE_OPEN_READONLY, both on a WAL sqlite database. These work just fine. I tested an INSERT query using the read-only connection and the statement correctly returned an error that the database is read-only.
Just make sure that the database is stored on some media with write-access as a -shm file needs to be created and maintained, and so even a 'ready-only' connection may actually physically write something to disk - which doesn't necessarily mean that it can modify data using SQL.

How can I write to a SQLite database file in a SourceForge project's web space?

I have a small Perl-based CGI application, which I am running in the project web space provided for a SourceForge project. This application stores data in a SQLite (v. 3) database file.
When I run test scripts from a shell, I can read from and write to this SQLite file. However, when the CGI code is executed by Apache, it has read-only access. Write operations result in a log file error:
error.log.web-2:[Wed Oct 27 14:40:22 2010] [error] [client 127.0.0.1] DBD::SQLite::db do failed: unable to open database file
For testing purposes, I have cranked the permissions for that SQLite file all the way up to 777. No difference.
However, there are some funny caveats to SourceForge's project web space, and I wonder if I'm being tripped up by that. Generally, the main web server filesystem is read-only to Apache. If you have files that need to be writable at runtime, you're supposed to store them in a special "persistent" directory elsewhere... and create symlinks from your web space to the actual files under that directory.
I have done this, and the permissions are set to 777 for both the symlink and the actual SQLite file under the "persistence" location. I know this mechanism works in general, because I'm doing the same thing with cache and log files and it works there.
I'm wondering if there's anything funky about SQLite itself, along the lines of it not wanting to open a symlink (rather than a raw file) for writing.
I believe the answer to this question is that it can't be done. Further research into SQLite tells me that the driver must get a lock on the database file before it can do any write operations. This type of lock cannot be obtained when the actual file is on a different machine with its filesystem cross-mounted.
I believe this is the case with SourceForge project web space hosting. It looks like the (writable) "persistent" directory is actually on a totally separate machine from the read-only web server filesystem.
In short, if you stumble across this question because you're having the same issue... either look for different web space hosting, or else it may be time to re-work your app and step up to MySQL or some other DB (SourceForge gives you free MySQL hosting anyway).
Another issue is if you have permissions for the specific db file but you don't have permission to make the temporary files in the directory. (Mixed permissions, or too restrictive permissions)
https://www.sqlite.org/tempfiles.html
If you can't write the temporary files then you can't do any writes on a sqlite database file. If you switch it to a :memory: database you could get by or maybe use the pragma mentioned by #bob.faist PRAGMA temp_store = MEMORY, but really you should diagnosis and fix the permissions problem if possible.
Use these commands to see if you have permission to write in those file locations.
ls -l app.db
getfacl app.db
ls -l -d . # check the directory to see if you can write the temp files there
getfacl .
Use chmod or setfacl -m to fix the files or folders to let you write to them.
Also check your diskspace.
df -k
If it shows that your partition where the database file is located or is trying to write its files to are full, you could also get these kinds of issues.
Hope that helps.

Change SQLite database mode to read-write

How can I change an SQLite database from read-only to read-write?
When I executed the update statement, I always got:
SQL error: attempt to write a readonly database
The SQLite file is a writeable file on the filesystem.
There can be several reasons for this error message:
Several processes have the database open at the same time (see the FAQ).
There is a plugin to compress and encrypt the database. It doesn't allow to modify the DB.
Lastly, another FAQ says: "Make sure that the directory containing the database file is also writable to the user executing the CGI script." I think this is because the engine needs to create more files in the directory.
The whole filesystem might be read only, for example after a crash.
On Unix systems, another process can replace the whole file.
I solved this by changing owner from "root" to my own user, on all files in Database's folder.
Just do ls -l on said folder, and if any of the files is owned by root, just change it to your user, like:
# For each file do:
sudo chown "$USER":"$USER" /path/to/my-folder/file.txt
# Or "R"ecursive.
sudo chown -R "$USER":"$USER" /path/to/my-folder
(this error message is typically misleading, and is usually a general permissions error)
On Windows
If you're issuing SQL directly against the database, make sure whatever application you're using to run the SQL is running as administrator
If an application is attempting the update, the account that it uses to access the database may need permissions on the folder containing your database file. For example, if IIS is accessing the database, the IUSR and IIS_IUSRS may both need appropriate permissions (you can try this by temporarily giving these accounts full control over the folder, checking if this works, then tying down the permissions as appropriate)
This error usually happens when your database is accessed by one application already, and you're trying to access it with another application.
To share personal experience I encountered with this error that eventually fix both. Might not necessarily be related to your issue but it appears this error is so generic that it can be attributed to gazillion things.
Database instance open in another application. My DB appeared to have been in a "locked" state so it transition to read only mode. I was able to track it down by stopping the a 2nd instance of the application sharing the DB.
Directory tree permission - please be sure to ensure user account has permission not just at the file level but at the entire upper directory level all the way to / level.
Thanks
If using Android.
Make sure you have added the permission to write to your EXTERNAL_STORAGE to your AndroidManifest.xml.
Add this line to your AndroidManifest.xml file above and outside your <application> tag.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
This will allow your application to write to the sdcard. This will help if your EXTERNAL_STORAGE is where you have stored your database on the device.
On win10 after a system crash, try to open db with DB Browser, but read only.
Simply delete the journal file.
In Linux command shell, I did:
chmod 777 <db_folder>
Where contains the database file.
It works. Now I can access my database and make insert queries.
On Windows:
tl;dr: Try opening the file again.
Our system was suffering this problem, and it definitely wasn't a permissions issue, since the program itself would be able to open the database as writable from many threads most of the time, but occasionally (only on Windows, not on OSX), a thread would get these errors even though all the other threads in the program were having no difficulties.
We eventually discovered that the threads that were failing were only those that were trying to open the database immediately after another thread had closed it (within 3 ms). We speculated that the problem was due to the fact that Windows (or the sqlite implementation under windows) doesn't always immediately clean up up file resources upon closing of a file. We got around this by running a test write query against the db upon opening (e.g., creating then dropping a table with a silly name). If the create/drop failed, we waited for 50 ms and tried again, repeating until we succeeded or 5 seconds elapsed.
It worked; apparently there just needed to be enough time for the resources to flush out to disk.
On Ubuntu, change the owner to the Apache group and grant the right permissions (no, it's not 777):
sudo chgrp www-data <path to db.sqlite3>
sudo chmod 664 <path to db.sqlite3>
Update
You can set the permissions for group and user as well.
sudo chown www-data:www-data <path to db.sqlite3>
If <db_name>.sqlite-journal file exists in the same folder with DB file, that means your DB is opened currently and in the middle of some changes (or it had been at the moment when DB folder was copied). If you try to open DB at this moment error attempt to write a readonly database (or similar) could appear.
As a solution, wait till <db_name>.sqlite-journal disappears or remove it (is not recommended on the working system)
I had this problem today, too.
It was caused by ActiveSync on Windows Mobile - the folder I was working in was synced so the AS process grabbed the DB file from time to time causing this error.
On Linux, give read/write permissions to the entire folder containing the database file.
Also, SELinux might be blocking the write. You need to set the correct permissions.
In my SELinux Management GUI (on Fedora 19), I checked the box on the line labelled httpd_unified (Unify HTTPD handling of all content files), and I was good to go.
I'm using SQLite on ESP32 and all answers here are "very strange"....
When I look at the data on the flash of the ESP I notice there is only one file for the whole db (there is also a temp file).
In this db file we have of course the user tables but also the system tables so "sqlite_master" for example which contain the definiton of the tables.
So, it's seems hard to belive this can be a "chmod" problem, because if the file is read only, even creating table would be impossible as SQLite would be unable to write the "sqlite_master" data...
So I think our friend user143482 is trying to acesse a "read only" table. In SQLite source code we can see a function named tabIsReadOnly with this comment:
/* Return true if table pTab is read-only.
**
** A table is read-only if any of the following are true:
**
** 1) It is a virtual table and no implementation of the xUpdate method
** has been provided
**
** 2) It is a system table (i.e. sqlite_master), this call is not
** part of a nested parse and writable_schema pragma has not
** been specified
**
** 3) The table is a shadow table, the database connection is in
** defensive mode, and the current sqlite3_prepare()
** is for a top-level SQL statement.
*/

Resources