bpo-46874: Speed up sqlite3 user-defined aggregate 'step' method (GH-31604)

This commit is contained in:
Erlend Egeberg Aasland 2022-03-03 14:54:36 +01:00 committed by GitHub
parent 751c9ed801
commit 88567a9970
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 13 additions and 6 deletions

View file

@ -502,11 +502,13 @@ class AggregateTests(unittest.TestCase):
with self.assertRaises(sqlite.OperationalError): with self.assertRaises(sqlite.OperationalError):
self.con.create_function("bla", -100, AggrSum) self.con.create_function("bla", -100, AggrSum)
@with_tracebacks(AttributeError, name="AggrNoStep")
def test_aggr_no_step(self): def test_aggr_no_step(self):
cur = self.con.cursor() cur = self.con.cursor()
with self.assertRaises(AttributeError) as cm: with self.assertRaises(sqlite.OperationalError) as cm:
cur.execute("select nostep(t) from test") cur.execute("select nostep(t) from test")
self.assertEqual(str(cm.exception), "'AggrNoStep' object has no attribute 'step'") self.assertEqual(str(cm.exception),
"user-defined aggregate's 'step' method not defined")
def test_aggr_no_finalize(self): def test_aggr_no_finalize(self):
cur = self.con.cursor() cur = self.con.cursor()

View file

@ -734,11 +734,11 @@ step_callback(sqlite3_context *context, int argc, sqlite3_value **params)
PyObject** aggregate_instance; PyObject** aggregate_instance;
PyObject* stepmethod = NULL; PyObject* stepmethod = NULL;
aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
if (*aggregate_instance == NULL) {
callback_context *ctx = (callback_context *)sqlite3_user_data(context); callback_context *ctx = (callback_context *)sqlite3_user_data(context);
assert(ctx != NULL); assert(ctx != NULL);
aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
if (*aggregate_instance == NULL) {
*aggregate_instance = PyObject_CallNoArgs(ctx->callable); *aggregate_instance = PyObject_CallNoArgs(ctx->callable);
if (!*aggregate_instance) { if (!*aggregate_instance) {
set_sqlite_error(context, set_sqlite_error(context,
@ -747,8 +747,10 @@ step_callback(sqlite3_context *context, int argc, sqlite3_value **params)
} }
} }
stepmethod = PyObject_GetAttrString(*aggregate_instance, "step"); stepmethod = PyObject_GetAttr(*aggregate_instance, ctx->state->str_step);
if (!stepmethod) { if (!stepmethod) {
set_sqlite_error(context,
"user-defined aggregate's 'step' method not defined");
goto error; goto error;
} }

View file

@ -627,6 +627,7 @@ module_clear(PyObject *module)
Py_CLEAR(state->str___conform__); Py_CLEAR(state->str___conform__);
Py_CLEAR(state->str_executescript); Py_CLEAR(state->str_executescript);
Py_CLEAR(state->str_finalize); Py_CLEAR(state->str_finalize);
Py_CLEAR(state->str_step);
Py_CLEAR(state->str_upper); Py_CLEAR(state->str_upper);
return 0; return 0;
@ -713,6 +714,7 @@ module_exec(PyObject *module)
ADD_INTERNED(state, __conform__); ADD_INTERNED(state, __conform__);
ADD_INTERNED(state, executescript); ADD_INTERNED(state, executescript);
ADD_INTERNED(state, finalize); ADD_INTERNED(state, finalize);
ADD_INTERNED(state, step);
ADD_INTERNED(state, upper); ADD_INTERNED(state, upper);
/* Set error constants */ /* Set error constants */

View file

@ -64,6 +64,7 @@ typedef struct {
PyObject *str___conform__; PyObject *str___conform__;
PyObject *str_executescript; PyObject *str_executescript;
PyObject *str_finalize; PyObject *str_finalize;
PyObject *str_step;
PyObject *str_upper; PyObject *str_upper;
} pysqlite_state; } pysqlite_state;