Skip to content

Commit dfce455

Browse files
gh-103489: Add get/set config methods to sqlite3.Connection
1 parent 2b6e877 commit dfce455

File tree

6 files changed

+352
-1
lines changed

6 files changed

+352
-1
lines changed

Doc/library/sqlite3.rst

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,35 @@ Module constants
573573
package, a third-party library which used to upstream changes to
574574
:mod:`!sqlite3`. Today, it carries no meaning or practical value.
575575

576+
.. _sqlite3-dbconfig-constants
577+
578+
.. data:: SQLITE_DBCONFIG_DEFENSIVE
579+
SQLITE_DBCONFIG_DQS_DDL
580+
SQLITE_DBCONFIG_DQS_DML
581+
SQLITE_DBCONFIG_ENABLE_FKEY
582+
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
583+
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
584+
SQLITE_DBCONFIG_ENABLE_QPSG
585+
SQLITE_DBCONFIG_ENABLE_TRIGGER
586+
SQLITE_DBCONFIG_ENABLE_VIEW
587+
SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
588+
SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
589+
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
590+
SQLITE_DBCONFIG_RESET_DATABASE
591+
SQLITE_DBCONFIG_TRIGGER_EQP
592+
SQLITE_DBCONFIG_TRUSTED_SCHEMA
593+
SQLITE_DBCONFIG_WRITABLE_SCHEMA
594+
595+
These constants are used for the :meth:Connection.setconfig:
596+
and :meth:~Connection.getconfig: methods.
597+
598+
..versionadded:: 3.12
599+
600+
..seealso::
601+
602+
https://www.sqlite.org/c3ref/c_dbconfig_defensive.html
603+
SQLite docs: Database Connection Configuration Options
604+
576605

577606
.. _sqlite3-connection-objects:
578607

@@ -1201,6 +1230,30 @@ Connection objects
12011230
.. _SQLite limit category: https://www.sqlite.org/c3ref/c_limit_attached.html
12021231

12031232

1233+
.. method:: getconfig(op, /)
1234+
1235+
Query a boolean connection configuration option.
1236+
1237+
:param int op:
1238+
A :ref:`SQLITE_DBCONFIG code <sqlite3-dbconfig-constants>`.
1239+
1240+
:rtype: bool
1241+
1242+
.. versionadded:: 3.12
1243+
1244+
.. method:: setconfig(op, enable, /)
1245+
1246+
Set a boolean connection configuration option.
1247+
1248+
:param int op:
1249+
A :ref:`SQLITE_DBCONFIG code <sqlite3-dbconfig-constants>`.
1250+
1251+
:param bool enable:
1252+
``True`` if the configuration option should be enabled;
1253+
``False`` if it should be disabled.
1254+
1255+
.. versionadded:: 3.12
1256+
12041257
.. method:: serialize(*, name="main")
12051258

12061259
Serialize a database into a :class:`bytes` object. For an

Doc/whatsnew/3.12.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,11 @@ sqlite3
384384
:ref:`transaction handling <sqlite3-transaction-control-autocommit>`.
385385
(Contributed by Erlend E. Aasland in :gh:`83638`.)
386386

387+
* Add :meth:`~sqlite3.Connection.getconfig` and
388+
:meth:`~sqlite3.Connection.setconfig` to :class:`~sqlite3.Connection`
389+
to make configuration changes to a database connection.
390+
(Contributed by Erlend E. Aasland in :gh:`103489`.)
391+
387392
threading
388393
---------
389394

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add :meth:`~sqlite3.Connection.getconfig` and
2+
:meth:`~sqlite3.Connection.setconfig` to :class:`~sqlite3.Connection` to
3+
make configuration changes to a database connection. Patch by Erlend E.
4+
Aasland.

Modules/_sqlite/clinic/connection.c.h

Lines changed: 133 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: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include "prepare_protocol.h"
3131
#include "util.h"
3232

33+
#include <stdbool.h>
34+
3335
#if SQLITE_VERSION_NUMBER >= 3014000
3436
#define HAVE_TRACE_V2
3537
#endif
@@ -2340,6 +2342,116 @@ getlimit_impl(pysqlite_Connection *self, int category)
23402342
return setlimit_impl(self, category, -1);
23412343
}
23422344

