mirror of https://github.com/python/cpython
bpo-45613: Set `sqlite3.threadsafety` dynamically (GH-29227)
Use the compile-time selected default SQLite threaded mode to set the DB-API 2.0 attribute 'threadsafety' Mappings: - SQLITE_THREADSAFE=0 => threadsafety=0 - SQLITE_THREADSAFE=1 => threadsafety=3 - SQLITE_THREADSAFE=2 => threadsafety=1
This commit is contained in:
parent
762173c670
commit
c273986711
|
@ -159,23 +159,41 @@ Module functions and constants
|
|||
|
||||
.. data:: threadsafety
|
||||
|
||||
Integer constant required by the DB-API, stating the level of thread safety
|
||||
the :mod:`sqlite3` module supports. Currently hard-coded to ``1``, meaning
|
||||
*"Threads may share the module, but not connections."* However, this may not
|
||||
always be true. You can check the underlying SQLite library's compile-time
|
||||
threaded mode using the following query::
|
||||
Integer constant required by the DB-API 2.0, stating the level of thread
|
||||
safety the :mod:`sqlite3` module supports. This attribute is set based on
|
||||
the default `threading mode <https://sqlite.org/threadsafe.html>`_ the
|
||||
underlying SQLite library is compiled with. The SQLite threading modes are:
|
||||
|
||||
import sqlite3
|
||||
con = sqlite3.connect(":memory:")
|
||||
con.execute("""
|
||||
select * from pragma_compile_options
|
||||
where compile_options like 'THREADSAFE=%'
|
||||
""").fetchall()
|
||||
1. **Single-thread**: In this mode, all mutexes are disabled and SQLite is
|
||||
unsafe to use in more than a single thread at once.
|
||||
2. **Multi-thread**: In this mode, SQLite can be safely used by multiple
|
||||
threads provided that no single database connection is used
|
||||
simultaneously in two or more threads.
|
||||
3. **Serialized**: In serialized mode, SQLite can be safely used by
|
||||
multiple threads with no restriction.
|
||||
|
||||
Note that the `SQLITE_THREADSAFE levels
|
||||
<https://sqlite.org/compile.html#threadsafe>`_ do not match the DB-API 2.0
|
||||
``threadsafety`` levels.
|
||||
The mappings from SQLite threading modes to DB-API 2.0 threadsafety levels
|
||||
are as follows:
|
||||
|
||||
+------------------+-----------------+----------------------+-------------------------------+
|
||||
| SQLite threading | `threadsafety`_ | `SQLITE_THREADSAFE`_ | DB-API 2.0 meaning |
|
||||
| mode | | | |
|
||||
+==================+=================+======================+===============================+
|
||||
| single-thread | 0 | 0 | Threads may not share the |
|
||||
| | | | module |
|
||||
+------------------+-----------------+----------------------+-------------------------------+
|
||||
| multi-thread | 1 | 2 | Threads may share the module, |
|
||||
| | | | but not connections |
|
||||
+------------------+-----------------+----------------------+-------------------------------+
|
||||
| serialized | 3 | 1 | Threads may share the module, |
|
||||
| | | | connections and cursors |
|
||||
+------------------+-----------------+----------------------+-------------------------------+
|
||||
|
||||
.. _threadsafety: https://www.python.org/dev/peps/pep-0249/#threadsafety
|
||||
.. _SQLITE_THREADSAFE: https://sqlite.org/compile.html#threadsafe
|
||||
|
||||
.. versionchanged:: 3.11
|
||||
Set *threadsafety* dynamically instead of hard-coding it to ``1``.
|
||||
|
||||
.. data:: PARSE_DECLTYPES
|
||||
|
||||
|
|
|
@ -254,6 +254,10 @@ sqlite3
|
|||
setting and getting SQLite limits by connection basis.
|
||||
(Contributed by Erlend E. Aasland in :issue:`45243`.)
|
||||
|
||||
* :mod:`sqlite3` now sets :attr:`sqlite3.threadsafety` based on the default
|
||||
threading mode the underlying SQLite library has been compiled with.
|
||||
(Contributed by Erlend E. Aasland in :issue:`45613`.)
|
||||
|
||||
|
||||
threading
|
||||
---------
|
||||
|
|
|
@ -28,8 +28,6 @@ from _sqlite3 import *
|
|||
|
||||
paramstyle = "qmark"
|
||||
|
||||
threadsafety = 1
|
||||
|
||||
apilevel = "2.0"
|
||||
|
||||
Date = datetime.date
|
||||
|
|
|
@ -54,8 +54,9 @@ class ModuleTests(unittest.TestCase):
|
|||
"apilevel is %s, should be 2.0" % sqlite.apilevel)
|
||||
|
||||
def test_thread_safety(self):
|
||||
self.assertEqual(sqlite.threadsafety, 1,
|
||||
"threadsafety is %d, should be 1" % sqlite.threadsafety)
|
||||
self.assertIn(sqlite.threadsafety, {0, 1, 3},
|
||||
"threadsafety is %d, should be 0, 1 or 3" %
|
||||
sqlite.threadsafety)
|
||||
|
||||
def test_param_style(self):
|
||||
self.assertEqual(sqlite.paramstyle, "qmark",
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
:mod:`sqlite3` now sets :attr:`sqlite3.threadsafety` based on the default
|
||||
threading mode the underlying SQLite library has been compiled with. Patch by
|
||||
Erlend E. Aasland.
|
|
@ -540,6 +540,28 @@ add_integer_constants(PyObject *module) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Convert SQLite default threading mode (as set by the compile-time constant
|
||||
* SQLITE_THREADSAFE) to the corresponding DB-API 2.0 (PEP 249) threadsafety
|
||||
* level. */
|
||||
static int
|
||||
get_threadsafety(pysqlite_state *state)
|
||||
{
|
||||
int mode = sqlite3_threadsafe();
|
||||
switch (mode) {
|
||||
case 0: // Single-thread mode; threads may not share the module.
|
||||
return 0;
|
||||
case 1: // Serialized mode; threads may share the module,
|
||||
return 3; // connections, and cursors.
|
||||
case 2: // Multi-thread mode; threads may share the module, but not
|
||||
return 1; // connections.
|
||||
default:
|
||||
PyErr_Format(state->InterfaceError,
|
||||
"Unable to interpret SQLite threadsafety mode. Got %d, "
|
||||
"expected 0, 1, or 2", mode);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
module_traverse(PyObject *module, visitproc visit, void *arg)
|
||||
{
|
||||
|
@ -689,6 +711,14 @@ module_exec(PyObject *module)
|
|||
goto error;
|
||||
}
|
||||
|
||||
int threadsafety = get_threadsafety(state);
|
||||
if (threadsafety < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (PyModule_AddIntConstant(module, "threadsafety", threadsafety) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* initialize microprotocols layer */
|
||||
if (pysqlite_microprotocols_init(module) < 0) {
|
||||
goto error;
|
||||
|
|
Loading…
Reference in New Issue