Reputation: 1737
The SQLite docs for in-memory databases (https://www.sqlite.org/inmemorydb.html) indicate that to share :memory: across connections, you should use URI naming and set cache=shared, like so (C API):
rc = sqlite3_open("file::memory:?cache=shared", &db);
I tried this from Python 2.7.14, with these attributes:
>>> sqlite3.version
'2.6.0'
>>> sqlite3.apilevel
'2.0'
>>> sqlite3.sqlite_version
'3.20.1'
What I discovered was that the database isn't quite as transient as I would have expected. Here's a session.
First, create a database and insert a row...
% python
Python 2.7.14 |Anaconda, Inc.| (default, Dec 7 2017, 17:05:42)
[GCC 7.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sqlite3
>>> conn = sqlite3.Connection("file::memory:?cache=shared")
>>> curs = conn.cursor()
>>> curs.execute("select * from sqlite_master").fetchall()
[]
>>> curs.execute("create table XYZ (x int, y int, z varchar)")
<sqlite3.Cursor object at 0x7ff4b2a06110>
>>> curs.execute("insert into XYZ values (?, ?, ?)", (1, 2, '3'))
<sqlite3.Cursor object at 0x7ff4b2a06110>
>>> curs.execute("select * from sqlite_master").fetchall()
[(u'table', u'XYZ', u'XYZ', 2, u'CREATE TABLE XYZ (x int, y int, z varchar)')]
>>> curs.execute("select * from XYZ").fetchall()
[(1, 2, u'3')]
>>> conn.close()
>>>
Look here, there's a leftover file:
% ls -l file*
-rw-r--r-- 1 skip skip 8192 Jan 22 12:49 file::memory:?cache=shared
And it seems to have some bits left over from the session:
% strings -a file*
SQLite format 3
atableXYZXYZ
CREATE TABLE XYZ (x int, y int, z varchar)
Indeed, I can open it. Although it appears to be empty (I didn't explicitly commit() in the first session, so perhaps that's why), the database is still there and accessibe:
% python
Python 2.7.14 |Anaconda, Inc.| (default, Dec 7 2017, 17:05:42)
[GCC 7.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sqlite3
>>> conn = sqlite3.Connection("file::memory:?cache=shared")
>>> curs = conn.cursor()
>>> curs.execute("select * from XYZ").fetchall()
[]
>>> curs.execute("select * from sqlite_master").fetchall()
[(u'table', u'XYZ', u'XYZ', 2, u'CREATE TABLE XYZ (x int, y int, z varchar)')]
When I first saw mention of the form "file::memory?cache=shared", I thought it looked odd. Should it instead have been something more like "file://:memory:?cache=shared"? I tried that and received an error. Still, while the documented name works, it clearly writes a file to the filesystem. I discovered this quite by accident earlier when I noticed how slow it was compared to plain old ":memory:", and how large the resulting files were. Unfortunately, those files were written to an NFS-mounted filesystem, which might explain a lot of the slowness.
Is there a way to guarantee an in-memory database which can be accessed from multiple connections in the same process?
Upvotes: 0
Views: 2267
Reputation: 7665
If connecting via SQLAlchemy, the uri=true
flag needs to be set on the URI itself, eg:
sqlalchemy.create_engine('sqlite:///:memory:?cache=shared&uri=true')
See https://docs.sqlalchemy.org/en/14/dialects/sqlite.html#uri-connections for details
Upvotes: 0
Reputation: 180020
Opening an in-memory database with shared-cache mode requires a URI filename. Your Python version does not support this; it always treats the entire string as the file name.
URI filenames are supported in Python 3.4 and later:
db = sqlite3.connect("file::memory:?cache=shared", uri=True)
Upvotes: 1