Skip to content

Commit

Permalink
Fixed #14223 -- Extended unification of exception raised in presence …
Browse files Browse the repository at this point in the history
…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.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14320 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
ramiro committed Oct 23, 2010
1 parent cad4fea commit cfdad9e
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 6 deletions.
7 changes: 7 additions & 0 deletions django/db/backends/postgresql/base.py
Expand Up @@ -153,6 +153,13 @@ def _cursor(self):
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.
Expand Down
7 changes: 7 additions & 0 deletions django/db/backends/postgresql_psycopg2/base.py
Expand Up @@ -192,3 +192,10 @@ def _set_isolation_level(self, level):
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]
18 changes: 16 additions & 2 deletions tests/regressiontests/backends/models.py
@@ -1,8 +1,7 @@
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.conf import settings
from django.db import models
from django.db import connection, DEFAULT_DB_ALIAS
from django.db import connection


class Square(models.Model):
Expand Down Expand Up @@ -55,3 +54,18 @@ class Meta:
db_table = 'CaseSensitive_Post'


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
46 changes: 42 additions & 4 deletions tests/regressiontests/backends/tests.py
Expand Up @@ -2,13 +2,11 @@
# Unit and doctests for specific database backends.
import datetime

from django.conf import settings
from django.core import management
from django.core.management.color import no_style
from django.db import backend, connection, connections, DEFAULT_DB_ALIAS
from django.db import backend, connection, connections, DEFAULT_DB_ALIAS, IntegrityError
from django.db.backends.signals import connection_created
from django.db.backends.postgresql import version as pg_version
from django.test import TestCase, skipUnlessDBFeature
from django.test import TestCase, skipUnlessDBFeature, TransactionTestCase
from django.utils import unittest

from regressiontests.backends import models
Expand Down Expand Up @@ -225,3 +223,43 @@ def test_unicode_fetches(self):
self.assertEqual(list(cursor.fetchmany(2)), [(u'Jane', u'Doe'), (u'John', u'Doe')])
self.assertEqual(list(cursor.fetchall()), [(u'Mary', u'Agnelline'), (u'Peter', u'Parker')])


# 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

0 comments on commit cfdad9e

Please sign in to comment.