]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-46874: Speed up sqlite3 user-defined aggregate 'step' method (GH-31604)
authorErlend Egeberg Aasland <erlend.aasland@innova.no>
Thu, 3 Mar 2022 13:54:36 +0000 (14:54 +0100)
committerGitHub <noreply@github.com>
Thu, 3 Mar 2022 13:54:36 +0000 (22:54 +0900)
Lib/test/test_sqlite3/test_userfunctions.py
Modules/_sqlite/connection.c
Modules/_sqlite/module.c
Modules/_sqlite/module.h

index 23ecfb4e8a68959982a4137714fdd54c9eaab059..2588cae3d1f15152636ca406d03c47c78cb50c6f 100644 (file)
@@ -502,11 +502,13 @@ class AggregateTests(unittest.TestCase):
         with self.assertRaises(sqlite.OperationalError):
             self.con.create_function("bla", -100, AggrSum)
 
+    @with_tracebacks(AttributeError, name="AggrNoStep")
     def test_aggr_no_step(self):
         cur = self.con.cursor()
-        with self.assertRaises(AttributeError) as cm:
+        with self.assertRaises(sqlite.OperationalError) as cm:
             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):
         cur = self.con.cursor()
index 0efb5ae35a7f55afea88b4bfdb2d92c32f691876..9f12e691f8912fbe005dbe4b7f09e47db672c44f 100644 (file)
@@ -734,11 +734,11 @@ step_callback(sqlite3_context *context, int argc, sqlite3_value **params)
     PyObject** aggregate_instance;
     PyObject* stepmethod = NULL;
 
-    aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
+    callback_context *ctx = (callback_context *)sqlite3_user_data(context);
+    assert(ctx != NULL);
 
+    aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
     if (*aggregate_instance == NULL) {
-        callback_context *ctx = (callback_context *)sqlite3_user_data(context);
-        assert(ctx != NULL);
         *aggregate_instance = PyObject_CallNoArgs(ctx->callable);
         if (!*aggregate_instance) {
             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) {
+        set_sqlite_error(context,
+                "user-defined aggregate's 'step' method not defined");
         goto error;
     }
 
index 70fde4910f6a47ce903473f25403957faacf9054..563105c63910025e98b9549945ce60eaa07e5cf9 100644 (file)
@@ -627,6 +627,7 @@ module_clear(PyObject *module)
     Py_CLEAR(state->str___conform__);
     Py_CLEAR(state->str_executescript);
     Py_CLEAR(state->str_finalize);
+    Py_CLEAR(state->str_step);
     Py_CLEAR(state->str_upper);
 
     return 0;
@@ -713,6 +714,7 @@ module_exec(PyObject *module)
     ADD_INTERNED(state, __conform__);
     ADD_INTERNED(state, executescript);
     ADD_INTERNED(state, finalize);
+    ADD_INTERNED(state, step);
     ADD_INTERNED(state, upper);
 
     /* Set error constants */
index 35c6f385526064daf287fee71699ac911531d915..cca52d1e04b2cb62b1affc844abe3517fa7cec3a 100644 (file)
@@ -64,6 +64,7 @@ typedef struct {
     PyObject *str___conform__;
     PyObject *str_executescript;
     PyObject *str_finalize;
+    PyObject *str_step;
     PyObject *str_upper;
 } pysqlite_state;