From: Mike Bayer Date: Wed, 15 Mar 2017 14:15:12 +0000 (-0400) Subject: Consult compiled paramstyle on execute_compiled X-Git-Tag: rel_1_2_0b1~151 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7b056709c0f8a37744d18f37d40f94fa30c50c71;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Consult compiled paramstyle on execute_compiled Fixed bug where in the unusual case of passing a :class:`.Compiled` object directly to :meth:`.Connection.execute`, the dialect with which the :class:`.Compiled` object were generated was not consulted for the paramstyle of the string statement, instead assuming it would match the dialect-level paramstyle, causing mismatches to occur. Change-Id: I114e4db2183fbb75bb7c0b0641f5a161855696ee Fixes: #3938 --- diff --git a/doc/build/changelog/changelog_12.rst b/doc/build/changelog/changelog_12.rst index 7e6c406da9..f2646fdf1c 100644 --- a/doc/build/changelog/changelog_12.rst +++ b/doc/build/changelog/changelog_12.rst @@ -13,6 +13,17 @@ .. changelog:: :version: 1.2.0b1 + .. change:: 3938 + :tags: bug, engine + :tickets: 3938 + + Fixed bug where in the unusual case of passing a + :class:`.Compiled` object directly to :meth:`.Connection.execute`, + the dialect with which the :class:`.Compiled` object were generated + was not consulted for the paramstyle of the string statement, instead + assuming it would match the dialect-level paramstyle, causing + mismatches to occur. + .. change:: 3918 :tags: bug, ext :tickets: 3918 diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index b8c2d28452..3968663fb4 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -627,7 +627,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext): # into a dict or list to be sent to the DBAPI's # execute() or executemany() method. parameters = [] - if dialect.positional: + if compiled.positional: for compiled_params in self.compiled_parameters: param = [] for key in self.compiled.positiontup: diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index 32834f950b..54a85bf9f5 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -19,6 +19,7 @@ from sqlalchemy.engine import result as _result, default from sqlalchemy.engine.base import Engine from sqlalchemy.testing import fixtures from sqlalchemy.testing.mock import Mock, call, patch +from sqlalchemy.testing import mock from contextlib import contextmanager from sqlalchemy.util import nested from sqlalchemy.testing.assertsql import CompiledSQL @@ -433,6 +434,35 @@ class ExecuteTest(fixtures.TestBase): values(user_name=bindparam('name', None)), []) eq_(testing.db.execute(users_autoinc.select()).fetchall(), [(1, None)]) + @testing.only_on("sqlite") + def test_execute_compiled_favors_compiled_paramstyle(self): + with patch.object(testing.db.dialect, "do_execute") as do_exec: + stmt = users.update().values(user_id=1, user_name='foo') + + d1 = default.DefaultDialect(paramstyle="format") + d2 = default.DefaultDialect(paramstyle="pyformat") + + testing.db.execute(stmt.compile(dialect=d1)) + testing.db.execute(stmt.compile(dialect=d2)) + + eq_( + do_exec.mock_calls, [ + call( + mock.ANY, + "UPDATE users SET user_id=%s, user_name=%s", + (1, 'foo'), + mock.ANY + ), + call( + mock.ANY, + "UPDATE users SET user_id=%(user_id)s, " + "user_name=%(user_name)s", + {'user_name': 'foo', 'user_id': 1}, + mock.ANY + ) + ] + ) + @testing.requires.ad_hoc_engines def test_engine_level_options(self): eng = engines.testing_engine(options={'execution_options':