diff -r 7145c0852013 django/db/__init__.py
--- a/django/db/__init__.py	Thu Jan 28 13:46:18 2010 +0000
+++ b/django/db/__init__.py	Fri Jan 29 20:22:25 2010 +0800
@@ -1,7 +1,8 @@
 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 @@
 # 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.
diff -r 7145c0852013 django/db/backends/mysql/base.py
--- a/django/db/backends/mysql/base.py	Thu Jan 28 13:46:18 2010 +0000
+++ b/django/db/backends/mysql/base.py	Fri Jan 29 20:22:25 2010 +0800
@@ -5,6 +5,7 @@
 """
 
 import re
+import sys
 
 try:
     import MySQLdb as Database
@@ -24,6 +25,7 @@
 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,23 +84,30 @@
     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__:
             return self.__dict__[attr]
diff -r 7145c0852013 django/db/backends/oracle/base.py
--- a/django/db/backends/oracle/base.py	Thu Jan 28 13:46:18 2010 +0000
+++ b/django/db/backends/oracle/base.py	Fri Jan 29 20:22:25 2010 +0800
@@ -4,8 +4,10 @@
 Requires cx_Oracle: http://cx-oracle.sourceforge.net/
 """
 
+
+import datetime
 import os
-import datetime
+import sys
 import time
 try:
     from decimal import Decimal
@@ -24,6 +26,7 @@
     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 @@
         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 @@
         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()
diff -r 7145c0852013 django/db/backends/postgresql/base.py
--- a/django/db/backends/postgresql/base.py	Thu Jan 28 13:46:18 2010 +0000
+++ b/django/db/backends/postgresql/base.py	Fri Jan 29 20:22:25 2010 +0800
@@ -4,6 +4,9 @@
 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 @@
             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):
-        new_param_list = [self.format_params(params) for params in param_list]
-        return self.cursor.executemany(sql, new_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__:
diff -r 7145c0852013 django/db/backends/postgresql_psycopg2/base.py
--- a/django/db/backends/postgresql_psycopg2/base.py	Thu Jan 28 13:46:18 2010 +0000
+++ b/django/db/backends/postgresql_psycopg2/base.py	Fri Jan 29 20:22:25 2010 +0800
@@ -4,6 +4,9 @@
 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_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 @@
                     # 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):
         """
diff -r 7145c0852013 django/db/backends/sqlite3/base.py
--- a/django/db/backends/sqlite3/base.py	Thu Jan 28 13:46:18 2010 +0000
+++ b/django/db/backends/sqlite3/base.py	Fri Jan 29 20:22:25 2010 +0800
@@ -7,6 +7,9 @@
 standard library.
 """
 
+import sys
+
+from django.db import utils
 from django.db.backends import *
 from django.db.backends.signals import connection_created
 from django.db.backends.sqlite3.client import DatabaseClient
@@ -185,16 +188,25 @@
     you'll need to use "%%s".
     """
     def execute(self, query, params=()):
-        query = self.convert_query(query, len(params))
-        return Database.Cursor.execute(self, query, params)
+        try:
+            query = self.convert_query(query, len(params))
+            return Database.Cursor.execute(self, query, params)
+        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, param_list):
         try:
-          query = self.convert_query(query, len(param_list[0]))
-          return Database.Cursor.executemany(self, query, param_list)
+            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
+            # No parameter list provided
+            return None
+        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 convert_query(self, query, num_params):
         return query % tuple("?" * num_params)
diff -r 7145c0852013 django/db/utils.py
--- a/django/db/utils.py	Thu Jan 28 13:46:18 2010 +0000
+++ b/django/db/utils.py	Fri Jan 29 20:22:25 2010 +0800
@@ -7,6 +7,16 @@
 
 DEFAULT_DB_ALIAS = 'default'
 
+# Define some exceptions that mirror the PEP249 interface.
+# We will rethrow any backend-specific errors using these
+# common wrappers
+class DatabaseError(Exception):
+    pass
+
+class IntegrityError(DatabaseError):
+    pass
+
+
 def load_backend(backend_name):
     try:
         module = import_module('.base', 'django.db.backends.%s' % backend_name)
@@ -40,9 +50,11 @@
             else:
                 raise # If there's some other error, this must be an error in Django itself.
 
+
 class ConnectionDoesNotExist(Exception):
     pass
 
+
 class ConnectionHandler(object):
     def __init__(self, databases):
         self.databases = databases
@@ -87,6 +99,7 @@
     def all(self):
         return [self[alias] for alias in self]
 
+
 class ConnectionRouter(object):
     def __init__(self, routers):
         self.routers = []
