Ticket #9205: 9205-r9084-savepoints-in-save.diff

File 9205-r9084-savepoints-in-save.diff, 6.5 KB (added by Richard Davies <richard.davies@…>, 14 years ago)

Add savepoint protection to Model.save()

  • django/db/models/base.py

     
    1414from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField
    1515from django.db.models.query import delete_objects, Q, CollectedObjects
    1616from django.db.models.options import Options
    17 from django.db import connection, transaction, DatabaseError
     17from django.db import connection, transaction, DatabaseError, IntegrityError
    1818from django.db.models import signals
    1919from django.db.models.loading import register_models, get_model
    2020from django.utils.functional import curry
     
    304304        if force_insert and force_update:
    305305            raise ValueError("Cannot force both insert and updating in "
    306306                    "model saving.")
    307         self.save_base(force_insert=force_insert, force_update=force_update)
    308307
     308        try:
     309            sid = transaction.savepoint()
     310            self.save_base(force_insert=force_insert, force_update=force_update)
     311            transaction.savepoint_commit(sid)
     312        except IntegrityError:
     313            transaction.savepoint_rollback(sid)
     314            raise
     315
    309316    save.alters_data = True
    310317
    311318    def save_base(self, raw=False, cls=None, force_insert=False,
  • django/db/models/query.py

     
    329329                params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
    330330                params.update(defaults)
    331331                obj = self.model(**params)
    332                 sid = transaction.savepoint()
    333332                obj.save(force_insert=True)
    334                 transaction.savepoint_commit(sid)
    335333                return obj, True
    336334            except IntegrityError, e:
    337                 transaction.savepoint_rollback(sid)
    338335                try:
    339336                    return self.get(**kwargs), False
    340337                except self.model.DoesNotExist:
  • django/db/backends/__init__.py

     
    3434    def _savepoint(self, sid):
    3535        if not self.features.uses_savepoints:
    3636            return
    37         self.connection.cursor().execute(self.ops.savepoint_create_sql(sid))
     37        if self.connection is not None:
     38            self.connection.cursor().execute(self.ops.savepoint_create_sql(sid))
    3839
    3940    def _savepoint_rollback(self, sid):
    4041        if not self.features.uses_savepoints:
    4142            return
    42         self.connection.cursor().execute(self.ops.savepoint_rollback_sql(sid))
     43        if self.connection is not None:
     44            self.connection.cursor().execute(self.ops.savepoint_rollback_sql(sid))
    4345
    4446    def _savepoint_commit(self, sid):
    4547        if not self.features.uses_savepoints:
    4648            return
    47         self.connection.cursor().execute(self.ops.savepoint_commit_sql(sid))
     49        if self.connection is not None:
     50            self.connection.cursor().execute(self.ops.savepoint_commit_sql(sid))
    4851
    4952    def close(self):
    5053        if self.connection is not None:
  • django/contrib/sessions/backends/db.py

     
    5353            session_data = self.encode(self._get_session(no_load=must_create)),
    5454            expire_date = self.get_expiry_date()
    5555        )
    56         sid = transaction.savepoint()
    5756        try:
    5857            obj.save(force_insert=must_create)
    5958        except IntegrityError:
    6059            if must_create:
    61                 transaction.savepoint_rollback(sid)
    6260                raise CreateError
    6361            raise
    6462
  • tests/modeltests/force_insert_update/models.py

     
    4040>>> c1.save(force_insert=True)
    4141
    4242# Won't work because we can't insert a pk of the same value.
    43 >>> sid = transaction.savepoint()
    4443>>> c.value = 5
    4544>>> try:
    4645...     c.save(force_insert=True)
     
    5049...     else:
    5150...         print "Fail with %s" % type(e)
    5251Pass
    53 >>> transaction.savepoint_rollback(sid)
    5452
    5553# Trying to update should still fail, even with manual primary keys, if the
    5654# data isn't in the database already.
  • tests/modeltests/one_to_one/models.py

     
    178178
    179179# This will fail because each one-to-one field must be unique (and link2=o1 was
    180180# used for x1, above).
    181 >>> sid = transaction.savepoint()
    182181>>> try:
    183182...     MultiModel(link1=p2, link2=o1, name="x1").save()
    184183... except Exception, e:
     
    187186...     else:
    188187...         print "Fail with %s" % type(e)
    189188Pass
    190 >>> transaction.savepoint_rollback(sid)
    191189
    192190"""}
  • tests/modeltests/custom_pk/models.py

     
    110110# The primary key must also obviously be unique, so trying to create a new
    111111# object with the same primary key will fail.
    112112>>> try:
    113 ...    sid = transaction.savepoint()
    114113...    Employee.objects.create(employee_code=123, first_name='Fred', last_name='Jones')
    115 ...    transaction.savepoint_commit(sid)
    116114... except Exception, e:
    117115...    if isinstance(e, IntegrityError):
    118 ...        transaction.savepoint_rollback(sid)
    119116...        print "Pass"
    120117...    else:
    121118...        print "Fail with %s" % type(e)
     
    131128# The primary key must be specified, so an error is raised if you try to create
    132129# an object without it.
    133130>>> try:
    134 ...     sid = transaction.savepoint()
    135131...     Employee.objects.create(first_name='Tom', last_name='Smith')
    136132...     print 'hello'
    137 ...     transaction.savepoint_commit(sid)
    138133...     print 'hello2'
    139134... except Exception, e:
    140135...     if isinstance(e, IntegrityError):
    141 ...         transaction.savepoint_rollback(sid)
    142136...         print "Pass"
    143137...     else:
    144138...         print "Fail with %s" % type(e)
Back to Top