Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
sqlite3_file_control
  • Loading branch information
hashbrowncipher committed Jan 5, 2025
commit e32c3729d318dc9dde5ebfd6a8f7a10fe2848ea5
27 changes: 27 additions & 0 deletions Lib/test/test_sqlite3/test_dbapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import sqlite3 as sqlite
import subprocess
import sys
import tempfile
import threading
import unittest
import urllib.parse
Expand Down Expand Up @@ -735,6 +736,30 @@ def test_database_keyword(self):
with contextlib.closing(sqlite.connect(database=":memory:")) as cx:
self.assertEqual(type(cx), sqlite.Connection)

def test_wal_preservation(self):
with tempfile.TemporaryDirectory() as dirname:
path = os.path.join(dirname, "db.sqlite")
with contextlib.closing(sqlite.connect(path)) as cx:
cx.set_file_control(sqlite.SQLITE_FCNTL_PERSIST_WAL, 1)
cu = cx.cursor()
cu.execute("PRAGMA journal_mode = WAL")
cu.execute("CREATE TABLE foo (id int)")
cu.execute("INSERT INTO foo (id) VALUES (1)")
self.assertTrue(os.path.exists(path + "-wal"))
self.assertTrue(os.path.exists(path + "-wal"))

with contextlib.closing(sqlite.connect(path)) as cx:
cu = cx.cursor()
self.assertTrue(os.path.exists(path + "-wal"))
cu.execute("INSERT INTO foo (id) VALUES (2)")
self.assertFalse(os.path.exists(path + "-wal"))


def test_file_control_raises(self):
with contextlib.closing(sqlite.connect(database=":memory:")) as cx:
with self.assertRaises(sqlite.ProgrammingError):
cx.set_file_control(sqlite.SQLITE_FCNTL_PERSIST_WAL, 1)


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




@requires_subprocess()
class MultiprocessTests(unittest.TestCase):
CONNECTION_TIMEOUT = 0 # Disable the busy timeout.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +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`_.
93 changes: 92 additions & 1 deletion Modules/_sqlite/clinic/connection.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 40 additions & 0 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -2173,6 +2173,45 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
Py_RETURN_NONE;
}

/*[clinic input]
_sqlite3.Connection.set_file_control as pysqlite_connection_set_file_control

op: int
a SQLITE_FCNTL_ constant
arg: long
argument to pass
/
dbname: str = NULL
database name

Invoke a file control method on the database.
[clinic start generated code]*/

static PyObject *
pysqlite_connection_set_file_control_impl(pysqlite_Connection *self, int op,
long arg, const char *dbname)
/*[clinic end generated code: output=d9d2d311892893b6 input=0253798d9514fea2]*/
{
int rc;
long val = arg;

if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
return NULL;
}

Py_BEGIN_ALLOW_THREADS
rc = sqlite3_file_control(self->db, dbname, op, &val);
Py_END_ALLOW_THREADS

if (rc != SQLITE_OK) {
PyErr_SetString(self->ProgrammingError, sqlite3_errstr(rc));
return NULL;
}

return PyLong_FromLong(val);
}


#ifdef PY_SQLITE_HAVE_SERIALIZE
/*[clinic input]
_sqlite3.Connection.serialize as serialize
Expand Down Expand Up @@ -2601,6 +2640,7 @@ static PyMethodDef connection_methods[] = {
PYSQLITE_CONNECTION_SET_AUTHORIZER_METHODDEF
PYSQLITE_CONNECTION_SET_PROGRESS_HANDLER_METHODDEF
PYSQLITE_CONNECTION_SET_TRACE_CALLBACK_METHODDEF
PYSQLITE_CONNECTION_SET_FILE_CONTROL_METHODDEF
SETLIMIT_METHODDEF
GETLIMIT_METHODDEF
SERIALIZE_METHODDEF
Expand Down
42 changes: 42 additions & 0 deletions Modules/_sqlite/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,48 @@ add_integer_constants(PyObject *module) {
ADD_INT(SQLITE_DBCONFIG_LEGACY_FILE_FORMAT);
ADD_INT(SQLITE_DBCONFIG_TRUSTED_SCHEMA);
#endif
ADD_INT(SQLITE_FCNTL_LOCKSTATE);
ADD_INT(SQLITE_FCNTL_GET_LOCKPROXYFILE);
ADD_INT(SQLITE_FCNTL_SET_LOCKPROXYFILE);
ADD_INT(SQLITE_FCNTL_LAST_ERRNO);
ADD_INT(SQLITE_FCNTL_SIZE_HINT);
ADD_INT(SQLITE_FCNTL_CHUNK_SIZE);
ADD_INT(SQLITE_FCNTL_FILE_POINTER);
ADD_INT(SQLITE_FCNTL_SYNC_OMITTED);
ADD_INT(SQLITE_FCNTL_WIN32_AV_RETRY);
ADD_INT(SQLITE_FCNTL_PERSIST_WAL);
ADD_INT(SQLITE_FCNTL_OVERWRITE);
ADD_INT(SQLITE_FCNTL_VFSNAME);
ADD_INT(SQLITE_FCNTL_POWERSAFE_OVERWRITE);
ADD_INT(SQLITE_FCNTL_PRAGMA);
ADD_INT(SQLITE_FCNTL_BUSYHANDLER);
ADD_INT(SQLITE_FCNTL_TEMPFILENAME);
ADD_INT(SQLITE_FCNTL_MMAP_SIZE);
ADD_INT(SQLITE_FCNTL_TRACE);
ADD_INT(SQLITE_FCNTL_HAS_MOVED);
ADD_INT(SQLITE_FCNTL_SYNC);
ADD_INT(SQLITE_FCNTL_COMMIT_PHASETWO);
ADD_INT(SQLITE_FCNTL_WIN32_SET_HANDLE);
ADD_INT(SQLITE_FCNTL_WAL_BLOCK);
ADD_INT(SQLITE_FCNTL_ZIPVFS);
ADD_INT(SQLITE_FCNTL_RBU);
ADD_INT(SQLITE_FCNTL_VFS_POINTER);
ADD_INT(SQLITE_FCNTL_JOURNAL_POINTER);
ADD_INT(SQLITE_FCNTL_WIN32_GET_HANDLE);
ADD_INT(SQLITE_FCNTL_PDB);
ADD_INT(SQLITE_FCNTL_BEGIN_ATOMIC_WRITE);
ADD_INT(SQLITE_FCNTL_COMMIT_ATOMIC_WRITE);
ADD_INT(SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE);
ADD_INT(SQLITE_FCNTL_LOCK_TIMEOUT);
ADD_INT(SQLITE_FCNTL_DATA_VERSION);
ADD_INT(SQLITE_FCNTL_SIZE_LIMIT);
ADD_INT(SQLITE_FCNTL_CKPT_DONE);
ADD_INT(SQLITE_FCNTL_RESERVE_BYTES);
ADD_INT(SQLITE_FCNTL_CKPT_START);
ADD_INT(SQLITE_FCNTL_EXTERNAL_READER);
ADD_INT(SQLITE_FCNTL_CKSM_FILE);
ADD_INT(SQLITE_FCNTL_RESET_CACHE);

#undef ADD_INT
return 0;
}
Expand Down