Skip to content

Commit 4867672

Browse files
sqlite3_file_control
1 parent dc60055 commit 4867672

File tree

5 files changed

+117
-38
lines changed

5 files changed

+117
-38
lines changed

Lib/test/test_sqlite3/test_dbapi.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -736,11 +736,12 @@ def test_database_keyword(self):
736736
with contextlib.closing(sqlite.connect(database=":memory:")) as cx:
737737
self.assertEqual(type(cx), sqlite.Connection)
738738

739+
@unittest.skipIf(sys.platform == "darwin", "skipped on macOS")
739740
def test_wal_preservation(self):
740741
with tempfile.TemporaryDirectory() as dirname:
741742
path = os.path.join(dirname, "db.sqlite")
742743
with contextlib.closing(sqlite.connect(path)) as cx:
743-
cx.set_file_control(sqlite.SQLITE_FCNTL_PERSIST_WAL, 1)
744+
cx.file_control(sqlite.SQLITE_FCNTL_PERSIST_WAL, 1)
744745
cu = cx.cursor()
745746
cu.execute("PRAGMA journal_mode = WAL")
746747
cu.execute("CREATE TABLE foo (id int)")
@@ -756,9 +757,9 @@ def test_wal_preservation(self):
756757

757758

758759
def test_file_control_raises(self):
759-
with memory_database() as con:
760+
with memory_database() as cx:
760761
with self.assertRaises(sqlite.ProgrammingError):
761-
cx.set_file_control(sqlite.SQLITE_FCNTL_PERSIST_WAL, 1)
762+
cx.file_control(sqlite.SQLITE_FCNTL_PERSIST_WAL, 1)
762763

763764

764765
class CursorTests(unittest.TestCase):
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
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`_.
1+
sqlite Connection objects now expose a method
2+
:meth:`~sqlite3.Connection.file_control`, which is a thin wrapper for
3+
`sqlite3_file_control <https://www.sqlite.org/c3ref/file_control.html>`_.

Modules/_sqlite/clinic/connection.c.h

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

Modules/_sqlite/connection.c

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,34 +2173,109 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
21732173
Py_RETURN_NONE;
21742174
}
21752175

2176+
static inline bool
2177+
is_int_fcntl(const int op)
2178+
{
2179+
switch (op) {
2180+
case SQLITE_FCNTL_LOCKSTATE:
2181+
case SQLITE_FCNTL_GET_LOCKPROXYFILE:
2182+
case SQLITE_FCNTL_SET_LOCKPROXYFILE:
2183+
case SQLITE_FCNTL_LAST_ERRNO:
2184+
case SQLITE_FCNTL_SIZE_HINT:
2185+
case SQLITE_FCNTL_CHUNK_SIZE:
2186+
case SQLITE_FCNTL_FILE_POINTER:
2187+
case SQLITE_FCNTL_SYNC_OMITTED:
2188+
case SQLITE_FCNTL_WIN32_AV_RETRY:
2189+
case SQLITE_FCNTL_PERSIST_WAL:
2190+
case SQLITE_FCNTL_OVERWRITE:
2191+
case SQLITE_FCNTL_POWERSAFE_OVERWRITE:
2192+
case SQLITE_FCNTL_PRAGMA:
2193+
case SQLITE_FCNTL_BUSYHANDLER:
2194+
case SQLITE_FCNTL_MMAP_SIZE:
2195+
case SQLITE_FCNTL_TRACE:
2196+
case SQLITE_FCNTL_HAS_MOVED:
2197+
case SQLITE_FCNTL_SYNC:
2198+
case SQLITE_FCNTL_COMMIT_PHASETWO:
2199+
case SQLITE_FCNTL_WIN32_SET_HANDLE:
2200+
case SQLITE_FCNTL_WAL_BLOCK:
2201+
case SQLITE_FCNTL_ZIPVFS:
2202+
case SQLITE_FCNTL_RBU:
2203+
case SQLITE_FCNTL_VFS_POINTER:
2204+
case SQLITE_FCNTL_JOURNAL_POINTER:
2205+
case SQLITE_FCNTL_WIN32_GET_HANDLE:
2206+
case SQLITE_FCNTL_PDB:
2207+
#if SQLITE_VERSION_NUMBER >= 3021000
2208+
case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE:
2209+
case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE:
2210+
case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE:
2211+
#endif
2212+
#if SQLITE_VERSION_NUMBER >= 3023000
2213+
case SQLITE_FCNTL_LOCK_TIMEOUT:
2214+
#endif
2215+
#if SQLITE_VERSION_NUMBER >= 3025000
2216+
case SQLITE_FCNTL_DATA_VERSION:
2217+
#endif
2218+
#if SQLITE_VERSION_NUMBER >= 3028000
2219+
case SQLITE_FCNTL_SIZE_LIMIT:
2220+
#endif
2221+
#if SQLITE_VERSION_NUMBER >= 3031000
2222+
case SQLITE_FCNTL_CKPT_DONE:
2223+
#endif
2224+
#if SQLITE_VERSION_NUMBER >= 3032000
2225+
case SQLITE_FCNTL_RESERVE_BYTES:
2226+
case SQLITE_FCNTL_CKPT_START:
2227+
#endif
2228+
#if SQLITE_VERSION_NUMBER >= 3035000
2229+
case SQLITE_FCNTL_EXTERNAL_READER:
2230+
#endif
2231+
#if SQLITE_VERSION_NUMBER >= 3036000
2232+
case SQLITE_FCNTL_CKSM_FILE:
2233+
#endif
2234+
#if SQLITE_VERSION_NUMBER >= 3040000
2235+
case SQLITE_FCNTL_RESET_CACHE:
2236+
#endif
2237+
#if SQLITE_VERSION_NUMBER >= 3048000
2238+
case SQLITE_FCNTL_NULL_IO:
2239+
#endif
2240+
return true;
2241+
default:
2242+
return false;
2243+
}
2244+
}
2245+
21762246
/*[clinic input]
2177-
_sqlite3.Connection.set_file_control as pysqlite_connection_set_file_control
2247+
_sqlite3.Connection.file_control as pysqlite_connection_file_control
21782248
21792249
op: int
2180-
a SQLITE_FCNTL_ constant
2250+
The SQLITE_FCNTL_* constant to invoke.
21812251
arg: long
2182-
argument to pass
2252+
The argument to pass to the operation.
21832253
/
2184-
dbname: str = NULL
2185-
database name
2254+
name: str = "main"
2255+
The database name to operate against.
21862256
21872257
Invoke a file control method on the database.
21882258
[clinic start generated code]*/
21892259

