Ticket #3460: 3640_r9736-autocommit-safe.diff

File 3640_r9736-autocommit-safe.diff, 8.0 KB (added by iamseb, 6 years ago)
  • django/db/models/sql/subqueries.py

     
    304304        result = ['INSERT INTO %s' % qn(self.model._meta.db_table)]
    305305        result.append('(%s)' % ', '.join([qn(c) for c in self.columns]))
    306306        result.append('VALUES (%s)' % ', '.join(self.values))
     307        if self.connection.features.can_return_id_from_insert:
     308            result.append('RETURNING %s.%s' % (qn(self.model._meta.db_table),
     309                                 qn(self.model._meta.pk.column)))
     310
    307311        return ' '.join(result), self.params
    308312
    309313    def execute_sql(self, return_id=False):
    310314        cursor = super(InsertQuery, self).execute_sql(None)
    311         if return_id:
     315        if return_id and self.connection.features.can_return_id_from_insert:
     316            row_id = cursor.fetchone()[0]
     317            return row_id
     318        elif return_id:
    312319            return self.connection.ops.last_insert_id(cursor,
    313320                    self.model._meta.db_table, self.model._meta.pk.column)
    314321
  • django/db/backends/__init__.py

     
    3131        if self.connection is not None:
    3232            return self.connection.rollback()
    3333
     34    def _enter_transaction_management(self, managed):
     35        pass
     36
     37    def _leave_transaction_management(self, managed):
     38        pass
     39
    3440    def _savepoint(self, sid):
    3541        if not self.features.uses_savepoints:
    3642            return
     
    7480    # If True, don't use integer foreign keys referring to, e.g., positive
    7581    # integer primary keys.
    7682    related_fields_match_type = False
     83    native_autocommit = False
     84    can_return_id_from_insert = False
    7785
    7886class BaseDatabaseOperations(object):
    7987    """
  • django/db/backends/postgresql_psycopg2/base.py

     
    44Requires psycopg 2: http://initd.org/projects/psycopg2
    55"""
    66
     7from django.conf import settings
    78from django.db.backends import *
    89from django.db.backends.postgresql.operations import DatabaseOperations as PostgresqlDatabaseOperations
    910from django.db.backends.postgresql.client import DatabaseClient
     
    2829
    2930class DatabaseFeatures(BaseDatabaseFeatures):
    3031    needs_datetime_string_cast = False
    31     uses_savepoints = True
    3232
    3333class DatabaseOperations(PostgresqlDatabaseOperations):
    3434    def last_executed_query(self, cursor, sql, params):
     
    5959        super(DatabaseWrapper, self).__init__(*args, **kwargs)
    6060       
    6161        self.features = DatabaseFeatures()
     62        if settings.DATABASE_OPTIONS.get('native_autocommit', False):
     63          self.features.native_autocommit = True
     64          self.features.uses_savepoints = False
     65          self.features.can_return_id_from_insert = True
     66          self._isolation_level = 0
     67        else:
     68          self.features.native_autocommit = False
     69          self.features.uses_savepoints = True
     70          self.features.can_return_id_from_insert = False
     71          self._isolation_level = 1
    6272        self.ops = DatabaseOperations()
    6373        self.client = DatabaseClient()
    6474        self.creation = DatabaseCreation(self)
    6575        self.introspection = DatabaseIntrospection(self)
    6676        self.validation = BaseDatabaseValidation()
     77 
     78    def _enter_transaction_management(self, managed):
     79        """Manages the mapping of transaction management to isolation levels"""
    6780
     81        if self.features.native_autocommit and managed and self._isolation_level == 0:
     82            try:
     83                if self.connection != None:
     84                    self.connection.set_isolation_level(1)
     85            finally:
     86                self._isolation_level = 1
     87                self.features.uses_savepoints = True
     88
     89    def _leave_transaction_management(self, managed):
     90        """Manages the mapping of transaction management to isolation levels"""
     91
     92        if self.features.native_autocommit and not managed and self._isolation_level == 1:
     93            try:
     94                if self.connection != None:
     95                    self.connection.set_isolation_level(0)
     96            finally:
     97                self._isolation_level = 0
     98                self.features.uses_savepoints = False
     99
    68100    def _cursor(self, settings):
    69101        set_tz = False
    70102        if self.connection is None:
     
    81113                conn_string += " host=%s" % settings.DATABASE_HOST
    82114            if settings.DATABASE_PORT:
    83115                conn_string += " port=%s" % settings.DATABASE_PORT
    84             self.connection = Database.connect(conn_string, **self.options)
    85             self.connection.set_isolation_level(1) # make transactions transparent to all cursors
     116            x = self.options.copy()
     117            x.pop('native_autocommit', '')
     118            self.connection = Database.connect(conn_string, **x)
     119            self.connection.set_isolation_level(self._isolation_level)
    86120            self.connection.set_client_encoding('UTF8')
    87121        cursor = self.connection.cursor()
    88122        cursor.tzinfo_factory = None
  • django/db/transaction.py

     
    4040# database commit.
    4141dirty = {}
    4242
    43 def enter_transaction_management():
     43def enter_transaction_management(managed=True):
    4444    """
    4545    Enters transaction management for a running thread. It must be balanced with
    4646    the appropriate leave_transaction_management call, since the actual state is
     
    5858        state[thread_ident].append(settings.TRANSACTIONS_MANAGED)
    5959    if thread_ident not in dirty:
    6060        dirty[thread_ident] = False
     61    connection._enter_transaction_management(managed)
    6162
    6263def leave_transaction_management():
    6364    """
     
    6566    over to the surrounding block, as a commit will commit all changes, even
    6667    those from outside. (Commits are on connection level.)
    6768    """
     69    connection._leave_transaction_management(is_managed())
    6870    thread_ident = thread.get_ident()
    6971    if thread_ident in state and state[thread_ident]:
    7072        del state[thread_ident][-1]
     
    216218    """
    217219    def _autocommit(*args, **kw):
    218220        try:
    219             enter_transaction_management()
     221            enter_transaction_management(managed=False)
    220222            managed(False)
    221223            return func(*args, **kw)
    222224        finally:
  • docs/ref/databases.txt

     
    260260column types have a maximum length restriction of 255 characters, regardless
    261261of whether ``unique=True`` is specified or not.
    262262
     263.. _postgresql-notes:
     264
     265PostgreSQL notes
     266================
     267
     268Django supports PostgreSQL using the psycopg_ package. Django supports both
     269version 1 and 2. (When you configure Django's database layer, specify either
     270``postgresql`` [for version 1] or ``postgresql_psycopg2`` [for version 2].)
     271
     272Native Autocommit
     273-----------------
     274
     275By default, Django database backends run with a permanently open
     276transaction, as per the Python DB-API. Django simulates autocommit behaviour
     277by committing this transaction automatically (e.g. in ``save()``). For
     278PostgreSQL, this corresponds to running in ``set_isolation_level(1)``.
     279
     280For higher performance, ``postgresql_psycopg2`` can be configured to run
     281without an open connection when Django is in autocommit mode. This
     282corresponds to PostgreSQL ``set_isolation_level(0)`` and is configured
     283with::
     284
     285    DATABASE_OPTIONS = {'native_autocommit':True}
     286
     287.. _psycopg: http://initd.org/pub/software/psycopg/
     288
    263289.. _sqlite-notes:
    264290
    265291SQLite notes
Back to Top