Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #10320 -- Made it possible to use executemany with iterators. T…

…hanks MockSoul for the report.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17387 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 7beb0db79b468b5cc6f20b05873a631ace989a84 1 parent 4d030e5
Aymeric Augustin authored January 22, 2012
3  django/db/backends/oracle/base.py
@@ -670,6 +670,9 @@ def execute(self, query, params=None):
670 670
             raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
671 671
 
672 672
     def executemany(self, query, params=None):
  673
+        # cx_Oracle doesn't support iterators, convert them to lists
  674
+        if params is not None and not isinstance(params, (list, tuple)):
  675
+            params = list(params)
673 676
         try:
674 677
             args = [(':arg%d' % i) for i in range(len(params[0]))]
675 678
         except (IndexError, TypeError):
10  django/db/backends/util.py
@@ -47,7 +47,7 @@ def execute(self, sql, params=()):
47 47
                 'time': "%.3f" % duration,
48 48
             })
49 49
             logger.debug('(%.3f) %s; args=%s' % (duration, sql, params),
50  
-                extra={'duration':duration, 'sql':sql, 'params':params}
  50
+                extra={'duration': duration, 'sql': sql, 'params': params}
51 51
             )
52 52
 
53 53
     def executemany(self, sql, param_list):
@@ -58,12 +58,16 @@ def executemany(self, sql, param_list):
58 58
         finally:
59 59
             stop = time()
60 60
             duration = stop - start
  61
+            try:
  62
+                times = len(param_list)
  63
+            except TypeError:           # param_list could be an iterator
  64
+                times = '?'
61 65
             self.db.queries.append({
62  
-                'sql': '%s times: %s' % (len(param_list), sql),
  66
+                'sql': '%s times: %s' % (times, sql),
63 67
                 'time': "%.3f" % duration,
64 68
             })
65 69
             logger.debug('(%.3f) %s; args=%s' % (duration, sql, param_list),
66  
-                extra={'duration':duration, 'sql':sql, 'params':param_list}
  70
+                extra={'duration': duration, 'sql': sql, 'params': param_list}
67 71
             )
68 72
 
69 73
 
39  tests/regressiontests/backends/tests.py
@@ -14,6 +14,7 @@
14 14
 from django.db.backends.postgresql_psycopg2 import version as pg_version
15 15
 from django.db.utils import ConnectionHandler, DatabaseError, load_backend
16 16
 from django.test import TestCase, skipUnlessDBFeature, TransactionTestCase
  17
+from django.test.utils import override_settings
17 18
 from django.utils import unittest
18 19
 
19 20
 from . import models
@@ -308,23 +309,43 @@ def test_parameter_escaping(self):
308 309
 
309 310
 
310 311
 class BackendTestCase(TestCase):
311  
-    def test_cursor_executemany(self):
312  
-        #4896: Test cursor.executemany
  312
+
  313
+    def create_squares_with_executemany(self, args):
313 314
         cursor = connection.cursor()
314  
-        qn = connection.ops.quote_name
315 315
         opts = models.Square._meta
316  
-        f1, f2 = opts.get_field('root'), opts.get_field('square')
317  
-        query = ('INSERT INTO %s (%s, %s) VALUES (%%s, %%s)'
318  
-                 % (connection.introspection.table_name_converter(opts.db_table), qn(f1.column), qn(f2.column)))
319  
-        cursor.executemany(query, [(i, i**2) for i in range(-5, 6)])
  316
+        tbl = connection.introspection.table_name_converter(opts.db_table)
  317
+        f1 = connection.ops.quote_name(opts.get_field('root').column)
  318
+        f2 = connection.ops.quote_name(opts.get_field('square').column)
  319
+        query = 'INSERT INTO %s (%s, %s) VALUES (%%s, %%s)' % (tbl, f1, f2)
  320
+        cursor.executemany(query, args)
  321
+
  322
+    def test_cursor_executemany(self):
  323
+        #4896: Test cursor.executemany
  324
+        args = [(i, i**2) for i in range(-5, 6)]
  325
+        self.create_squares_with_executemany(args)
320 326
         self.assertEqual(models.Square.objects.count(), 11)
321 327
         for i in range(-5, 6):
322 328
             square = models.Square.objects.get(root=i)
323 329
             self.assertEqual(square.square, i**2)
324 330
 
  331
+    def test_cursor_executemany_with_empty_params_list(self):
325 332
         #4765: executemany with params=[] does nothing
326  
-        cursor.executemany(query, [])
327  
-        self.assertEqual(models.Square.objects.count(), 11)
  333
+        args = []
  334
+        self.create_squares_with_executemany(args)
  335
+        self.assertEqual(models.Square.objects.count(), 0)
  336
+
  337
+    def test_cursor_executemany_with_iterator(self):
  338
+        #10320: executemany accepts iterators
  339
+        args = iter((i, i**2) for i in range(-3, 2))
  340
+        self.create_squares_with_executemany(args)
  341
+        self.assertEqual(models.Square.objects.count(), 5)
  342
+
  343
+        args = iter((i, i**2) for i in range(3, 7))
  344
+        with override_settings(DEBUG=True):
  345
+            # same test for DebugCursorWrapper
  346
+            self.create_squares_with_executemany(args)
  347
+        self.assertEqual(models.Square.objects.count(), 9)
  348
+
328 349
 
329 350
     def test_unicode_fetches(self):
330 351
         #6254: fetchone, fetchmany, fetchall return strings as unicode objects

0 notes on commit 7beb0db

Please sign in to comment.
Something went wrong with that request. Please try again.