21902260
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]*/
2261+
pysqlite_connection_file_control_impl(pysqlite_Connection *self, int op,
2262+
long arg, const char *name)
2263+
/*[clinic end generated code: output=ab3230aaca500391 input=506d31506027e9ce]*/
21942264
{
2265+
if(!is_int_fcntl(op)) {
2266+
PyErr_Format(PyExc_ValueError, "unknown file control 'op': %d", op);
2267+
return NULL;
2268+
}
2269+
2270+
int val = arg;
21952271
int rc;
2196-
long val = arg;
21972272

21982273
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
21992274
return NULL;
22002275
}
22012276

22022277
Py_BEGIN_ALLOW_THREADS
2203-
rc = sqlite3_file_control(self->db, dbname, op, &val);
2278+
rc = sqlite3_file_control(self->db, name, op, &val);
22042279
Py_END_ALLOW_THREADS
22052280

22062281
if (rc != SQLITE_OK) {
@@ -2640,7 +2715,7 @@ static PyMethodDef connection_methods[] = {
26402715
PYSQLITE_CONNECTION_SET_AUTHORIZER_METHODDEF
26412716
PYSQLITE_CONNECTION_SET_PROGRESS_HANDLER_METHODDEF
26422717
PYSQLITE_CONNECTION_SET_TRACE_CALLBACK_METHODDEF
2643-
PYSQLITE_CONNECTION_SET_FILE_CONTROL_METHODDEF
2718+
PYSQLITE_CONNECTION_FILE_CONTROL_METHODDEF
26442719
SETLIMIT_METHODDEF
26452720
GETLIMIT_METHODDEF
26462721
SERIALIZE_METHODDEF

Modules/_sqlite/module.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,8 @@ add_integer_constants(PyObject *module) {
576576
#if SQLITE_VERSION_NUMBER >= 3048000
577577
ADD_INT(SQLITE_FCNTL_NULL_IO);
578578
#endif
579-
579+
// When updating this list, also update PYSQLITE_LAST_VALID_FCNTL in module.h
580+
// and is_int_fcntl in connection.c
580581
#undef ADD_INT
581582
return 0;
582583
}

0 commit comments

Comments
 (0)