Commit 11ee9746 authored by Russell Keith-Magee's avatar Russell Keith-Magee
Browse files

Fixed #12702 -- Introduced a common implementation of DatabaseError and...

Fixed #12702 -- Introduced a common implementation of DatabaseError and IntegrityError, so that database backends can (re)raise common error classes. Thanks for Waldemar Kornewald for the report.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12352 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 47acb1d6
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
from django.conf import settings
from django.core import signals
from django.core.exceptions import ImproperlyConfigured
from django.db.utils import ConnectionHandler, ConnectionRouter, load_backend, DEFAULT_DB_ALIAS
from django.db.utils import ConnectionHandler, ConnectionRouter, load_backend, DEFAULT_DB_ALIAS, \
                            DatabaseError, IntegrityError
from django.utils.functional import curry

__all__ = ('backend', 'connection', 'connections', 'router', 'DatabaseError',
@@ -73,8 +74,6 @@ router = ConnectionRouter(settings.DATABASE_ROUTERS)
# connections['default'] instead.
connection = connections[DEFAULT_DB_ALIAS]
backend = load_backend(connection.settings_dict['ENGINE'])
DatabaseError = backend.DatabaseError
IntegrityError = backend.IntegrityError

# Register an event that closes the database connection
# when a Django request is finished.
+12 −2
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ Requires MySQLdb: http://sourceforge.net/projects/mysql-python
"""

import re
import sys

try:
    import MySQLdb as Database
@@ -24,6 +25,7 @@ if (version < (1,2,1) or (version[:3] == (1, 2, 1) and
from MySQLdb.converters import conversions
from MySQLdb.constants import FIELD_TYPE, FLAG, CLIENT

from django.db import utils
from django.db.backends import *
from django.db.backends.signals import connection_created
from django.db.backends.mysql.client import DatabaseClient
@@ -82,22 +84,30 @@ class CursorWrapper(object):
    def execute(self, query, args=None):
        try:
            return self.cursor.execute(query, args)
        except Database.IntegrityError, e:
            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
        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 utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
            raise
        except Database.DatabaseError, e:
            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]

    def executemany(self, query, args):
        try:
            return self.cursor.executemany(query, args)
        except Database.IntegrityError, e:
            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
        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 utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
            raise
        except Database.DatabaseError, e:
            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]

    def __getattr__(self, attr):
        if attr in self.__dict__:
+14 −7
Original line number Diff line number Diff line
@@ -4,8 +4,10 @@ Oracle database backend for Django.
Requires cx_Oracle: http://cx-oracle.sourceforge.net/
"""

import os

import datetime
import os
import sys
import time
try:
    from decimal import Decimal
@@ -24,6 +26,7 @@ except ImportError, e:
    from django.core.exceptions import ImproperlyConfigured
    raise ImproperlyConfigured("Error loading cx_Oracle module: %s" % e)

from django.db import utils
from django.db.backends import *
from django.db.backends.signals import connection_created
from django.db.backends.oracle.client import DatabaseClient
@@ -480,11 +483,13 @@ class FormatStylePlaceholderCursor(object):
        self._guess_input_sizes([params])
        try:
            return self.cursor.execute(query, self._param_generator(params))
        except DatabaseError, e:
        except Database.IntegrityError, e:
            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
        except Database.DatabaseError, e:
            # cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400.
            if e.args[0].code == 1400 and not isinstance(e, IntegrityError):
                e = IntegrityError(e.args[0])
            raise e
                raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]

    def executemany(self, query, params=None):
        try:
@@ -504,11 +509,13 @@ class FormatStylePlaceholderCursor(object):
        try:
            return self.cursor.executemany(query,
                                [self._param_generator(p) for p in formatted])
        except DatabaseError, e:
        except Database.IntegrityError, e:
            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
        except Database.DatabaseError, e:
            # cx_Oracle <= 4.4.0 wrongly raises a DatabaseError for ORA-01400.
            if e.args[0].code == 1400 and not isinstance(e, IntegrityError):
                e = IntegrityError(e.args[0])
            raise e
                raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]

    def fetchone(self):
        row = self.cursor.fetchone()
+16 −3
Original line number Diff line number Diff line
@@ -4,6 +4,9 @@ PostgreSQL database backend for Django.
Requires psycopg 1: http://initd.org/projects/psycopg1
"""

import sys

from django.db import utils
from django.db.backends import *
from django.db.backends.signals import connection_created
from django.db.backends.postgresql.client import DatabaseClient
@@ -50,11 +53,21 @@ class UnicodeCursorWrapper(object):
            return tuple([smart_str(p, self.charset, True) for p in params])

    def execute(self, sql, params=()):
        return self.cursor.execute(smart_str(sql, self.charset), self.format_params(params))
        try:
            return self.cursor.execute(query, args)
        except Database.IntegrityError, e:
            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
        except Database.DatabaseError, e:
            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]

    def executemany(self, sql, param_list):
        try:
            new_param_list = [self.format_params(params) for params in param_list]
            return self.cursor.executemany(sql, new_param_list)
        except Database.IntegrityError, e:
            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
        except Database.DatabaseError, e:
            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]

    def __getattr__(self, attr):
        if attr in self.__dict__:
+38 −1
Original line number Diff line number Diff line
@@ -4,6 +4,9 @@ PostgreSQL database backend for Django.
Requires psycopg 2: http://initd.org/projects/psycopg2
"""

import sys

from django.db import utils
from django.db.backends import *
from django.db.backends.signals import connection_created
from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
@@ -27,6 +30,40 @@ psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_adapter(SafeString, psycopg2.extensions.QuotedString)
psycopg2.extensions.register_adapter(SafeUnicode, psycopg2.extensions.QuotedString)

class CursorWrapper(object):
    """
    A thin wrapper around psycopg2's normal cursor class so that we can catch
    particular exception instances and reraise them with the right types.
    """

    def __init__(self, cursor):
        self.cursor = cursor

    def execute(self, query, args=None):
        try:
            return self.cursor.execute(query, args)
        except Database.IntegrityError, e:
            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
        except Database.DatabaseError, e:
            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]

    def executemany(self, query, args):
        try:
            return self.cursor.executemany(query, args)
        except Database.IntegrityError, e:
            raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
        except Database.DatabaseError, e:
            raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]

    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):
    needs_datetime_string_cast = False
    can_return_id_from_insert = False
@@ -118,7 +155,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
                    # versions that support it, but, right now, that's hard to
                    # do without breaking other things (#10509).
                    self.features.can_return_id_from_insert = True
        return cursor
        return CursorWrapper(cursor)

    def _enter_transaction_management(self, managed):
        """
Loading