mirror of
				https://github.com/django/django.git
				synced 2025-11-04 05:35:37 +00:00 
			
		
		
		
	Fixed #17062 -- Ensured that the effect of SET TIME ZONE isn't lost when the first transation is rolled back under PostgreSQL. Thanks Anssi for the patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17128 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		
							parent
							
								
									98b08bd4d4
								
							
						
					
					
						commit
						74b836abf5
					
				
					 2 changed files with 49 additions and 7 deletions
				
			
		| 
						 | 
					@ -153,10 +153,8 @@ class DatabaseWrapper(BaseDatabaseWrapper):
 | 
				
			||||||
    pg_version = property(_get_pg_version)
 | 
					    pg_version = property(_get_pg_version)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _cursor(self):
 | 
					    def _cursor(self):
 | 
				
			||||||
        new_connection = False
 | 
					 | 
				
			||||||
        settings_dict = self.settings_dict
 | 
					        settings_dict = self.settings_dict
 | 
				
			||||||
        if self.connection is None:
 | 
					        if self.connection is None:
 | 
				
			||||||
            new_connection = True
 | 
					 | 
				
			||||||
            if settings_dict['NAME'] == '':
 | 
					            if settings_dict['NAME'] == '':
 | 
				
			||||||
                from django.core.exceptions import ImproperlyConfigured
 | 
					                from django.core.exceptions import ImproperlyConfigured
 | 
				
			||||||
                raise ImproperlyConfigured("You need to specify NAME in your Django settings file.")
 | 
					                raise ImproperlyConfigured("You need to specify NAME in your Django settings file.")
 | 
				
			||||||
