summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2010-03-23 14:08:31 +0000
committerRussell Keith-Magee <russell@keith-magee.com>2010-03-23 14:08:31 +0000
commit752856530f94cd3579813d6474020459cc80730a (patch)
tree64014033eabc7b37681a048715770514dc27df3f
parentef41bd405e703f0881c4d6bc2c2a54146c965373 (diff)
[1.1.X] Fixed #12612 -- Corrected handling of parameter formatting in SQLite backend so that executemany raises exceptions when bad parameter counts are provided. Thanks to Niels <niels@pythonheads.nl> for the report, and Gabriel Hurley for the help narrowing down the problem.
Backport of r12836 from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.1.X@12837 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/db/backends/sqlite3/base.py18
-rw-r--r--tests/regressiontests/backends/tests.py13
2 files changed, 22 insertions, 9 deletions
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'