diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index b7e071d077..ec2e43aa52 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -7,6 +7,8 @@ Python 2.5 and later can use a pysqlite2 module or the sqlite3 module in the standard library. """ +import re + from django.db.backends import * from django.db.backends.signals import connection_created from django.db.backends.sqlite3.client import DatabaseClient @@ -186,6 +188,8 @@ class DatabaseWrapper(BaseDatabaseWrapper): if self.settings_dict['DATABASE_NAME'] != ":memory:": BaseDatabaseWrapper.close(self) +FORMAT_QMARK_REGEX = re.compile(r'(?![^%])%s') + class SQLiteCursorWrapper(Database.Cursor): """ Django uses "format" style placeholders, but pysqlite2 uses "qmark" style. @@ -193,19 +197,15 @@ class SQLiteCursorWrapper(Database.Cursor): you'll need to use "%%s". """ def execute(self, query, params=()): - query = self.convert_query(query, len(params)) + query = self.convert_query(query) return Database.Cursor.execute(self, query, params) def executemany(self, query, param_list): - try: - query = self.convert_query(query, len(param_list[0])) - return Database.Cursor.executemany(self, query, param_list) - except (IndexError,TypeError): - # No parameter list provided - return None + query = self.convert_query(query) + return Database.Cursor.executemany(self, query, param_list) - def convert_query(self, query, num_params): - return query % tuple("?" * num_params) + def convert_query(self, query): + return FORMAT_QMARK_REGEX.sub('?', query).replace('%%','%') def _sqlite_extract(lookup_type, dt): if dt is None: diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py index a376cd8e87..da3f4ab17c 100644 --- a/tests/regressiontests/backends/tests.py +++ b/tests/regressiontests/backends/tests.py @@ -66,6 +66,19 @@ class DateQuotingTest(TestCase): classes = models.SchoolClass.objects.filter(last_updated__day=20) self.assertEqual(len(classes), 1) +class ParameterHandlingTest(TestCase): + def test_bad_parameter_count(self): + "An executemany call with too many/not enough parameters will raise an exception (Refs #12612)" + cursor = connection.cursor() + query = ('INSERT INTO %s (%s, %s) VALUES (%%s, %%s)' % ( + connection.introspection.table_name_converter('backends_square'), + connection.ops.quote_name('root'), + connection.ops.quote_name('square') + )) + self.assertRaises(Exception, cursor.executemany, query, [(1,2,3),]) + self.assertRaises(Exception, cursor.executemany, query, [(1,),]) + + def connection_created_test(sender, **kwargs): print 'connection_created signal'