diff options
author | Erlend Egeberg Aasland <erlend.aasland@innova.no> | 2021-10-19 13:44:45 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-19 13:44:45 (GMT) |
commit | 09c04e7f0d26f0006964554b6a0caa5ef7f0bd24 (patch) | |
tree | 9c2bb61a1e804cec7e06245eaf68824d56536455 | |
parent | 8702b667d8e7da7a1888297d84f493f26c580a2d (diff) | |
download | cpython-09c04e7f0d26f0006964554b6a0caa5ef7f0bd24.zip cpython-09c04e7f0d26f0006964554b6a0caa5ef7f0bd24.tar.gz cpython-09c04e7f0d26f0006964554b6a0caa5ef7f0bd24.tar.bz2 |
bpo-42064: Add module backref to `sqlite3` callback context (GH-28242)
-rw-r--r-- | Modules/_sqlite/clinic/connection.c.h | 154 | ||||
-rw-r--r-- | Modules/_sqlite/connection.c | 61 | ||||
-rw-r--r-- | Modules/_sqlite/connection.h | 1 |
3 files changed, 91 insertions, 125 deletions
diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h index bf5a58d..e9e3064 100644 --- a/Modules/_sqlite/clinic/connection.c.h +++ b/Modules/_sqlite/clinic/connection.c.h @@ -204,57 +204,30 @@ PyDoc_STRVAR(pysqlite_connection_create_function__doc__, "Creates a new function. Non-standard."); #define PYSQLITE_CONNECTION_CREATE_FUNCTION_METHODDEF \ - {"create_function", (PyCFunction)(void(*)(void))pysqlite_connection_create_function, METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_create_function__doc__}, + {"create_function", (PyCFunction)(void(*)(void))pysqlite_connection_create_function, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_create_function__doc__}, static PyObject * pysqlite_connection_create_function_impl(pysqlite_Connection *self, - const char *name, int narg, - PyObject *func, int deterministic); + PyTypeObject *cls, const char *name, + int narg, PyObject *func, + int deterministic); static PyObject * -pysqlite_connection_create_function(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +pysqlite_connection_create_function(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; static const char * const _keywords[] = {"name", "narg", "func", "deterministic", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "create_function", 0}; - PyObject *argsbuf[4]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3; + static _PyArg_Parser _parser = {"siO|$p:create_function", _keywords, 0}; const char *name; int narg; PyObject *func; int deterministic = 0; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); - if (!args) { - goto exit; - } - if (!PyUnicode_Check(args[0])) { - _PyArg_BadArgument("create_function", "argument 'name'", "str", args[0]); - goto exit; - } - Py_ssize_t name_length; - name = PyUnicode_AsUTF8AndSize(args[0], &name_length); - if (name == NULL) { + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &name, &narg, &func, &deterministic)) { goto exit; } - if (strlen(name) != (size_t)name_length) { - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } - narg = _PyLong_AsInt(args[1]); - if (narg == -1 && PyErr_Occurred()) { - goto exit; - } - func = args[2]; - if (!noptargs) { - goto skip_optional_kwonly; - } - deterministic = PyObject_IsTrue(args[3]); - if (deterministic < 0) { - goto exit; - } -skip_optional_kwonly: - return_value = pysqlite_connection_create_function_impl(self, name, narg, func, deterministic); + return_value = pysqlite_connection_create_function_impl(self, cls, name, narg, func, deterministic); exit: return return_value; @@ -267,47 +240,29 @@ PyDoc_STRVAR(pysqlite_connection_create_aggregate__doc__, "Creates a new aggregate. Non-standard."); #define PYSQLITE_CONNECTION_CREATE_AGGREGATE_METHODDEF \ - {"create_aggregate", (PyCFunction)(void(*)(void))pysqlite_connection_create_aggregate, METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_create_aggregate__doc__}, + {"create_aggregate", (PyCFunction)(void(*)(void))pysqlite_connection_create_aggregate, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_create_aggregate__doc__}, static PyObject * pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self, + PyTypeObject *cls, const char *name, int n_arg, PyObject *aggregate_class); static PyObject * -pysqlite_connection_create_aggregate(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +pysqlite_connection_create_aggregate(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; static const char * const _keywords[] = {"name", "n_arg", "aggregate_class", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "create_aggregate", 0}; - PyObject *argsbuf[3]; + static _PyArg_Parser _parser = {"siO:create_aggregate", _keywords, 0}; const char *name; int n_arg; PyObject *aggregate_class; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); - if (!args) { - goto exit; - } - if (!PyUnicode_Check(args[0])) { - _PyArg_BadArgument("create_aggregate", "argument 'name'", "str", args[0]); - goto exit; - } - Py_ssize_t name_length; - name = PyUnicode_AsUTF8AndSize(args[0], &name_length); - if (name == NULL) { + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &name, &n_arg, &aggregate_class)) { goto exit; } - if (strlen(name) != (size_t)name_length) { - PyErr_SetString(PyExc_ValueError, "embedded null character"); - goto exit; - } - n_arg = _PyLong_AsInt(args[1]); - if (n_arg == -1 && PyErr_Occurred()) { - goto exit; - } - aggregate_class = args[2]; - return_value = pysqlite_connection_create_aggregate_impl(self, name, n_arg, aggregate_class); + return_value = pysqlite_connection_create_aggregate_impl(self, cls, name, n_arg, aggregate_class); exit: return return_value; @@ -320,27 +275,26 @@ PyDoc_STRVAR(pysqlite_connection_set_authorizer__doc__, "Sets authorizer callback. Non-standard."); #define PYSQLITE_CONNECTION_SET_AUTHORIZER_METHODDEF \ - {"set_authorizer", (PyCFunction)(void(*)(void))pysqlite_connection_set_authorizer, METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_authorizer__doc__}, + {"set_authorizer", (PyCFunction)(void(*)(void))pysqlite_connection_set_authorizer, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_authorizer__doc__}, static PyObject * pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self, + PyTypeObject *cls, PyObject *callable); static PyObject * -pysqlite_connection_set_authorizer(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +pysqlite_connection_set_authorizer(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; static const char * const _keywords[] = {"authorizer_callback", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "set_authorizer", 0}; - PyObject *argsbuf[1]; + static _PyArg_Parser _parser = {"O:set_authorizer", _keywords, 0}; PyObject *callable; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); - if (!args) { + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &callable)) { goto exit; } - callable = args[0]; - return_value = pysqlite_connection_set_authorizer_impl(self, callable); + return_value = pysqlite_connection_set_authorizer_impl(self, cls, callable); exit: return return_value; @@ -353,32 +307,27 @@ PyDoc_STRVAR(pysqlite_connection_set_progress_handler__doc__, "Sets progress handler callback. Non-standard."); #define PYSQLITE_CONNECTION_SET_PROGRESS_HANDLER_METHODDEF \ - {"set_progress_handler", (PyCFunction)(void(*)(void))pysqlite_connection_set_progress_handler, METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_progress_handler__doc__}, + {"set_progress_handler", (PyCFunction)(void(*)(void))pysqlite_connection_set_progress_handler, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_progress_handler__doc__}, static PyObject * pysqlite_connection_set_progress_handler_impl(pysqlite_Connection *self, + PyTypeObject *cls, PyObject *callable, int n); static PyObject * -pysqlite_connection_set_progress_handler(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +pysqlite_connection_set_progress_handler(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; static const char * const _keywords[] = {"progress_handler", "n", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "set_progress_handler", 0}; - PyObject *argsbuf[2]; + static _PyArg_Parser _parser = {"Oi:set_progress_handler", _keywords, 0}; PyObject *callable; int n; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); - if (!args) { - goto exit; - } - callable = args[0]; - n = _PyLong_AsInt(args[1]); - if (n == -1 && PyErr_Occurred()) { + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &callable, &n)) { goto exit; } - return_value = pysqlite_connection_set_progress_handler_impl(self, callable, n); + return_value = pysqlite_connection_set_progress_handler_impl(self, cls, callable, n); exit: return return_value; @@ -393,27 +342,26 @@ PyDoc_STRVAR(pysqlite_connection_set_trace_callback__doc__, "Non-standard."); #define PYSQLITE_CONNECTION_SET_TRACE_CALLBACK_METHODDEF \ - {"set_trace_callback", (PyCFunction)(void(*)(void))pysqlite_connection_set_trace_callback, METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_trace_callback__doc__}, + {"set_trace_callback", (PyCFunction)(void(*)(void))pysqlite_connection_set_trace_callback, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_trace_callback__doc__}, static PyObject * pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self, + PyTypeObject *cls, PyObject *callable); static PyObject * -pysqlite_connection_set_trace_callback(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +pysqlite_connection_set_trace_callback(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; static const char * const _keywords[] = {"trace_callback", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "set_trace_callback", 0}; - PyObject *argsbuf[1]; + static _PyArg_Parser _parser = {"O:set_trace_callback", _keywords, 0}; PyObject *callable; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); - if (!args) { + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &callable)) { goto exit; } - callable = args[0]; - return_value = pysqlite_connection_set_trace_callback_impl(self, callable); + return_value = pysqlite_connection_set_trace_callback_impl(self, cls, callable); exit: return return_value; @@ -720,38 +668,28 @@ PyDoc_STRVAR(pysqlite_connection_create_collation__doc__, "Creates a collation function. Non-standard."); #define PYSQLITE_CONNECTION_CREATE_COLLATION_METHODDEF \ - {"create_collation", (PyCFunction)(void(*)(void))pysqlite_connection_create_collation, METH_FASTCALL, pysqlite_connection_create_collation__doc__}, + {"create_collation", (PyCFunction)(void(*)(void))pysqlite_connection_create_collation, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_create_collation__doc__}, static PyObject * pysqlite_connection_create_collation_impl(pysqlite_Connection *self, + PyTypeObject *cls, const char *name, PyObject *callable); static PyObject * -pysqlite_connection_create_collation(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) +pysqlite_connection_create_collation(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + static const char * const _keywords[] = {"", "", NULL}; + static _PyArg_Parser _parser = {"sO:create_collation", _keywords, 0}; const char *name; PyObject *callable; - if (!_PyArg_CheckPositional("create_collation", nargs, 2, 2)) { - goto exit; - } - if (!PyUnicode_Check(args[0])) { - _PyArg_BadArgument("create_collation", "argument 1", "str", args[0]); - goto exit; - } - Py_ssize_t name_length; - name = PyUnicode_AsUTF8AndSize(args[0], &name_length); - if (name == NULL) { - goto exit; - } - if (strlen(name) != (size_t)name_length) { - PyErr_SetString(PyExc_ValueError, "embedded null character"); + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &name, &callable)) { goto exit; } - callable = args[1]; - return_value = pysqlite_connection_create_collation_impl(self, name, callable); + return_value = pysqlite_connection_create_collation_impl(self, cls, name, callable); exit: return return_value; @@ -819,4 +757,4 @@ exit: #ifndef PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF #define PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF #endif /* !defined(PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF) */ -/*[clinic end generated code: output=5b7268875f33c016 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7567e5d716309258 input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index d6d1fa8..e94c4cb 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -256,6 +256,7 @@ pysqlite_do_all_statements(pysqlite_Connection *self) do { \ if (ctx) { \ Py_VISIT(ctx->callable); \ + Py_VISIT(ctx->module); \ } \ } while (0) @@ -280,6 +281,7 @@ clear_callback_context(callback_context *ctx) { if (ctx != NULL) { Py_CLEAR(ctx->callable); + Py_CLEAR(ctx->module); } } @@ -822,13 +824,21 @@ static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self) Py_SETREF(self->cursors, new_list); } +/* Allocate a UDF/callback context structure. In order to ensure that the state + * pointer always outlives the callback context, we make sure it owns a + * reference to the module itself. create_callback_context() is always called + * from connection methods, so we use the defining class to fetch the module + * pointer. + */ static callback_context * -create_callback_context(pysqlite_state *state, PyObject *callable) +create_callback_context(PyTypeObject *cls, PyObject *callable) { callback_context *ctx = PyMem_Malloc(sizeof(callback_context)); if (ctx != NULL) { + PyObject *module = PyType_GetModule(cls); ctx->callable = Py_NewRef(callable); - ctx->state = state; + ctx->module = Py_NewRef(module); + ctx->state = pysqlite_get_state(module); } return ctx; } @@ -838,6 +848,7 @@ free_callback_context(callback_context *ctx) { assert(ctx != NULL); Py_XDECREF(ctx->callable); + Py_XDECREF(ctx->module); PyMem_Free(ctx); } @@ -867,6 +878,8 @@ destructor_callback(void *ctx) /*[clinic input] _sqlite3.Connection.create_function as pysqlite_connection_create_function + cls: defining_class + / name: str narg: int func: object @@ -878,9 +891,10 @@ Creates a new function. Non-standard. static PyObject * pysqlite_connection_create_function_impl(pysqlite_Connection *self, - const char *name, int narg, - PyObject *func, int deterministic) -/*[clinic end generated code: output=07d1877dd98c0308 input=f2edcf073e815beb]*/ + PyTypeObject *cls, const char *name, + int narg, PyObject *func, + int deterministic) +/*[clinic end generated code: output=8a811529287ad240 input=f0f99754bfeafd8d]*/ { int rc; int flags = SQLITE_UTF8; @@ -903,7 +917,7 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self, flags |= SQLITE_DETERMINISTIC; #endif } - callback_context *ctx = create_callback_context(self->state, func); + callback_context *ctx = create_callback_context(cls, func); if (ctx == NULL) { return NULL; } @@ -924,6 +938,8 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self, /*[clinic input] _sqlite3.Connection.create_aggregate as pysqlite_connection_create_aggregate + cls: defining_class + / name: str n_arg: int aggregate_class: object @@ -933,9 +949,10 @@ Creates a new aggregate. Non-standard. static PyObject * pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self, + PyTypeObject *cls, const char *name, int n_arg, PyObject *aggregate_class) -/*[clinic end generated code: output=fbb2f858cfa4d8db input=c2e13bbf234500a5]*/ +/*[clinic end generated code: output=1b02d0f0aec7ff96 input=bd527067e6c2e33f]*/ { int rc; @@ -943,8 +960,7 @@ pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self, return NULL; } - callback_context *ctx = create_callback_context(self->state, - aggregate_class); + callback_context *ctx = create_callback_context(cls, aggregate_class); if (ctx == NULL) { return NULL; } @@ -1075,6 +1091,8 @@ trace_callback(void *ctx, const char *statement_string) /*[clinic input] _sqlite3.Connection.set_authorizer as pysqlite_connection_set_authorizer + cls: defining_class + / authorizer_callback as callable: object Sets authorizer callback. Non-standard. @@ -1082,8 +1100,9 @@ Sets authorizer callback. Non-standard. static PyObject * pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self, + PyTypeObject *cls, PyObject *callable) -/*[clinic end generated code: output=c193601e9e8a5116 input=ec104f130b82050b]*/ +/*[clinic end generated code: output=75fa60114fc971c3 input=9f3e90d3d642c4a0]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -1095,7 +1114,7 @@ pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self, set_callback_context(&self->authorizer_ctx, NULL); } else { - callback_context *ctx = create_callback_context(self->state, callable); + callback_context *ctx = create_callback_context(cls, callable); if (ctx == NULL) { return NULL; } @@ -1114,6 +1133,8 @@ pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self, /*[clinic input] _sqlite3.Connection.set_progress_handler as pysqlite_connection_set_progress_handler + cls: defining_class + / progress_handler as callable: object n: int @@ -1122,8 +1143,9 @@ Sets progress handler callback. Non-standard. static PyObject * pysqlite_connection_set_progress_handler_impl(pysqlite_Connection *self, + PyTypeObject *cls, PyObject *callable, int n) -/*[clinic end generated code: output=ba14008a483d7a53 input=3cf56d045f130a84]*/ +/*[clinic end generated code: output=0739957fd8034a50 input=83e8dcbb4ce183f7]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -1135,7 +1157,7 @@ pysqlite_connection_set_progress_handler_impl(pysqlite_Connection *self, set_callback_context(&self->progress_ctx, NULL); } else { - callback_context *ctx = create_callback_context(self->state, callable); + callback_context *ctx = create_callback_context(cls, callable); if (ctx == NULL) { return NULL; } @@ -1148,6 +1170,8 @@ pysqlite_connection_set_progress_handler_impl(pysqlite_Connection *self, /*[clinic input] _sqlite3.Connection.set_trace_callback as pysqlite_connection_set_trace_callback + cls: defining_class + / trace_callback as callable: object Sets a trace callback called for each SQL statement (passed as unicode). @@ -1157,8 +1181,9 @@ Non-standard. static PyObject * pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self, + PyTypeObject *cls, PyObject *callable) -/*[clinic end generated code: output=c9fd551e359165d3 input=d76eabbb633057bc]*/ +/*[clinic end generated code: output=d91048c03bfcee05 input=96f03acec3ec8044]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -1180,7 +1205,7 @@ pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self, set_callback_context(&self->trace_ctx, NULL); } else { - callback_context *ctx = create_callback_context(self->state, callable); + callback_context *ctx = create_callback_context(cls, callable); if (ctx == NULL) { return NULL; } @@ -1742,6 +1767,7 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self, /*[clinic input] _sqlite3.Connection.create_collation as pysqlite_connection_create_collation + cls: defining_class name: str callback as callable: object / @@ -1751,9 +1777,10 @@ Creates a collation function. Non-standard. static PyObject * pysqlite_connection_create_collation_impl(pysqlite_Connection *self, + PyTypeObject *cls, const char *name, PyObject *callable) -/*[clinic end generated code: output=a4ceaff957fdef9a input=301647aab0f2fb1d]*/ +/*[clinic end generated code: output=32d339e97869c378 input=fee2c8e5708602ad]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -1771,7 +1798,7 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self, PyErr_SetString(PyExc_TypeError, "parameter must be callable"); return NULL; } - ctx = create_callback_context(self->state, callable); + ctx = create_callback_context(cls, callable); if (ctx == NULL) { return NULL; } diff --git a/Modules/_sqlite/connection.h b/Modules/_sqlite/connection.h index c4cec85..6a2aa1c 100644 --- a/Modules/_sqlite/connection.h +++ b/Modules/_sqlite/connection.h @@ -35,6 +35,7 @@ typedef struct _callback_context { PyObject *callable; + PyObject *module; pysqlite_state *state; } callback_context; |