]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
send same sub_stmt to after_cursor_execute as before
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 3 Dec 2025 04:10:10 +0000 (23:10 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 3 Dec 2025 04:10:10 +0000 (23:10 -0500)
Fixed issue in the :meth:`.ConnectionEvents.after_cursor_execute` method
where the SQL statement and parameter list for an "insertmanyvalues"
operation sent to the event would not be the actual SQL / parameters just
emitted on the cursor, instead being the non-batched form of the statement
that's used as a template to generate the batched statements.

Fixes: #13018
Change-Id: Ib5b6c576f2c7a9ed275de30290d619cc651b4816

doc/build/changelog/unreleased_21/13018.rst [new file with mode: 0644]
lib/sqlalchemy/engine/base.py
lib/sqlalchemy/testing/assertsql.py
test/engine/test_execute.py

diff --git a/doc/build/changelog/unreleased_21/13018.rst b/doc/build/changelog/unreleased_21/13018.rst
new file mode 100644 (file)
index 0000000..630ab24
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: bug, engine
+    :tickets: 13018
+
+    Fixed issue in the :meth:`.ConnectionEvents.after_cursor_execute` method
+    where the SQL statement and parameter list for an "insertmanyvalues"
+    operation sent to the event would not be the actual SQL / parameters just
+    emitted on the cursor, instead being the non-batched form of the statement
+    that's used as a template to generate the batched statements.
index 4e2d6d878d04c4ba36dd231928d48b16ca1951ee..4e81ab478cb6c4b422d216a7c1477dd6222f7edd 100644 (file)
@@ -1984,13 +1984,6 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
         else:
             do_execute_dispatch = ()
 
-        if engine_events:
-            _WORKAROUND_ISSUE_13018 = getattr(
-                self, "_WORKAROUND_ISSUE_13018", False
-            )
-        else:
-            _WORKAROUND_ISSUE_13018 = False
-
         if self._echo:
             stats = context._get_cache_stats() + " (insertmanyvalues)"
 
@@ -2105,9 +2098,8 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
                 self.dispatch.after_cursor_execute(
                     self,
                     cursor,
-                    # TODO: this will be fixed by #13018
-                    sub_stmt if _WORKAROUND_ISSUE_13018 else str_statement,
-                    sub_params if _WORKAROUND_ISSUE_13018 else parameters,
+                    sub_stmt,
+                    sub_params,
                     context,
                     context.executemany,
                 )
index 603955a8b5196981d7149d51b62e04bbdc547696..db28709cc379a6250fe7936cfc020c2cbaea9afc 100644 (file)
@@ -484,7 +484,6 @@ def assert_engine(engine):
     def connection_execute(
         conn, clauseelement, multiparams, params, execution_options
     ):
-        conn._WORKAROUND_ISSUE_13018 = True
         # grab the original statement + params before any cursor
         # execution
         orig[:] = clauseelement, multiparams, params
index b07c0cc9a828c8ed20f7cfa253e2154905e0f7c0..600cf10da9cf8252f05eecc2e4f8ccfb770b8428 100644 (file)
@@ -912,6 +912,38 @@ class ExecuteDriverTest(fixtures.TablesTest):
                 eq_(conn.scalar(select(1)), 1)
             eng.dispose()
 
+    @testing.requires.insertmanyvalues
+    def test_cursor_execute_insertmanyvalues(self, connection, metadata):
+        """test #13018, that before_cursor_execute and after_cursor_execute
+        get the inner INSERT statements / params for an insertmanyvalues
+
+        """
+        canary = Mock()
+
+        t = Table(
+            "t",
+            metadata,
+            Column("id", Integer, primary_key=True),
+            Column("data", String(50)),
+        )
+        t.create(connection)
+
+        event.listen(connection, "before_cursor_execute", canary.bce)
+        event.listen(connection, "after_cursor_execute", canary.ace)
+
+        result = connection.execute(
+            t.insert().returning(
+                t.c.id, t.c.data, sort_by_parameter_order=True
+            ),
+            [{"data": f"d{i}"} for i in range(10)],
+        )
+        eq_(result.all(), [(i + 1, f"d{i}") for i in range(10)])
+
+        eq_(
+            [(c1.args[2], c1.args[3]) for c1 in canary.bce.mock_calls],
+            [(c1.args[2], c1.args[3]) for c1 in canary.ace.mock_calls],
+        )
+
 
 class CompiledCacheTest(fixtures.TestBase):
     __sparse_driver_backend__ = True