diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-01-05 10:25:36 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-01-05 10:25:36 -0500 |
commit | 197ffa2be2cadce3df8bfb0799b3c80158250286 (patch) | |
tree | a67320139e3ae72014a71bdd56396660408a4b12 | |
parent | 04b1a52783a38148e52d50566161bdaf5262cd43 (diff) | |
download | sqlalchemy-197ffa2be2cadce3df8bfb0799b3c80158250286.tar.gz |
- Fixed 1.0 regression where the eager fetch of cursor.rowcount was
no longer called for an UPDATE or DELETE statement emitted via plain
text or via the :func:`.text` construct, affecting those drivers
that erase cursor.rowcount once the cursor is closed such as SQL
Server ODBC and Firebird drivers.
fixes #3622
-rw-r--r-- | doc/build/changelog/changelog_10.rst | 16 | ||||
-rw-r--r-- | lib/sqlalchemy/engine/base.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/engine/default.py | 3 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 6 | ||||
-rw-r--r-- | test/sql/test_rowcount.py | 17 |
5 files changed, 43 insertions, 1 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index 25592a3b1..782af7320 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -16,6 +16,22 @@ :start-line: 5 .. changelog:: + :version: 1.0.12 + :released: + + .. change:: + :tags: bug, mssql, firebird + :versions: 1.1.0b1 + :tickets: 3622 + + Fixed 1.0 regression where the eager fetch of cursor.rowcount was + no longer called for an UPDATE or DELETE statement emitted via plain + text or via the :func:`.text` construct, affecting those drivers + that erase cursor.rowcount once the cursor is closed such as SQL + Server ODBC and Firebird drivers. + + +.. changelog:: :version: 1.0.11 :released: December 22, 2015 diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index eaa435d45..31e253eed 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -1155,7 +1155,7 @@ class Connection(Connectable): if context.compiled: context.post_exec() - if context.is_crud: + if context.is_crud or context.is_text: result = context._setup_crud_result_proxy() else: result = context.get_result_proxy() diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index 9a7b80bfd..87278c2be 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -467,6 +467,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext): isupdate = False isdelete = False is_crud = False + is_text = False isddl = False executemany = False compiled = None @@ -543,6 +544,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext): self.isinsert = compiled.isinsert self.isupdate = compiled.isupdate self.isdelete = compiled.isdelete + self.is_text = compiled.isplaintext if not parameters: self.compiled_parameters = [compiled.construct_params()] @@ -622,6 +624,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext): self.root_connection = connection self._dbapi_connection = dbapi_connection self.dialect = connection.dialect + self.is_text = True # plain text statement self.execution_options = connection._execution_options diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 6766c99b7..2ca549267 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -286,6 +286,7 @@ class _CompileLabel(visitors.Visitable): def self_group(self, **kw): return self + class SQLCompiler(Compiled): """Default implementation of Compiled. @@ -305,6 +306,8 @@ class SQLCompiler(Compiled): INSERT/UPDATE/DELETE """ + isplaintext = False + returning = None """holds the "returning" collection of columns if the statement is CRUD and defines returning columns @@ -688,6 +691,9 @@ class SQLCompiler(Compiled): else: return self.bindparam_string(name, **kw) + if not self.stack: + self.isplaintext = True + # un-escape any \:params return BIND_PARAMS_ESC.sub( lambda m: m.group(1), diff --git a/test/sql/test_rowcount.py b/test/sql/test_rowcount.py index 46e10e192..110f3639f 100644 --- a/test/sql/test_rowcount.py +++ b/test/sql/test_rowcount.py @@ -1,6 +1,7 @@ from sqlalchemy import * from sqlalchemy.testing import fixtures, AssertsExecutionResults from sqlalchemy import testing +from sqlalchemy.testing import eq_ class FoundRowsTest(fixtures.TestBase, AssertsExecutionResults): @@ -65,6 +66,22 @@ class FoundRowsTest(fixtures.TestBase, AssertsExecutionResults): print("expecting 3, dialect reports %s" % r.rowcount) assert r.rowcount == 3 + def test_raw_sql_rowcount(self): + # test issue #3622, make sure eager rowcount is called for text + with testing.db.connect() as conn: + result = conn.execute( + "update employees set department='Z' where department='C'") + eq_(result.rowcount, 3) + + def test_text_rowcount(self): + # test issue #3622, make sure eager rowcount is called for text + with testing.db.connect() as conn: + result = conn.execute( + text( + "update employees set department='Z' " + "where department='C'")) + eq_(result.rowcount, 3) + def test_delete_rowcount(self): # WHERE matches 3, 3 rows deleted department = employees_table.c.department |