]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Enable sane_multi_rowcount for cx_Oracle
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Mar 2017 17:38:12 +0000 (13:38 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Mar 2017 17:38:12 +0000 (13:38 -0400)
Also add some tests to test_rowcount.

Change-Id: Idaa18fdc4fcfeb615725531c37de77decf76a783
Fixes: #3932
doc/build/changelog/changelog_12.rst
lib/sqlalchemy/dialects/oracle/base.py
lib/sqlalchemy/dialects/oracle/cx_oracle.py
test/sql/test_rowcount.py

index 503c59a268f351626aa088a0aa0e870daec2270c..abf7035cad113ac33a234031d96fd7a021f7d6d7 100644 (file)
 .. changelog::
     :version: 1.2.0b1
 
+    .. change:: 3932
+        :tags: bug, oracle
+        :tickets: 3932
+
+        The cx_Oracle dialect now supports "sane multi rowcount", that is,
+        when a series of parameter sets are executed via DBAPI
+        ``cursor.executemany()``, we can make use of ``cursor.rowcount`` to
+        verify the number of rows matched.  This has an impact within the
+        ORM when detecting concurrent modification scenarios, in that
+        some simple conditions can now be detected even when the ORM
+        is batching statements, as well as when the more strict versioning
+        feature is used, the ORM can still use statement batching.  The
+        flag is enabled for cx_Oracle assuming at least version 5.0, which
+        is now commonplace.
 
     .. change:: 3276
         :tags: bug, oracle
index 39bc5e1d3119a0f6408b0d795c179ad020bf9c2e..8cafb36568e40f6f1e142ba362b81dbb38d3a2ea 100644 (file)
@@ -957,8 +957,6 @@ class OracleDialect(default.DefaultDialect):
     supports_unicode_statements = False
     supports_unicode_binds = False
     max_identifier_length = 30
-    supports_sane_rowcount = True
-    supports_sane_multi_rowcount = False
 
     supports_simple_order_by_label = False
 
index 9b3e3b8a12241185e441c1744d0db5e75943dab8..6789cd49ffbacd3293bcb698a92d830dfa3d54d0 100644 (file)
@@ -653,6 +653,9 @@ class OracleDialect_cx_oracle(OracleDialect):
     execution_ctx_cls = OracleExecutionContext_cx_oracle
     statement_compiler = OracleCompiler_cx_oracle
 
+    supports_sane_rowcount = True
+    supports_sane_multi_rowcount = True
+
     driver = "cx_oracle"
 
     colspecs = colspecs = {
@@ -723,6 +726,8 @@ class OracleDialect_cx_oracle(OracleDialect):
         self._cx_oracle_binary_types = types("BFILE", "CLOB", "NCLOB", "BLOB")
         self.supports_unicode_binds = self.cx_oracle_ver >= (5, 0)
 
+        self.supports_sane_multi_rowcount = self.cx_oracle_ver >= (5, 0)
+
         self.coerce_to_unicode = (
             self.cx_oracle_ver >= (5, 0) and
             coerce_to_unicode
index 0ab5589ab3bfdeec9872d7b2b3d6b205fc019d31..16087b94ccd749880c77dadcc41a1e920b746dff 100644 (file)
@@ -57,14 +57,12 @@ class FoundRowsTest(fixtures.TestBase, AssertsExecutionResults):
         # WHERE matches 3, 3 rows changed
         department = employees_table.c.department
         r = employees_table.update(department == 'C').execute(department='Z')
-        print("expecting 3, dialect reports %s" % r.rowcount)
         assert r.rowcount == 3
 
     def test_update_rowcount2(self):
         # WHERE matches 3, 0 rows changed
         department = employees_table.c.department
         r = employees_table.update(department == 'C').execute(department='C')
-        print("expecting 3, dialect reports %s" % r.rowcount)
         assert r.rowcount == 3
 
     def test_raw_sql_rowcount(self):
@@ -87,5 +85,35 @@ class FoundRowsTest(fixtures.TestBase, AssertsExecutionResults):
         # WHERE matches 3, 3 rows deleted
         department = employees_table.c.department
         r = employees_table.delete(department == 'C').execute()
-        print("expecting 3, dialect reports %s" % r.rowcount)
         assert r.rowcount == 3
+
+    @testing.requires.sane_multi_rowcount
+    def test_multi_update_rowcount(self):
+        stmt = employees_table.update().\
+            where(employees_table.c.name == bindparam('emp_name')).\
+            values(department="C")
+
+        r = testing.db.execute(
+            stmt,
+            [{"emp_name": "Bob"}, {"emp_name": "Cynthia"},
+             {"emp_name": "nonexistent"}]
+        )
+
+        eq_(
+            r.rowcount, 2
+        )
+
+    @testing.requires.sane_multi_rowcount
+    def test_multi_delete_rowcount(self):
+        stmt = employees_table.delete().\
+            where(employees_table.c.name == bindparam('emp_name'))
+
+        r = testing.db.execute(
+            stmt,
+            [{"emp_name": "Bob"}, {"emp_name": "Cynthia"},
+             {"emp_name": "nonexistent"}]
+        )
+
+        eq_(
+            r.rowcount, 2
+        )