2345+
static inline bool
2346+
is_int_config(const int op)
2347+
{
2348+
switch (op) {
2349+
case SQLITE_DBCONFIG_ENABLE_FKEY:
2350+
case SQLITE_DBCONFIG_ENABLE_TRIGGER:
2351+
#if SQLITE_VERSION_NUMBER >= 3012002
2352+
case SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER:
2353+
#endif
2354+
#if SQLITE_VERSION_NUMBER >= 3013000
2355+
case SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION:
2356+
#endif
2357+
#if SQLITE_VERSION_NUMBER >= 3016000
2358+
case SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE:
2359+
#endif
2360+
#if SQLITE_VERSION_NUMBER >= 3020000
2361+
case SQLITE_DBCONFIG_ENABLE_QPSG:
2362+
#endif
2363+
#if SQLITE_VERSION_NUMBER >= 3022000
2364+
case SQLITE_DBCONFIG_TRIGGER_EQP:
2365+
#endif
2366+
#if SQLITE_VERSION_NUMBER >= 3024000
2367+
case SQLITE_DBCONFIG_RESET_DATABASE:
2368+
#endif
2369+
#if SQLITE_VERSION_NUMBER >= 3026000
2370+
case SQLITE_DBCONFIG_DEFENSIVE:
2371+
#endif
2372+
#if SQLITE_VERSION_NUMBER >= 3028000
2373+
case SQLITE_DBCONFIG_WRITABLE_SCHEMA:
2374+
#endif
2375+
#if SQLITE_VERSION_NUMBER >= 3029000
2376+
case SQLITE_DBCONFIG_DQS_DDL:
2377+
case SQLITE_DBCONFIG_DQS_DML:
2378+
case SQLITE_DBCONFIG_LEGACY_ALTER_TABLE:
2379+
#endif
2380+
#if SQLITE_VERSION_NUMBER >= 3030000
2381+
case SQLITE_DBCONFIG_ENABLE_VIEW:
2382+
#endif
2383+
#if SQLITE_VERSION_NUMBER >= 3031000
2384+
case SQLITE_DBCONFIG_LEGACY_FILE_FORMAT:
2385+
case SQLITE_DBCONFIG_TRUSTED_SCHEMA:
2386+
#endif
2387+
return true;
2388+
default:
2389+
return false;
2390+
}
2391+
}
2392+
2393+
/*[clinic input]
2394+
_sqlite3.Connection.setconfig as setconfig
2395+
2396+
op: int
2397+
The configuration verb; one of the sqlite3.SQLITE_DBCONFIG codes.
2398+
enable: bool
2399+
2400+
[clinic start generated code]*/
2401+
2402+
static PyObject *
2403+
setconfig_impl(pysqlite_Connection *self, int op, int enable)
2404+
/*[clinic end generated code: output=c60b13e618aff873 input=8c600361bffbfc02]*/
2405+
{
2406+
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
2407+
return NULL;
2408+
}
2409+
if (!is_int_config(op)) {
2410+
return PyErr_Format(PyExc_ValueError,
2411+
"unsupported config 'op': %d", op);
2412+
}
2413+
2414+
int actual;
2415+
int rc = sqlite3_db_config(self->db, op, enable, &actual);
2416+
if (rc != SQLITE_OK) {
2417+
(void)_pysqlite_seterror(self->state, self->db);
2418+
return NULL;
2419+
}
2420+
if (enable != actual) {
2421+
PyErr_SetString(self->state->OperationalError, "Unable to set config");
2422+
return NULL;
2423+
}
2424+
Py_RETURN_NONE;
2425+
}
2426+
2427+
/*[clinic input]
2428+
_sqlite3.Connection.getconfig as getconfig -> bool
2429+
2430+
op: int
2431+
The configuration verb; one of the sqlite3.SQLITE_DBCONFIG codes.
2432+
2433+
[clinic start generated code]*/
2434+
2435+
static int
2436+
getconfig_impl(pysqlite_Connection *self, int op)
2437+
/*[clinic end generated code: output=25ac05044c7b78a3 input=91d2415857d51d89]*/
2438+
{
2439+
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
2440+
return -1;
2441+
}
2442+
if (!is_int_config(op)) {
2443+
PyErr_Format(PyExc_ValueError, "unsupported config 'op': %d", op);
2444+
return -1;
2445+
}
2446+
2447+
int current;
2448+
int rc = sqlite3_db_config(self->db, op, -1, &current);
2449+
if (rc != SQLITE_OK) {
2450+
(void)_pysqlite_seterror(self->state, self->db);
2451+
return -1;
2452+
}
2453+
return current;
2454+
}
23432455

23442456
static PyObject *
23452457
get_autocommit(pysqlite_Connection *self, void *Py_UNUSED(ctx))
@@ -2421,6 +2533,8 @@ static PyMethodDef connection_methods[] = {
24212533
DESERIALIZE_METHODDEF
24222534
CREATE_WINDOW_FUNCTION_METHODDEF
24232535
BLOBOPEN_METHODDEF
2536+
SETCONFIG_METHODDEF
2537+
GETCONFIG_METHODDEF
24242538
{NULL, NULL}
24252539
};
24262540

0 commit comments

Comments
 (0)