10000 sqlite3_file_control · python/cpython@e32c372 · GitHub
[go: up one dir, main page]

Skip to content

Commit e32c372

Browse files
sqlite3_file_control
1 parent 0cafa97 commit e32c372

File tree

5 files changed

+202
-1
lines changed

5 files changed

+202
-1
lines changed

Lib/test/test_sqlite3/test_dbapi.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import sqlite3 as sqlite
2626
import subprocess
2727
import sys
28+
import tempfile
2829
import threading
2930
import unittest
3031
import urllib.parse
@@ -735,6 +736,30 @@ def test_database_keyword(self):
735736
with contextlib.closing(sqlite.connect(database=":memory:")) as cx:
736737
self.assertEqual(type(cx), sqlite.Connection)
737738

739+
def test_wal_preservation(self):
740+
with tempfile.TemporaryDirectory() as dirname:
741+
path = os.path.join(dirname, "db.sqlite")
742+
with contextlib.closing(sqlite.connect(path)) as cx:
743+
cx.set_file_control(sqlite.SQLITE_FCNTL_PERSIST_WAL, 1)
744+
cu = cx.cursor()
745+
cu.execute("PRAGMA journal_mode = WAL")
746+
cu.execute("CREATE TABLE foo (id int)")
747+
cu.execute("INSERT INTO foo (id) VALUES (1)")
748+
self.assertTrue(os.path.exists(path + "-wal"))
749+
self.assertTrue(os.path.exists(path + "-wal"))
750+
751+
with contextlib.closing(sqlite.connect(path)) as cx:
752+
cu = cx.cursor()
753+
self.assertTrue(os.path.exists(path + "-wal"))
754+
cu.execute("INSERT INTO foo (id) VALUES (2)")
755+
self.assertFalse(os.path.exists(path + "-wal"))
756+
757+
758+
def test_file_control_raises(self):
759+
with contextlib.closing(sqlite.connect(database=":memory:")) as cx:
760+
with self.assertRaises(sqlite.ProgrammingError):
761+
cx.set_file_control(sqlite.SQLITE_FCNTL_PERSIST_WAL, 1)
762+
738763

739764
class CursorTests(unittest.TestCase):
740765
def setUp(self):
@@ -1863,6 +1888,8 @@ def test_on_conflict_replace(self):
18631888
self.assertEqual(self.cu.fetchall(), [('Very different data!', 'foo')])
18641889

18651890

1891+
1892+
18661893
@requires_subprocess()
18671894
class MultiprocessTests(unittest.TestCase):
18681895
CONNECTION_TIMEOUT = 0 # Disable the busy timeout.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
sqlite Connection objects now expose a method set_file_control, which is a thin wrapper for `sqlite3_file_control https://www.sqlite.org/c3ref/file_control.html`_.

Modules/_sqlite/clinic/connection.c.h

Lines changed: 92 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_sqlite/connection.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,6 +2173,45 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
21732173
Py_RETURN_NONE;
21742174
}
21752175

