Ticket #11156: 12037.diff
File 12037.diff, 13.1 KB (added by , 15 years ago) |
---|
-
django/db/models/query.py
364 364 params = dict([(k, v) for k, v in kwargs.items() if '__' not in k]) 365 365 params.update(defaults) 366 366 obj = self.model(**params) 367 sid = transaction.savepoint(using=self.db )367 sid = transaction.savepoint(using=self.db, only_if_needed=True) 368 368 obj.save(force_insert=True, using=self.db) 369 transaction.savepoint_commit(sid, using=self.db) 369 transaction.savepoint_commit(sid, using=self.db, 370 only_if_needed=True) 370 371 return obj, True 371 372 except IntegrityError, e: 372 transaction.savepoint_rollback(sid, using=self.db) 373 transaction.savepoint_rollback(sid, using=self.db, 374 only_if_needed=True) 373 375 try: 374 376 return self.get(**kwargs), False 375 377 except self.model.DoesNotExist: -
django/db/backends/postgresql/base.py
67 67 68 68 class DatabaseFeatures(BaseDatabaseFeatures): 69 69 uses_savepoints = True 70 needs_savepoint_on_exception = True 70 71 71 72 class DatabaseWrapper(BaseDatabaseWrapper): 72 73 operators = { … … 124 125 if self._version[0:2] < (8, 0): 125 126 # No savepoint support for earlier version of PostgreSQL. 126 127 self.features.uses_savepoints = False 128 # Transactions will just break on exceptions 129 # and there's nothing we can do about it 130 self.features.needs_savepoint_on_exception = False 127 131 cursor.execute("SET client_encoding to 'UNICODE'") 128 132 cursor = UnicodeCursorWrapper(cursor, 'utf-8') 129 133 return cursor -
django/db/backends/__init__.py
50 50 """ 51 51 pass 52 52 53 def _savepoint(self, sid ):53 def _savepoint(self, sid, only_if_needed=False): 54 54 if not self.features.uses_savepoints: 55 55 return 56 if only_if_needed and not self.features.needs_savepoint_on_exception: 57 return 56 58 self.cursor().execute(self.ops.savepoint_create_sql(sid)) 57 59 58 def _savepoint_rollback(self, sid ):60 def _savepoint_rollback(self, sid, only_if_needed=False): 59 61 if not self.features.uses_savepoints: 60 62 return 63 if only_if_needed and not self.features.needs_savepoint_on_exception: 64 return 61 65 self.cursor().execute(self.ops.savepoint_rollback_sql(sid)) 62 66 63 def _savepoint_commit(self, sid ):67 def _savepoint_commit(self, sid, only_if_needed=False): 64 68 if not self.features.uses_savepoints: 65 69 return 70 if only_if_needed and not self.features.needs_savepoint_on_exception: 71 return 66 72 self.cursor().execute(self.ops.savepoint_commit_sql(sid)) 67 73 68 74 def close(self): … … 92 98 can_return_id_from_insert = False 93 99 uses_autocommit = False 94 100 uses_savepoints = False 101 needs_savepoint_on_exception = False 95 102 # If True, don't use integer foreign keys referring to, e.g., positive 96 103 # integer primary keys. 97 104 related_fields_match_type = False -
django/db/backends/postgresql_psycopg2/base.py
107 107 if self._version[0:2] < (8, 0): 108 108 # No savepoint support for earlier version of PostgreSQL. 109 109 self.features.uses_savepoints = False 110 # Transactions will just break on exceptions 111 # and there's nothing we can do about it 112 self.features.needs_savepoint_on_exception = False 110 113 if self.features.uses_autocommit: 111 114 if self._version[0:2] < (8, 2): 112 115 # FIXME: Needs extra code to do reliable model insert … … 149 152 finally: 150 153 self.isolation_level = level 151 154 self.features.uses_savepoints = bool(level) 155 self.features.needs_savepoint_on_exception = bool(level) -
django/db/transaction.py
209 209 connection._rollback() 210 210 set_clean(using=using) 211 211 212 def savepoint(using=None ):212 def savepoint(using=None, only_if_needed=False): 213 213 """ 214 214 Creates a savepoint (if supported and required by the backend) inside the 215 215 current transaction. Returns an identifier for the savepoint that will be … … 226 226 savepoint_state[thread_ident][using] = [None] 227 227 tid = str(thread_ident).replace('-', '') 228 228 sid = "s%s_x%d" % (tid, len(savepoint_state[thread_ident][using])) 229 connection._savepoint(sid )229 connection._savepoint(sid, only_if_needed) 230 230 return sid 231 231 232 def savepoint_rollback(sid, using=None ):232 def savepoint_rollback(sid, using=None, only_if_needed=False): 233 233 """ 234 234 Rolls back the most recent savepoint (if one exists). Does nothing if 235 savepoints are not supported. 235 savepoints are not supported, or if only_if_needed is set and the backend 236 does not need to use savepoints to recover from exceptions. 236 237 """ 237 238 if using is None: 238 239 using = DEFAULT_DB_ALIAS 239 240 connection = connections[using] 240 241 thread_ident = thread.get_ident() 241 242 if thread_ident in savepoint_state and using in savepoint_state[thread_ident]: 242 connection._savepoint_rollback(sid )243 connection._savepoint_rollback(sid, only_if_needed) 243 244 244 def savepoint_commit(sid, using=None ):245 def savepoint_commit(sid, using=None, only_if_needed=False): 245 246 """ 246 247 Commits the most recent savepoint (if one exists). Does nothing if 247 savepoints are not supported. 248 savepoints are not supported, or if only_if_needed is set and the backend 249 does not need to use savepoints to recover from exceptions. 248 250 """ 249 251 if using is None: 250 252 using = DEFAULT_DB_ALIAS 251 253 connection = connections[using] 252 254 thread_ident = thread.get_ident() 253 255 if thread_ident in savepoint_state and using in savepoint_state[thread_ident]: 254 connection._savepoint_commit(sid )256 connection._savepoint_commit(sid, only_if_needed) 255 257 256 258 ############## 257 259 # DECORATORS # -
django/contrib/sessions/backends/db.py
58 58 session_data = self.encode(self._get_session(no_load=must_create)), 59 59 expire_date = self.get_expiry_date() 60 60 ) 61 sid = transaction.savepoint(using=self.using )61 sid = transaction.savepoint(using=self.using, only_if_needed=True) 62 62 try: 63 63 obj.save(force_insert=must_create) 64 64 except IntegrityError: 65 65 if must_create: 66 transaction.savepoint_rollback(sid, using=self.using) 66 transaction.savepoint_rollback(sid, using=self.using, 67 only_if_needed=True) 67 68 raise CreateError 68 69 raise 69 70 -
tests/modeltests/force_insert_update/models.py
40 40 >>> c1.save(force_insert=True) 41 41 42 42 # Won't work because we can't insert a pk of the same value. 43 >>> sid = transaction.savepoint( )43 >>> sid = transaction.savepoint(only_if_needed=True) 44 44 >>> c.value = 5 45 45 >>> try: 46 46 ... c.save(force_insert=True) … … 50 50 ... else: 51 51 ... print "Fail with %s" % type(e) 52 52 Pass 53 >>> transaction.savepoint_rollback(sid )53 >>> transaction.savepoint_rollback(sid, only_if_needed=True) 54 54 55 55 # Trying to update should still fail, even with manual primary keys, if the 56 56 # data isn't in the database already. -
tests/modeltests/one_to_one/models.py
180 180 181 181 # This will fail because each one-to-one field must be unique (and link2=o1 was 182 182 # used for x1, above). 183 >>> sid = transaction.savepoint( )183 >>> sid = transaction.savepoint(only_if_needed=True) 184 184 >>> try: 185 185 ... MultiModel(link1=p2, link2=o1, name="x1").save() 186 186 ... except Exception, e: … … 189 189 ... else: 190 190 ... print "Fail with %s" % type(e) 191 191 Pass 192 >>> transaction.savepoint_rollback(sid )192 >>> transaction.savepoint_rollback(sid, only_if_needed=True) 193 193 194 194 """} -
tests/modeltests/custom_pk/models.py
122 122 # The primary key must also obviously be unique, so trying to create a new 123 123 # object with the same primary key will fail. 124 124 >>> try: 125 ... sid = transaction.savepoint( )125 ... sid = transaction.savepoint(only_if_needed=True) 126 126 ... Employee.objects.create(employee_code=123, first_name='Fred', last_name='Jones') 127 ... transaction.savepoint_commit(sid )127 ... transaction.savepoint_commit(sid, only_if_needed=True) 128 128 ... except Exception, e: 129 129 ... if isinstance(e, IntegrityError): 130 ... transaction.savepoint_rollback(sid )130 ... transaction.savepoint_rollback(sid, only_if_needed=True) 131 131 ... print "Pass" 132 132 ... else: 133 133 ... print "Fail with %s" % type(e) … … 161 161 # The primary key must be specified, so an error is raised if you try to create 162 162 # an object without it. 163 163 >>> try: 164 ... sid = transaction.savepoint( )164 ... sid = transaction.savepoint(only_if_needed=True) 165 165 ... Employee.objects.create(first_name='Tom', last_name='Smith') 166 166 ... print 'hello' 167 ... transaction.savepoint_commit(sid )167 ... transaction.savepoint_commit(sid, only_if_needed=True) 168 168 ... print 'hello2' 169 169 ... except Exception, e: 170 170 ... if isinstance(e, IntegrityError): 171 ... transaction.savepoint_rollback(sid )171 ... transaction.savepoint_rollback(sid, only_if_needed=True) 172 172 ... print "Pass" 173 173 ... else: 174 174 ... print "Fail with %s" % type(e) -
docs/topics/db/transactions.txt
191 191 192 192 Savepoints are controlled by three methods on the transaction object: 193 193 194 .. method:: transaction.savepoint(using=None )194 .. method:: transaction.savepoint(using=None, only_if_needed=False) 195 195 196 196 Creates a new savepoint. This marks a point in the transaction that 197 197 is known to be in a "good" state. 198 198 199 199 Returns the savepoint ID (sid). 200 200 201 .. method:: transaction.savepoint_commit(sid, using=None )201 .. method:: transaction.savepoint_commit(sid, using=None, only_if_needed=False) 202 202 203 203 Updates the savepoint to include any operations that have been performed 204 204 since the savepoint was created, or since the last commit. 205 205 206 .. method:: transaction.savepoint_rollback(sid, using=None )206 .. method:: transaction.savepoint_rollback(sid, using=None, only_if_needed=False) 207 207 208 208 Rolls the transaction back to the last point at which the savepoint was 209 209 committed. 210 210 211 .. note:: 212 213 The ``only_if_needed`` flag is an advanced option, which is used in the 214 context described under "Handling exceptions within PostgreSQL 215 transactions", below. 216 211 217 The following example demonstrates the use of savepoints:: 212 218 213 219 from django.db import transaction … … 288 294 289 295 a.save() # Succeeds, and never undone by savepoint rollback 290 296 try: 291 sid = transaction.savepoint( )297 sid = transaction.savepoint(only_if_needed=True) 292 298 b.save() # Could throw exception 293 transaction.savepoint_commit(sid )299 transaction.savepoint_commit(sid, only_if_needed=True) 294 300 except IntegrityError: 295 transaction.savepoint_rollback(sid )301 transaction.savepoint_rollback(sid, only_if_needed=True) 296 302 c.save() # Succeeds, and a.save() is never undone 297 303 298 304 In this example, ``a.save()`` will not be undone in the case where 299 ``b.save()`` raises an exception. 305 ``b.save()`` raises an exception. The ``only_if_needed`` flag means that the 306 savepoint code will only be executed on databases such as PostgreSQL which 307 require it to recover from exceptions, not on other databases. 300 308 301 309 Database-level autocommit 302 310 -------------------------