Skip to content

Commit 88567a9

Browse files
author
Erlend Egeberg Aasland
authored
bpo-46874: Speed up sqlite3 user-defined aggregate 'step' method (GH-31604)
1 parent 751c9ed commit 88567a9

File tree

4 files changed

+13
-6
lines changed

4 files changed

+13
-6
lines changed

Lib/test/test_sqlite3/test_userfunctions.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,11 +502,13 @@ def test_aggr_error_on_create(self):
502502
with self.assertRaises(sqlite.OperationalError):
503503
self.con.create_function("bla", -100, AggrSum)
504504

505+
@with_tracebacks(AttributeError, name="AggrNoStep")
505506
def test_aggr_no_step(self):
506507
cur = self.con.cursor()
507-
with self.assertRaises(AttributeError) as cm:
508+
with self.assertRaises(sqlite.OperationalError) as cm:
508509
cur.execute("select nostep(t) from test")
509-
self.assertEqual(str(cm.exception), "'AggrNoStep' object has no attribute 'step'")
510+
self.assertEqual(str(cm.exception),
511+
"user-defined aggregate's 'step' method not defined")
510512

511513
def test_aggr_no_finalize(self):
512514
cur = self.con.cursor()

Modules/_sqlite/connection.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -734,11 +734,11 @@ step_callback(sqlite3_context *context, int argc, sqlite3_value **params)
734734
PyObject** aggregate_instance;
735735
PyObject* stepmethod = NULL;
736736

737-
aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
737+
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
738+
assert(ctx != NULL);
738739

740+
aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
739741
if (*aggregate_instance == NULL) {
740-
callback_context *ctx = (callback_context *)sqlite3_user_data(context);
741-
assert(ctx != NULL);
742742
*aggregate_instance = PyObject_CallNoArgs(ctx->callable);
743743
if (!*aggregate_instance) {
744744
set_sqlite_error(context,
@@ -747,8 +747,10 @@ step_callback(sqlite3_context *context, int argc, sqlite3_value **params)
747747
}
748748
}
749749

750-
stepmethod = PyObject_GetAttrString(*aggregate_instance, "step");
750+
stepmethod = PyObject_GetAttr(*aggregate_instance, ctx->state->str_step);
751751
if (!stepmethod) {
752+
set_sqlite_error(context,
753+
"user-defined aggregate's 'step' method not defined");
752754
goto error;
753755
}
754756

Modules/_sqlite/module.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,7 @@ module_clear(PyObject *module)
627627
Py_CLEAR(state->str___conform__);
628628
Py_CLEAR(state->str_executescript);
629629
Py_CLEAR(state->str_finalize);
630+
Py_CLEAR(state->str_step);
630631
Py_CLEAR(state->str_upper);
631632

632633
return 0;
@@ -713,6 +714,7 @@ module_exec(PyObject *module)
713714
ADD_INTERNED(state, __conform__);
714715
ADD_INTERNED(state, executescript);
715716
ADD_INTERNED(state, finalize);
717+
ADD_INTERNED(state, step);
716718
ADD_INTERNED(state, upper);
717719

718720
/* Set error constants */

Modules/_sqlite/module.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ typedef struct {
6464
PyObject *str___conform__;
6565
PyObject *str_executescript;
6666
PyObject *str_finalize;
67+
PyObject *str_step;
6768
PyObject *str_upper;
6869
} pysqlite_state;
6970

0 commit comments

Comments
 (0)