From: Erlend Egeberg Aasland Date: Tue, 27 Jul 2021 13:54:20 +0000 (+0200) Subject: bpo-42064: Migrate to `sqlite3_create_collation_v2` (GH-27156) X-Git-Tag: v3.11.0a1~558 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=890e22957d427ee994b85d62dfe4d5a7cbd34ec5;p=thirdparty%2FPython%2Fcpython.git bpo-42064: Migrate to `sqlite3_create_collation_v2` (GH-27156) This implies that SQLite now takes care of destroying the callback context (the PyObject callable it has been passed), so we can strip the collation dict from the connection object. --- diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 33d3d4cfbd15..af093c3319c8 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -177,11 +177,6 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, self->function_pinboard_progress_handler = NULL; self->function_pinboard_authorizer_cb = NULL; - Py_XSETREF(self->collations, PyDict_New()); - if (!self->collations) { - return -1; - } - pysqlite_state *state = pysqlite_get_state(NULL); self->Warning = state->Warning; self->Error = state->Error; @@ -249,7 +244,6 @@ connection_traverse(pysqlite_Connection *self, visitproc visit, void *arg) Py_VISIT(self->function_pinboard_trace_callback); Py_VISIT(self->function_pinboard_progress_handler); Py_VISIT(self->function_pinboard_authorizer_cb); - Py_VISIT(self->collations); return 0; } @@ -265,7 +259,6 @@ connection_clear(pysqlite_Connection *self) Py_CLEAR(self->function_pinboard_trace_callback); Py_CLEAR(self->function_pinboard_progress_handler); Py_CLEAR(self->function_pinboard_authorizer_cb); - Py_CLEAR(self->collations); return 0; } @@ -1780,29 +1773,29 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self, if (!uppercase_name_str) goto finally; - if (callable != Py_None && !PyCallable_Check(callable)) { - PyErr_SetString(PyExc_TypeError, "parameter must be callable"); - goto finally; + int flags = SQLITE_UTF8; + if (callable == Py_None) { + rc = sqlite3_create_collation_v2(self->db, uppercase_name_str, flags, + NULL, NULL, NULL); } - - if (callable != Py_None) { - if (PyDict_SetItem(self->collations, uppercase_name, callable) == -1) - goto finally; - } else { - if (PyDict_DelItem(self->collations, uppercase_name) == -1) + else { + if (!PyCallable_Check(callable)) { + PyErr_SetString(PyExc_TypeError, "parameter must be callable"); goto finally; + } + rc = sqlite3_create_collation_v2(self->db, uppercase_name_str, flags, + Py_NewRef(callable), + &pysqlite_collation_callback, + &_destructor); } - rc = sqlite3_create_collation(self->db, - uppercase_name_str, - SQLITE_UTF8, - (callable != Py_None) ? callable : NULL, - (callable != Py_None) ? pysqlite_collation_callback : NULL); if (rc != SQLITE_OK) { + /* Unlike other sqlite3_* functions, the destructor callback is _not_ + * called if sqlite3_create_collation_v2() fails, so we have to free + * the context before returning. + */ if (callable != Py_None) { - if (PyDict_DelItem(self->collations, uppercase_name) < 0) { - PyErr_Clear(); - } + Py_DECREF(callable); } _pysqlite_seterror(self->db); goto finally; diff --git a/Modules/_sqlite/connection.h b/Modules/_sqlite/connection.h index 5e7e7e5abe06..50c2015be3eb 100644 --- a/Modules/_sqlite/connection.h +++ b/Modules/_sqlite/connection.h @@ -82,9 +82,6 @@ typedef struct PyObject* function_pinboard_progress_handler; PyObject* function_pinboard_authorizer_cb; - /* a dictionary of registered collation name => collation callable mappings */ - PyObject* collations; - /* Exception objects: borrowed refs. */ PyObject* Warning; PyObject* Error;