8000 bpo-42064: Pass module state to `sqlite3` UDF callbacks (GH-27456) · python/cpython@9ed5231 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9ed5231

Browse files
author
Erlend Egeberg Aasland
authored
bpo-42064: Pass module state to sqlite3 UDF callbacks (GH-27456)
- Establish common callback context struct - Convert UDF callbacks to fetch module state from callback context
1 parent 7179930 commit 9ed5231

File tree

2 files changed

+64
-31
lines changed

2 files changed

+64
-31
lines changed

Modules/_sqlite/connection.c

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -612,8 +612,10 @@ set_sqlite_error(sqlite3_context *context, const char *msg)
612612
else {
613613
sqlite3_result_error(context, msg, -1);
614614
}
615-
pysqlite_state *state = pysqlite_get_state(NULL);
616-
if (state->enable_callback_tracebacks) {
615+
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
616+
assert(ctx != NULL);
617+
assert(ctx->state != NULL);
618+
if (ctx->state->enable_callback_tracebacks) {
617619
PyErr_Print();
618620
}
619621
else {
@@ -625,19 +627,18 @@ static void
625627
_pysqlite_func_callback(sqlite3_context *context, int argc, sqlite3_value **argv)
626628
{
627629
PyObject* args;
628-
PyObject* py_func;
629630
PyObject* py_retval = NULL;
630631
int ok;
631632

632633
PyGILState_STATE threadstate;
633634

634635
threadstate = PyGILState_Ensure();
635636

636-
py_func = (PyObject*)sqlite3_user_data(context);
637-
638637
args = _pysqlite_build_py_params(context, argc, argv);
639638
if (args) {
640-
py_retval = PyObject_CallObject(py_func, args);
639+
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
640+
assert(ctx != NULL);
641+
py_retval = PyObject_CallObject(ctx->callable, args);
641642
Py_DECREF(args);
642643
}
643644

@@ -657,20 +658,19 @@ static void _pysqlite_step_callback(sqlite3_context *context, int argc, sqlite3_
657658
{
658659
PyObject* args;
659660
PyObject* function_result = NULL;
660-
PyObject* aggregate_class;
661661
PyObject** aggregate_instance;
662662
PyObject* stepmethod = NULL;
663663

664664
PyGILState_STATE threadstate;
665665

666666
threadstate = PyGILState_Ensure();
667667

668-
aggregate_class = (PyObject*)sqlite3_user_data(context);
669-
670668
aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
671669

672670
if (*aggregate_instance == NULL) {
673-
*aggregate_instance = _PyObject_CallNoArg(aggregate_class);
671+
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
672+
assert(ctx != NULL);
673+
*aggregate_instance = _PyObject_CallNoArg(ctx->callable);
674674
if (!*aggregate_instance) {
675675
set_sqlite_error(context,
676676
"user-defined aggregate's '__init__' method raised error");
@@ -784,14 +784,35 @@ static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
784784
Py_SETREF(self->cursors, new_list);
785785
}
786786

787-
static void _destructor(void* args)
787+
static callback_context *
788+
create_callback_context(pysqlite_state *state, PyObject *callable)
788789
{
789-
// This function may be called without the GIL held, so we need to ensure
790-
// that we destroy 'args' with the GIL
791-
PyGILState_STATE gstate;
< 8000 /td>
792-
gstate = PyGILState_Ensure();
793-
Py_DECREF((PyObject*)args);
790+
PyGILState_STATE gstate = PyGILState_Ensure();
791+
callback_context *ctx = PyMem_Malloc(sizeof(callback_context));
792+
if (ctx != NULL) {
793+
ctx->callable = Py_NewRef(callable);
794+
ctx->state = state;
795+
}
794796
PyGILState_Release(gstate);
797+
return ctx;
798+
}
799+
800+
static void
801+
free_callback_context(callback_context *ctx)
802+
{
803+
if (ctx != NULL) {
804+
// This function may be called without the GIL held, so we need to
805+
// ensure that we destroy 'ctx' with the GIL held.
806+
PyGILState_STATE gstate = PyGILState_Ensure();
807+
Py_DECREF(ctx->callable);
808+
PyMem_Free(ctx);
809+
PyGILState_Release(gstate);
810+
}
811+
}
812+
813+
static void _destructor(void* args)
814+
{
815+
free_callback_context((callback_context *)args);
795816
}
796817

797818
/*[clinic input]
@@ -833,11 +854,11 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self,
833854
flags |= SQLITE_DETERMINISTIC;
834855
#endif
835856
}
836-
rc = sqlite3_create_function_v2(self->db,
837-
name,
838-
narg,
839-
flags,
840-
A3E2 (void*)Py_NewRef(func),
857+
callback_context *ctx = create_callback_context(self->state, func);
858+
if (ctx == NULL) {
859+
return NULL;
860+
}
861+
rc = sqlite3_create_function_v2(self->db, name, narg, flags, ctx,
841862
_pysqlite_func_callback,
842863
NULL,
843864
NULL,
@@ -873,11 +894,12 @@ pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self,
873894
return NULL;
874895
}
875896

876-
rc = sqlite3_create_function_v2(self->db,
877-
name,
878-
n_arg,
879-
SQLITE_UTF8,
880-
(void*)Py_NewRef(aggregate_class),
897+
callback_context *ctx = create_callback_context(self->state,
898+
aggregate_class);
899+
if (ctx == NULL) {
900+
return NULL;
901+
}
902+
rc = sqlite3_create_function_v2(self->db, name, n_arg, SQLITE_UTF8, ctx,
881903
0,
882904
&_pysqlite_step_callback,
883905
&_pysqlite_final_callback,
@@ -1439,7 +1461,6 @@ pysqlite_collation_callback(
14391461
int text1_length, const void* text1_data,
14401462
int text2_length, const void* text2_data)
14411463
{
1442-
PyObject* callback = (PyObject*)context;
14431464
PyObject* string1 = 0;
14441465
PyObject* string2 = 0;
14451466
PyGILState_STATE gilstate;
@@ -1459,8 +1480,10 @@ pysqlite_collation_callback(
14591480
goto finally; /* failed to allocate strings */
14601481
}
14611482

1483+
callback_context *ctx = (callback_context *)context;
1484+
assert(ctx != NULL);
14621485
PyObject *args[] = { string1, string2 }; // Borrowed refs.
1463-
retval = PyObject_Vectorcall(callback, args, 2, NULL);
1486+
retval = PyObject_Vectorcall(ctx->callable, args, 2, NULL);
14641487
if (retval == NULL) {
14651488
/* execution failed */
14661489
goto finally;
@@ -1690,6 +1713,7 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
16901713
return NULL;
16911714
}
16921715

1716+
callback_context *ctx = NULL;
16931717
int rc;
16941718
int flags = SQLITE_UTF8;
16951719
if (callable == Py_None) {
@@ -1701,8 +1725,11 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
17011725
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
17021726
return NULL;
17031727
}
1704-
rc = sqlite3_create_collation_v2(self->db, name, flags,
1705-
Py_NewRef(callable),
1728+
ctx = create_callback_context(self->state, callable);
1729+
if (ctx == NULL) {
1730+
return NULL;
1731+
}
1732+
rc = sqlite3_create_collation_v2(self->db, name, flags, ctx,
17061733
&pysqlite_collation_callback,
17071734
&_destructor);
17081735
}
@@ -1713,7 +1740,7 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
17131740
* the context before returning.
17141741
*/
17151742
if (callable != Py_None) {
1716-
Py_DECREF(callable);
1743+
free_callback_context(ctx);
17171744
}
17181745
_pysqlite_seterror(self->state, self->db);
17191746
return NULL;

Modules/_sqlite/connection.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232

3333
#include "sqlite3.h"
3434

35+
typedef struct _callback_context
36+
{
37+
PyObject *callable;
38+
pysqlite_state *state;
39+
} callback_context;
40+
3541
typedef struct
3642
{
3743
PyObject_HEAD

0 commit comments

Comments
 (0)
0