gh-103015: Add entrypoint keyword param to sqlite3.Connection.load_extension (#103073)

This commit is contained in:
Erlend E. Aasland 2023-04-26 21:22:03 +02:00 committed by GitHub
parent 28a05f4cc2
commit 222c63fc6b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 105 additions and 15 deletions

View file

@ -1041,12 +1041,25 @@ Connection objects
(2, 'broccoli pie', 'broccoli cheese onions flour') (2, 'broccoli pie', 'broccoli cheese onions flour')
(3, 'pumpkin pie', 'pumpkin sugar flour butter') (3, 'pumpkin pie', 'pumpkin sugar flour butter')
.. method:: load_extension(path, /) .. method:: load_extension(path, /, *, entrypoint=None)
Load an SQLite extension from a shared library located at *path*. Load an SQLite extension from a shared library.
Enable extension loading with :meth:`enable_load_extension` before Enable extension loading with :meth:`enable_load_extension` before
calling this method. calling this method.
:param str path:
The path to the SQLite extension.
:param entrypoint:
Entry point name.
If ``None`` (the default),
SQLite will come up with an entry point name of its own;
see the SQLite docs `Loading an Extension`_ for details.
:type entrypoint: str | None
.. audit-event:: sqlite3.load_extension connection,path sqlite3.Connection.load_extension .. audit-event:: sqlite3.load_extension connection,path sqlite3.Connection.load_extension
.. versionadded:: 3.2 .. versionadded:: 3.2
@ -1054,6 +1067,11 @@ Connection objects
.. versionchanged:: 3.10 .. versionchanged:: 3.10
Added the ``sqlite3.load_extension`` auditing event. Added the ``sqlite3.load_extension`` auditing event.
.. versionadded:: 3.12
The *entrypoint* parameter.
.. _Loading an Extension: https://www.sqlite.org/loadext.html#loading_an_extension_
.. method:: iterdump .. method:: iterdump
Return an :term:`iterator` to dump the database as SQL source code. Return an :term:`iterator` to dump the database as SQL source code.

View file

@ -406,6 +406,11 @@ sqlite3
:ref:`transaction handling <sqlite3-transaction-control-autocommit>`. :ref:`transaction handling <sqlite3-transaction-control-autocommit>`.
(Contributed by Erlend E. Aasland in :gh:`83638`.) (Contributed by Erlend E. Aasland in :gh:`83638`.)
* Add *entrypoint* keyword-only parameter to
:meth:`~sqlite3.Connection.load_extension`,
for overriding the SQLite extension entry point.
(Contributed by Erlend E. Aasland in :gh:`103015`.)
threading threading
--------- ---------

View file

@ -890,6 +890,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(end_lineno)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(end_lineno));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(end_offset)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(end_offset));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(endpos)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(endpos));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(entrypoint));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(env)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(env));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(errors)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(errors));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event));

View file

@ -378,6 +378,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(end_lineno) STRUCT_FOR_ID(end_lineno)
STRUCT_FOR_ID(end_offset) STRUCT_FOR_ID(end_offset)
STRUCT_FOR_ID(endpos) STRUCT_FOR_ID(endpos)
STRUCT_FOR_ID(entrypoint)
STRUCT_FOR_ID(env) STRUCT_FOR_ID(env)
STRUCT_FOR_ID(errors) STRUCT_FOR_ID(errors)
STRUCT_FOR_ID(event) STRUCT_FOR_ID(event)

View file

@ -884,6 +884,7 @@ extern "C" {
INIT_ID(end_lineno), \ INIT_ID(end_lineno), \
INIT_ID(end_offset), \ INIT_ID(end_offset), \
INIT_ID(endpos), \ INIT_ID(endpos), \
INIT_ID(entrypoint), \
INIT_ID(env), \ INIT_ID(env), \
INIT_ID(errors), \ INIT_ID(errors), \
INIT_ID(event), \ INIT_ID(event), \

View file

@ -987,6 +987,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
string = &_Py_ID(endpos); string = &_Py_ID(endpos);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string); _PyUnicode_InternInPlace(interp, &string);
string = &_Py_ID(entrypoint);
assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string);
string = &_Py_ID(env); string = &_Py_ID(env);
assert(_PyUnicode_CheckConsistency(string, 1)); assert(_PyUnicode_CheckConsistency(string, 1));
_PyUnicode_InternInPlace(interp, &string); _PyUnicode_InternInPlace(interp, &string);

View file

@ -0,0 +1,3 @@
Add *entrypoint* keyword-only parameter to
:meth:`sqlite3.Connection.load_extension`, for overriding the SQLite
extension entry point. Patch by Erlend E. Aasland.

View file