| 
						 | 
					@ -176,15 +174,17 @@ class DatabaseWrapper(BaseDatabaseWrapper):
 | 
				
			||||||
                conn_params['port'] = settings_dict['PORT']
 | 
					                conn_params['port'] = settings_dict['PORT']
 | 
				
			||||||
            self.connection = Database.connect(**conn_params)
 | 
					            self.connection = Database.connect(**conn_params)
 | 
				
			||||||
            self.connection.set_client_encoding('UTF8')
 | 
					            self.connection.set_client_encoding('UTF8')
 | 
				
			||||||
 | 
					            # Set the time zone in autocommit mode (see #17062)
 | 
				
			||||||
 | 
					            tz = 'UTC' if settings.USE_TZ else settings_dict.get('TIME_ZONE')
 | 
				
			||||||
 | 
					            if tz:
 | 
				
			||||||
 | 
					                self.connection.set_isolation_level(
 | 
				
			||||||
 | 
					                        psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
 | 
				
			||||||
 | 
					                self.connection.cursor().execute("SET TIME ZONE %s", [tz])
 | 
				
			||||||
            self.connection.set_isolation_level(self.isolation_level)
 | 
					            self.connection.set_isolation_level(self.isolation_level)
 | 
				
			||||||
 | 
					            self._get_pg_version()
 | 
				
			||||||
            connection_created.send(sender=self.__class__, connection=self)
 | 
					            connection_created.send(sender=self.__class__, connection=self)
 | 
				
			||||||
        cursor = self.connection.cursor()
 | 
					        cursor = self.connection.cursor()
 | 
				
			||||||
        cursor.tzinfo_factory = utc_tzinfo_factory if settings.USE_TZ else None
 | 
					        cursor.tzinfo_factory = utc_tzinfo_factory if settings.USE_TZ else None
 | 
				
			||||||
        if new_connection:
 | 
					 | 
				
			||||||
            tz = 'UTC' if settings.USE_TZ else settings_dict.get('TIME_ZONE')
 | 
					 | 
				
			||||||
            if tz:
 | 
					 | 
				
			||||||
                cursor.execute("SET TIME ZONE %s", [tz])
 | 
					 | 
				
			||||||
            self._get_pg_version()
 | 
					 | 
				
			||||||
        return CursorWrapper(cursor)
 | 
					        return CursorWrapper(cursor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _enter_transaction_management(self, managed):
 | 
					    def _enter_transaction_management(self, managed):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@ from django.db import (backend, connection, connections, DEFAULT_DB_ALIAS,
 | 
				
			||||||
    IntegrityError, transaction)
 | 
					    IntegrityError, transaction)
 | 
				
			||||||
from django.db.backends.signals import connection_created
 | 
					from django.db.backends.signals import connection_created
 | 
				
			||||||
from django.db.backends.postgresql_psycopg2 import version as pg_version
 | 
					from django.db.backends.postgresql_psycopg2 import version as pg_version
 | 
				
			||||||
 | 
					from django.db.utils import ConnectionHandler, DatabaseError
 | 
				
			||||||
from django.test import TestCase, skipUnlessDBFeature, TransactionTestCase
 | 
					from django.test import TestCase, skipUnlessDBFeature, TransactionTestCase
 | 
				
			||||||
from django.utils import unittest
 | 
					from django.utils import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -229,6 +230,47 @@ class PostgresVersionTest(TestCase):
 | 
				
			||||||
        conn = OlderConnectionMock()
 | 
					        conn = OlderConnectionMock()
 | 
				
			||||||
        self.assertEqual(pg_version.get_version(conn), 80300)
 | 
					        self.assertEqual(pg_version.get_version(conn), 80300)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PostgresNewConnectionTest(TestCase):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    #17062: PostgreSQL shouldn't roll back SET TIME ZONE, even if the first
 | 
				
			||||||
 | 
					    transaction is rolled back.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    @unittest.skipUnless(connection.vendor == 'postgresql',
 | 
				
			||||||
 | 
					                         "Test valid only for PostgreSQL")
 | 
				
			||||||
 | 
					    @unittest.skipUnless(connection.isolation_level > 0,
 | 
				
			||||||
 | 
					                         "Test valid only if not using autocommit")
 | 
				
			||||||
 | 
					    def test_connect_and_rollback(self):
 | 
				
			||||||
 | 
					        new_connections = ConnectionHandler(settings.DATABASES)
 | 
				
			||||||
 | 
					        new_connection = new_connections[DEFAULT_DB_ALIAS]
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            # Ensure the database default time zone is different than
 | 
				
			||||||
 | 
					            # the time zone in new_connection.settings_dict. We can
 | 
				
			||||||
 | 
					            # get the default time zone by reset & show.
 | 
				
			||||||
 | 
					            cursor = new_connection.cursor()
 | 
				
			||||||
 | 
					            cursor.execute("RESET TIMEZONE")
 | 
				
			||||||
 | 
					            cursor.execute("SHOW TIMEZONE")
 | 
				
			||||||
 | 
					            db_default_tz = cursor.fetchone()[0]
 | 
				
			||||||
 | 
					            new_tz = 'Europe/Paris' if db_default_tz == 'UTC' else 'UTC'
 | 
				
			||||||
 | 
					            new_connection.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Fetch a new connection with the new_tz as default
 | 
				
			||||||
 | 
					            # time zone, run a query and rollback.
 | 
				
			||||||
 | 
					            new_connection.settings_dict['TIME_ZONE'] = new_tz
 | 
				
			||||||
 | 
					            new_connection.enter_transaction_management()
 | 
				
			||||||
 | 
					            cursor = new_connection.cursor()
 | 
				
			||||||
 | 
					            new_connection.rollback()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Now let's see if the rollback rolled back the SET TIME ZONE.
 | 
				
			||||||
 | 
					            cursor.execute("SHOW TIMEZONE")
 | 
				
			||||||
 | 
					            tz = cursor.fetchone()[0]
 | 
				
			||||||
 | 
					            self.assertEqual(new_tz, tz)
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                new_connection.close()
 | 
				
			||||||
 | 
					            except DatabaseError:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Unfortunately with sqlite3 the in-memory test database cannot be
 | 
					# Unfortunately with sqlite3 the in-memory test database cannot be
 | 
				
			||||||
# closed, and so it cannot be re-opened during testing, and so we
 | 
					# closed, and so it cannot be re-opened during testing, and so we
 | 
				
			||||||
# sadly disable this test for now.
 | 
					# sadly disable this test for now.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue