summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRamiro Morales <cramm0@gmail.com>2010-10-23 00:11:50 +0000
committerRamiro Morales <cramm0@gmail.com>2010-10-23 00:11:50 +0000
commitf6de03b3a2cc8bb48369a58db59001bcd25c0988 (patch)
tree07ff595f7bd9807366c796e7a62d2fa9ba4773cd
parent7377e4f92d8f13ec649f478cac41cab35039eb40 (diff)
[1.2.X] Fixed #14223 -- Extended unification of exception raised in presence of integrity constraint violations.
The unification had been introduced in r12352 and native backend exceptions still slipped through in cases that end in connection.commit() call. Thanks Alex, Jacob and Carl for reviewing. Backport of [14320] from trunk git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@14321 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/db/backends/postgresql/base.py7
-rw-r--r--django/db/backends/postgresql_psycopg2/base.py7
-rw-r--r--tests/regressiontests/backends/models.py16
-rw-r--r--tests/regressiontests/backends/tests.py50
4 files changed, 75 insertions, 5 deletions
diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py
index f84ad1da61..5f4d791f02 100644
--- a/django/db/backends/postgresql/base.py
+++ b/django/db/backends/postgresql/base.py
@@ -150,6 +150,13 @@ class DatabaseWrapper(BaseDatabaseWrapper):
cursor.execute("SET client_encoding to 'UNICODE'")
return UnicodeCursorWrapper(cursor, 'utf-8')
+ def _commit(self):
+ if self.connection is not None:
+ try:
+ return self.connection.commit()
+ except Database.IntegrityError, e:
+ raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
+
def typecast_string(s):
"""
Cast all returned strings to unicode strings.
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
index ce4e48330e..c9f1af1669 100644
--- a/django/db/backends/postgresql_psycopg2/base.py
+++ b/django/db/backends/postgresql_psycopg2/base.py
@@ -189,3 +189,10 @@ class DatabaseWrapper(BaseDatabaseWrapper):
finally:
self.isolation_level = level
self.features.uses_savepoints = bool(level)
+
+ def _commit(self):
+ if self.connection is not None:
+ try:
+ return self.connection.commit()
+ except Database.IntegrityError, e:
+ raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
diff --git a/tests/regressiontests/backends/models.py b/tests/regressiontests/backends/models.py
index 4ab00414db..ea7ff96b91 100644
--- a/tests/regressiontests/backends/models.py
+++ b/tests/regressiontests/backends/models.py
@@ -1,5 +1,4 @@
from django.db import models
-from django.db import connection
class Square(models.Model):
root = models.IntegerField()
@@ -21,3 +20,18 @@ class SchoolClass(models.Model):
last_updated = models.DateTimeField()
+class Reporter(models.Model):
+ first_name = models.CharField(max_length=30)
+ last_name = models.CharField(max_length=30)
+
+ def __unicode__(self):
+ return u"%s %s" % (self.first_name, self.last_name)
+
+
+class Article(models.Model):
+ headline = models.CharField(max_length=100)
+ pub_date = models.DateField()
+ reporter = models.ForeignKey(Reporter)
+
+ def __unicode__(self):
+ return self.headline
diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
index d955a098af..005fc4d86e 100644
--- a/tests/regressiontests/backends/tests.py
+++ b/tests/regressiontests/backends/tests.py
@@ -1,13 +1,15 @@
# -*- coding: utf-8 -*-
# Unit and doctests for specific database backends.
import datetime
-import models
import unittest
-from django.db import backend, connection, DEFAULT_DB_ALIAS
+
+from django.conf import settings
+from django.db import backend, connection, DEFAULT_DB_ALIAS, IntegrityError
from django.db.backends.signals import connection_created
from django.db.backends.postgresql import version as pg_version
-from django.conf import settings
-from django.test import TestCase
+from django.test import TestCase, TransactionTestCase
+
+import models
class Callproc(unittest.TestCase):
@@ -141,6 +143,46 @@ class BackendTestCase(TestCase):
cursor.executemany(query, [])
self.assertEqual(models.Square.objects.count(), 11)
+
+# We don't make these tests conditional because that means we would need to
+# check and differentiate between:
+# * MySQL+InnoDB, MySQL+MYISAM (something we currently can't do).
+# * if sqlite3 (if/once we get #14204 fixed) has referential integrity turned
+# on or not, something that would be controlled by runtime support and user
+# preference.
+# verify if its type is django.database.db.IntegrityError.
+
+class FkConstraintsTests(TransactionTestCase):
+
+ def setUp(self):
+ # Create a Reporter.
+ self.r = models.Reporter.objects.create(first_name='John', last_name='Smith')
+
+ def test_integrity_checks_on_creation(self):
+ """
+ Try to create a model instance that violates a FK constraint. If it
+ fails it should fail with IntegrityError.
+ """
+ a = models.Article(headline="This is a test", pub_date=datetime.datetime(2005, 7, 27), reporter_id=30)
+ try:
+ a.save()
+ except IntegrityError:
+ pass
+
+ def test_integrity_checks_on_update(self):
+ """
+ Try to update a model instance introducing a FK constraint violation.
+ If it fails it should fail with IntegrityError.
+ """
+ # Create an Article.
+ models.Article.objects.create(headline="Test article", pub_date=datetime.datetime(2010, 9, 4), reporter=self.r)
+ # Retrive it from the DB
+ a = models.Article.objects.get(headline="Test article")
+ a.reporter_id = 30
+ try:
+ a.save()
+ except IntegrityError:
+ pass
def test_unicode_fetches(self):
#6254: fetchone, fetchmany, fetchall return strings as unicode objects
qn = connection.ops.quote_name