Ticket #15119: 15119-2.diff

File 15119-2.diff, 8.5 KB (added by Ramiro Morales, 12 years ago)
  • django/db/backends/mysql/base.py

    diff -r 7ff5d18dc66d django/db/backends/mysql/base.py
    a b  
    4747# It's impossible to import datetime_or_None directly from MySQLdb.times
    4848datetime_or_None = conversions[FIELD_TYPE.DATETIME]
    4949
     50RETRIES = 1
     51
    5052def datetime_or_None_with_timezone_support(value):
    5153    dt = datetime_or_None(value)
    5254    # Confirm that dt is naive before overwriting its tzinfo.
     
    9294    """
    9395    codes_for_integrityerror = (1048,)
    9496
    95     def __init__(self, cursor):
     97    def __init__(self, cursor, conn):
    9698        self.cursor = cursor
     99        self.django_conn = conn
    97100
    98101    def execute(self, query, args=None):
    99         try:
    100             return self.cursor.execute(query, args)
    101         except Database.IntegrityError, e:
    102             raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
    103         except Database.OperationalError, e:
    104             # Map some error codes to IntegrityError, since they seem to be
    105             # misclassified and Django would prefer the more logical place.
    106             if e[0] in self.codes_for_integrityerror:
     102        attempt = 0
     103        while True:
     104            try:
     105                return self.cursor.execute(query, args)
     106            except Database.IntegrityError, e:
    107107                raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
    108             raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
    109         except Database.DatabaseError, e:
    110             raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
     108            except Database.OperationalError, e:
     109                # Map some error codes to IntegrityError, since they seem to be
     110                # misclassified and Django would prefer the more logical place.
     111                if e[0] in self.codes_for_integrityerror:
     112                    raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
     113                if attempt < RETRIES:
     114                    attempt += 1
     115                    self.django_conn.reconnect()
     116                else:
     117                    raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
     118            except Database.DatabaseError, e:
     119                raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
     120            else:
     121                break
    111122
    112123    def executemany(self, query, args):
    113         try:
    114             return self.cursor.executemany(query, args)
    115         except Database.IntegrityError, e:
    116             raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
    117         except Database.OperationalError, e:
    118             # Map some error codes to IntegrityError, since they seem to be
    119             # misclassified and Django would prefer the more logical place.
    120             if e[0] in self.codes_for_integrityerror:
     124        attempt = 0
     125        while True:
     126            try:
     127                return self.cursor.executemany(query, args)
     128            except Database.IntegrityError, e:
    121129                raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
    122             raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
    123         except Database.DatabaseError, e:
    124             raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
     130            except Database.OperationalError, e:
     131                # Map some error codes to IntegrityError, since they seem to be
     132                # misclassified and Django would prefer the more logical place.
     133                if e[0] in self.codes_for_integrityerror:
     134                    raise utils.IntegrityError, utils.IntegrityError(*tuple(e)), sys.exc_info()[2]
     135                if attempt < RETRIES:
     136                    attempt += 1
     137                    self.django_conn.reconnect()
     138                else:
     139                    raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
     140            except Database.DatabaseError, e:
     141                raise utils.DatabaseError, utils.DatabaseError(*tuple(e)), sys.exc_info()[2]
     142            else:
     143                break
    125144
    126145    def __getattr__(self, attr):
    127146        if attr in self.__dict__:
     
    344363                self.connection = None
    345364        return False
    346365
     366    def reconnect(self):
     367        """Connects or reconnects to the MySQL server"""
     368        kwargs = {
     369            'conv': django_conversions,
     370            'charset': 'utf8',
     371            'use_unicode': True,
     372        }
     373        settings_dict = self.settings_dict
     374        if settings_dict['USER']:
     375            kwargs['user'] = settings_dict['USER']
     376        if settings_dict['NAME']:
     377            kwargs['db'] = settings_dict['NAME']
     378        if settings_dict['PASSWORD']:
     379            kwargs['passwd'] = settings_dict['PASSWORD']
     380        if settings_dict['HOST'].startswith('/'):
     381            kwargs['unix_socket'] = settings_dict['HOST']
     382        elif settings_dict['HOST']:
     383            kwargs['host'] = settings_dict['HOST']
     384        if settings_dict['PORT']:
     385            kwargs['port'] = int(settings_dict['PORT'])
     386        # We need the number of potentially affected rows after an
     387        # "UPDATE", not the number of changed rows.
     388        kwargs['client_flag'] = CLIENT.FOUND_ROWS
     389        kwargs.update(settings_dict['OPTIONS'])
     390        self.connection = Database.connect(**kwargs)
     391        self.connection.encoders[SafeUnicode] = self.connection.encoders[unicode]
     392        self.connection.encoders[SafeString] = self.connection.encoders[str]
     393        self.features.uses_savepoints = \
     394            self.get_server_version() >= (5, 0, 3)
     395        connection_created.send(sender=self.__class__, connection=self)
     396
    347397    def _cursor(self):
    348         new_connection = False
    349         if not self._valid_connection():
    350             new_connection = True
    351             kwargs = {
    352                 'conv': django_conversions,
    353                 'charset': 'utf8',
    354                 'use_unicode': True,
    355             }
    356             settings_dict = self.settings_dict
    357             if settings_dict['USER']:
    358                 kwargs['user'] = settings_dict['USER']
    359             if settings_dict['NAME']:
    360                 kwargs['db'] = settings_dict['NAME']
    361             if settings_dict['PASSWORD']:
    362                 kwargs['passwd'] = settings_dict['PASSWORD']
    363             if settings_dict['HOST'].startswith('/'):
    364                 kwargs['unix_socket'] = settings_dict['HOST']
    365             elif settings_dict['HOST']:
    366                 kwargs['host'] = settings_dict['HOST']
    367             if settings_dict['PORT']:
    368                 kwargs['port'] = int(settings_dict['PORT'])
    369             # We need the number of potentially affected rows after an
    370             # "UPDATE", not the number of changed rows.
    371             kwargs['client_flag'] = CLIENT.FOUND_ROWS
    372             kwargs.update(settings_dict['OPTIONS'])
    373             self.connection = Database.connect(**kwargs)
    374             self.connection.encoders[SafeUnicode] = self.connection.encoders[unicode]
    375             self.connection.encoders[SafeString] = self.connection.encoders[str]
    376             self.features.uses_savepoints = \
    377                 self.get_server_version() >= (5, 0, 3)
    378             connection_created.send(sender=self.__class__, connection=self)
    379         cursor = self.connection.cursor()
    380         if new_connection:
    381             # SQL_AUTO_IS_NULL in MySQL controls whether an AUTO_INCREMENT column
    382             # on a recently-inserted row will return when the field is tested for
    383             # NULL.  Disabling this value brings this aspect of MySQL in line with
    384             # SQL standards.
    385             cursor.execute('SET SQL_AUTO_IS_NULL = 0')
    386         return CursorWrapper(cursor)
     398        attempt = 0
     399        while True:
     400            try:
     401                cursor = self.connection.cursor()
     402            except (AttributeError, Database.OperationalError):
     403                if attempt < RETRIES:
     404                    attempt += 1
     405                    self.reconnect()
     406                else:
     407                    raise
     408            else:
     409                # SQL_AUTO_IS_NULL in MySQL controls whether an AUTO_INCREMENT column
     410                # on a recently-inserted row will return when the field is tested for
     411                # NULL.  Disabling this value brings this aspect of MySQL in line with
     412                # SQL standards.
     413                cursor.execute('SET SQL_AUTO_IS_NULL = 0')
     414                break
     415        return CursorWrapper(cursor, self)
    387416
    388417    def _rollback(self):
    389418        try:
Back to Top