summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-08-29 04:30:07 +0000
committerMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-08-29 04:30:07 +0000
commit90279aeaf07222dd7388956bfd465d30365087a5 (patch)
tree64c2a67829d9601307e3455d81e2d3d716353e34
parent54f41e3507bee76b5e1556b25ddbb57c47c8b84b (diff)
Fixed #8575 -- Catch one particular instance of OperationalError in MySQL and
convert it to an IntegrityError, which seems like the more natural case (and is consistent with other backends). This makes exception handling in Django much easier. The solution is extensible for any other error codes we may wish to add going forwards. git-svn-id: http://code.djangoproject.com/svn/django/trunk@8692 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/db/backends/mysql/base.py44
1 files changed, 43 insertions, 1 deletions
diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
index 07fb700eaa..b93453bc1e 100644
--- a/django/db/backends/mysql/base.py
+++ b/django/db/backends/mysql/base.py
@@ -65,6 +65,48 @@ server_version_re = re.compile(r'(\d{1,2})\.(\d{1,2})\.(\d{1,2})')
# standard util.CursorDebugWrapper can be used. Also, using sql_mode
# TRADITIONAL will automatically cause most warnings to be treated as errors.
+class CursorWrapper(object):
+ """
+ A thin wrapper around MySQLdb's normal cursor class so that we can catch
+ particular exception instances and reraise them with the right types.
+
+ Implemented as a wrapper, rather than a subclass, so that we aren't stuck
+ to the particular underlying representation returned by Connection.cursor().
+ """
+ codes_for_integrityerror = (1048,)
+
+ def __init__(self, cursor):
+ self.cursor = cursor
+
+ def execute(self, query, args=None):
+ try:
+ return self.cursor.execute(query, args)
+ except Database.OperationalError, e:
+ # Map some error codes to IntegrityError, since they seem to be
+ # misclassified and Django would prefer the more logical place.
+ if e[0] in self.codes_for_integrityerror:
+ raise Database.IntegrityError(tuple(e))
+ raise
+
+ def executemany(self, query, args):
+ try:
+ return self.cursor.executemany(query, args)
+ except Database.OperationalError, e:
+ # Map some error codes to IntegrityError, since they seem to be
+ # misclassified and Django would prefer the more logical place.
+ if e[0] in self.codes_for_integrityerror:
+ raise Database.IntegrityError(tuple(e))
+ raise
+
+ def __getattr__(self, attr):
+ if attr in self.__dict__:
+ return self.__dict__[attr]
+ else:
+ return getattr(self.cursor, attr)
+
+ def __iter__(self):
+ return iter(self.cursor)
+
class DatabaseFeatures(BaseDatabaseFeatures):
empty_fetchmany_value = ()
update_can_self_select = False
@@ -207,7 +249,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
kwargs['port'] = int(settings.DATABASE_PORT)
kwargs.update(self.options)
self.connection = Database.connect(**kwargs)
- cursor = self.connection.cursor()
+ cursor = CursorWrapper(self.connection.cursor())
return cursor
def _rollback(self):