@ -846,30 +846,63 @@ exit:
#if defined(PY_SQLITE_ENABLE_LOAD_EXTENSION) #if defined(PY_SQLITE_ENABLE_LOAD_EXTENSION)
PyDoc_STRVAR(pysqlite_connection_load_extension__doc__, PyDoc_STRVAR(pysqlite_connection_load_extension__doc__,
"load_extension($self, name, /)\n" "load_extension($self, name, /, *, entrypoint=None)\n"
"--\n" "--\n"
"\n" "\n"
"Load SQLite extension module."); "Load SQLite extension module.");
#define PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF \ #define PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF \
{"load_extension", (PyCFunction)pysqlite_connection_load_extension, METH_O, pysqlite_connection_load_extension__doc__}, {"load_extension", _PyCFunction_CAST(pysqlite_connection_load_extension), METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_load_extension__doc__},
static PyObject * static PyObject *
pysqlite_connection_load_extension_impl(pysqlite_Connection *self, pysqlite_connection_load_extension_impl(pysqlite_Connection *self,
const char *extension_name); const char *extension_name,
const char *entrypoint);
static PyObject * static PyObject *
pysqlite_connection_load_extension(pysqlite_Connection *self, PyObject *arg) pysqlite_connection_load_extension(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
const char *extension_name; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
if (!PyUnicode_Check(arg)) { #define NUM_KEYWORDS 1
_PyArg_BadArgument("load_extension", "argument", "str", arg); static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_item = { &_Py_ID(entrypoint), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
#else // !Py_BUILD_CORE
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"", "entrypoint", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "load_extension",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
const char *extension_name;
const char *entrypoint = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf);
if (!args) {
goto exit;
}
if (!PyUnicode_Check(args[0])) {
_PyArg_BadArgument("load_extension", "argument 1", "str", args[0]);
goto exit; goto exit;
} }
Py_ssize_t extension_name_length; Py_ssize_t extension_name_length;
extension_name = PyUnicode_AsUTF8AndSize(arg, &extension_name_length); extension_name = PyUnicode_AsUTF8AndSize(args[0], &extension_name_length);
if (extension_name == NULL) { if (extension_name == NULL) {
goto exit; goto exit;
} }
@ -877,7 +910,29 @@ pysqlite_connection_load_extension(pysqlite_Connection *self, PyObject *arg)
PyErr_SetString(PyExc_ValueError, "embedded null character"); PyErr_SetString(PyExc_ValueError, "embedded null character");
goto exit; goto exit;
} }
return_value = pysqlite_connection_load_extension_impl(self, extension_name); if (!noptargs) {
goto skip_optional_kwonly;
}
if (args[1] == Py_None) {
entrypoint = NULL;
}
else if (PyUnicode_Check(args[1])) {
Py_ssize_t entrypoint_length;
entrypoint = PyUnicode_AsUTF8AndSize(args[1], &entrypoint_length);
if (entrypoint == NULL) {
goto exit;
}
if (strlen(entrypoint) != (size_t)entrypoint_length) {
PyErr_SetString(PyExc_ValueError, "embedded null character");
goto exit;
}
}
else {
_PyArg_BadArgument("load_extension", "argument 'entrypoint'", "str or None", args[1]);
goto exit;
}
skip_optional_kwonly:
return_value = pysqlite_connection_load_extension_impl(self, extension_name, entrypoint);
exit: exit:
return return_value; return return_value;
@ -1532,4 +1587,4 @@ exit:
#ifndef DESERIALIZE_METHODDEF #ifndef DESERIALIZE_METHODDEF
#define DESERIALIZE_METHODDEF #define DESERIALIZE_METHODDEF
#endif /* !defined(DESERIALIZE_METHODDEF) */ #endif /* !defined(DESERIALIZE_METHODDEF) */
/*[clinic end generated code: output=f10306e10427488b input=a9049054013a1b77]*/ /*[clinic end generated code: output=833f0e27cd3a4560 input=a9049054013a1b77]*/

View file

@ -1601,14 +1601,17 @@ _sqlite3.Connection.load_extension as pysqlite_connection_load_extension
name as extension_name: str name as extension_name: str
/ /
*
entrypoint: str(accept={str, NoneType}) = None
Load SQLite extension module. Load SQLite extension module.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
pysqlite_connection_load_extension_impl(pysqlite_Connection *self, pysqlite_connection_load_extension_impl(pysqlite_Connection *self,
const char *extension_name) const char *extension_name,
/*[clinic end generated code: output=47eb1d7312bc97a7 input=edd507389d89d621]*/ const char *entrypoint)
/*[clinic end generated code: output=7e61a7add9de0286 input=c36b14ea702e04f5]*/
{ {
int rc; int rc;
char* errmsg; char* errmsg;
@ -1621,7 +1624,7 @@ pysqlite_connection_load_extension_impl(pysqlite_Connection *self,
return NULL; return NULL;
} }
rc = sqlite3_load_extension(self->db, extension_name, 0, &errmsg); rc = sqlite3_load_extension(self->db, extension_name, entrypoint, &errmsg);
if (rc != 0) { if (rc != 0) {
PyErr_SetString(self->OperationalError, errmsg); PyErr_SetString(self->OperationalError, errmsg);
return NULL; return NULL;