2176+
/*[clinic input]
2177+
_sqlite3.Connection.set_file_control as pysqlite_connection_set_file_control
2178+
2179+
op: int
2180+
a SQLITE_FCNTL_ constant
2181+
arg: long
2182+
argument to pass
2183+
/
2184+
dbname: str = NULL
2185+
database name
2186+
2187+
Invoke a file control method on the database.
2188+
[clinic start generated code]*/
2189+
2190+
static PyObject *
2191+
pysqlite_connection_set_file_control_impl(pysqlite_Connection *self, int op,
2192+
long arg, const char *dbname)
2193+
/*[clinic end generated code: output=d9d2d311892893b6 input=0253798d9514fea2]*/
2194+
{
2195+
int rc;
2196+
long val = arg;
2197+
2198+
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
2199+
return NULL;
2200+
}
2201+
2202+
Py_BEGIN_ALLOW_THREADS
2203+
rc = sqlite3_file_control(self->db, dbname, op, &val);
2204+
Py_END_ALLOW_THREADS
2205+
2206+
if (rc != SQLITE_OK) {
2207+
PyErr_SetString(self->ProgrammingError, sqlite3_errstr(rc));
2208+
return NULL;
2209+
}
2210+
2211+
return PyLong_FromLong(val);
2212+
}
2213+
2214+
21762215
#ifdef PY_SQLITE_HAVE_SERIALIZE
21772216
/*[clinic input]
21782217
_sqlite3.Connection.serialize as serialize
@@ -2601,6 +2640,7 @@ static PyMethodDef connection_methods[] = {
26012640
PYSQLITE_CONNECTION_SET_AUTHORIZER_METHODDEF
26022641
PYSQLITE_CONNECTION_SET_PROGRESS_HANDLER_METHODDEF
26032642
PYSQLITE_CONNECTION_SET_TRACE_CALLBACK_METHODDEF
2643+
PYSQLITE_CONNECTION_SET_FILE_CONTROL_METHODDEF
26042644
SETLIMIT_METHODDEF
26052645
GETLIMIT_METHODDEF
26062646
SERIALIZE_METHODDEF

Modules/_sqlite/module.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,48 @@ add_integer_constants(PyObject *module) {
514514
ADD_INT(SQLITE_DBCONFIG_LEGACY_FILE_FORMAT);
515515
ADD_INT(SQLITE_DBCONFIG_TRUSTED_SCHEMA);
516516
#endif
517+
ADD_INT(SQLITE_FCNTL_LOCKSTATE);
518+
ADD_INT(SQLITE_FCNTL_GET_LOCKPROXYFILE);
519+
ADD_INT(SQLITE_FCNTL_SET_LOCKPROXYFILE);
520+
ADD_INT(SQLITE_FCNTL_LAST_ERRNO);
521+
ADD_INT(SQLITE_FCNTL_SIZE_HINT);
522+
ADD_INT(SQLITE_FCNTL_CHUNK_SIZE);
523+
ADD_INT(SQLITE_FCNTL_FILE_POINTER);
524+
ADD_INT(SQLITE_FCNTL_SYNC_OMITTED);
525+
ADD_INT(SQLITE_FCNTL_WIN32_AV_RETRY);
526+
ADD_INT(SQLITE_FCNTL_PERSIST_WAL);
527+
ADD_INT(SQLITE_FCNTL_OVERWRITE);
528+
ADD_INT(SQLITE_FCNTL_VFSNAME);
529+
ADD_INT(SQLITE_FCNTL_POWERSAFE_OVERWRITE);
530+
ADD_INT(SQLITE_FCNTL_PRAGMA);
531+
ADD_INT(SQLITE_FCNTL_BUSYHANDLER);
532+
ADD_INT(SQLITE_FCNTL_TEMPFILENAME);
533+
ADD_INT(SQLITE_FCNTL_MMAP_SIZE);
534+
ADD_INT(SQLITE_FCNTL_TRACE);
535+
ADD_INT(SQLITE_FCNTL_HAS_MOVED);
536+
ADD_INT(SQLITE_FCNTL_SYNC);
537+
ADD_INT(SQLITE_FCNTL_COMMIT_PHASETWO);
538+
ADD_INT(SQLITE_FCNTL_WIN32_SET_HANDLE);
539+
ADD_INT(SQLITE_FCNTL_WAL_BLOCK);
540+
ADD_INT(SQLITE_FCNTL_ZIPVFS);
541+
ADD_INT(SQLITE_FCNTL_RBU);
542+
ADD_INT(SQLITE_FCNTL_VFS_POINTER);
543+
ADD_INT(SQLITE_FCNTL_JOURNAL_POINTER);
544+
ADD_INT(SQLITE_FCNTL_WIN32_GET_HANDLE);
545+
ADD_INT(SQLITE_FCNTL_PDB);
546+
ADD_INT(SQLITE_FCNTL_BEGIN_ATOMIC_WRITE);
547+
ADD_INT(SQLITE_FCNTL_COMMIT_ATOMIC_WRITE);
548+
ADD_INT(SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE);
549+
ADD_INT(SQLITE_FCNTL_LOCK_TIMEOUT);
550+
ADD_INT(SQLITE_FCNTL_DATA_VERSION);
551+
ADD_INT(SQLITE_FCNTL_SIZE_LIMIT);
552+
ADD_INT(SQLITE_FCNTL_CKPT_DONE);
553+
ADD_INT(SQLITE_FCNTL_RESERVE_BYTES);
554+
ADD_INT(SQLITE_FCNTL_CKPT_START);
555+
ADD_INT(SQLITE_FCNTL_EXTERNAL_READER);
556+
ADD_INT(SQLITE_FCNTL_CKSM_FILE);
557+
ADD_INT(SQLITE_FCNTL_RESET_CACHE);
558+
517559
#undef ADD_INT
518560
return 0;
519561
}

0 commit comments

Comments
 (0)
0