Code

Ticket #17760: 17760-5.diff

File 17760-5.diff, 8.9 KB (added by claudep, 2 years ago)

Updated to current trunk

Line 
1diff --git a/django/contrib/gis/db/backends/spatialite/creation.py b/django/contrib/gis/db/backends/spatialite/creation.py
2index 7efab3e..31f2fca 100644
3--- a/django/contrib/gis/db/backends/spatialite/creation.py
4+++ b/django/contrib/gis/db/backends/spatialite/creation.py
5@@ -31,9 +31,6 @@ class SpatiaLiteCreation(DatabaseCreation):
6         self.connection.close()
7         self.connection.settings_dict["NAME"] = test_database_name
8 
9-        # Confirm the feature set of the test database
10-        self.connection.features.confirm()
11-
12         # Need to load the SpatiaLite initialization SQL before running `syncdb`.
13         self.load_spatialite_sql()
14 
15diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
16index f26653f..d70fe54 100644
17--- a/django/db/backends/__init__.py
18+++ b/django/db/backends/__init__.py
19@@ -10,6 +10,7 @@ from django.conf import settings
20 from django.db import DEFAULT_DB_ALIAS
21 from django.db.backends import util
22 from django.db.transaction import TransactionManagementError
23+from django.utils.functional import cached_property
24 from django.utils.importlib import import_module
25 from django.utils.timezone import is_aware
26 
27@@ -402,12 +403,10 @@ class BaseDatabaseFeatures(object):
28     # Does the backend reset sequences between tests?
29     supports_sequence_reset = True
30 
31-    # Features that need to be confirmed at runtime
32-    # Cache whether the confirmation has been performed.
33-    _confirmed = False
34-    supports_transactions = None
35-    supports_stddev = None
36-    can_introspect_foreign_keys = None
37+    # Confirm support for introspected foreign keys
38+    # Every database can do this reliably, except MySQL,
39+    # which can't do it for MyISAM tables
40+    can_introspect_foreign_keys = True
41 
42     # Support for the DISTINCT ON clause
43     can_distinct_on_fields = False
44@@ -415,15 +414,8 @@ class BaseDatabaseFeatures(object):
45     def __init__(self, connection):
46         self.connection = connection
47 
48-    def confirm(self):
49-        "Perform manual checks of any database features that might vary between installs"
50-        if not self._confirmed:
51-            self._confirmed = True
52-            self.supports_transactions = self._supports_transactions()
53-            self.supports_stddev = self._supports_stddev()
54-            self.can_introspect_foreign_keys = self._can_introspect_foreign_keys()
55-
56-    def _supports_transactions(self):
57+    @cached_property
58+    def supports_transactions(self):
59         "Confirm support for transactions"
60         cursor = self.connection.cursor()
61         cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
62@@ -436,7 +428,8 @@ class BaseDatabaseFeatures(object):
63         self.connection._commit()
64         return count == 0
65 
66-    def _supports_stddev(self):
67+    @cached_property
68+    def supports_stddev(self):
69         "Confirm support for STDDEV and related stats functions"
70         class StdDevPop(object):
71             sql_function = 'STDDEV_POP'
72@@ -447,12 +440,6 @@ class BaseDatabaseFeatures(object):
73         except NotImplementedError:
74             return False
75 
76-    def _can_introspect_foreign_keys(self):
77-        "Confirm support for introspected foreign keys"
78-        # Every database can do this reliably, except MySQL,
79-        # which can't do it for MyISAM tables
80-        return True
81-
82 
83 class BaseDatabaseOperations(object):
84     """
85diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py
86index ba90cb9..0f06131 100644
87--- a/django/db/backends/creation.py
88+++ b/django/db/backends/creation.py
89@@ -264,9 +264,6 @@ class BaseDatabaseCreation(object):
90         self.connection.close()
91         self.connection.settings_dict["NAME"] = test_database_name
92 
93-        # Confirm the feature set of the test database
94-        self.connection.features.confirm()
95-
96         # Report syncdb messages at one level lower than that requested.
97         # This ensures we don't get flooded with messages during testing
98         # (unless you really ask to be flooded)
99diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
100index 1df487b..1dbd91b 100644
101--- a/django/db/backends/mysql/base.py
102+++ b/django/db/backends/mysql/base.py
103@@ -36,6 +36,7 @@ from django.db.backends.mysql.client import DatabaseClient
104 from django.db.backends.mysql.creation import DatabaseCreation
105 from django.db.backends.mysql.introspection import DatabaseIntrospection
106 from django.db.backends.mysql.validation import DatabaseValidation
107+from django.utils.functional import cached_property
108 from django.utils.safestring import SafeString, SafeUnicode
109 from django.utils import timezone
110 
111@@ -169,26 +170,25 @@ class DatabaseFeatures(BaseDatabaseFeatures):
112 
113     def __init__(self, connection):
114         super(DatabaseFeatures, self).__init__(connection)
115-        self._storage_engine = None
116 
117+    @cached_property
118     def _mysql_storage_engine(self):
119         "Internal method used in Django tests. Don't rely on this from your code"
120-        if self._storage_engine is None:
121-            cursor = self.connection.cursor()
122-            cursor.execute('CREATE TABLE INTROSPECT_TEST (X INT)')
123-            # This command is MySQL specific; the second column
124-            # will tell you the default table type of the created
125-            # table. Since all Django's test tables will have the same
126-            # table type, that's enough to evaluate the feature.
127-            cursor.execute("SHOW TABLE STATUS WHERE Name='INTROSPECT_TEST'")
128-            result = cursor.fetchone()
129-            cursor.execute('DROP TABLE INTROSPECT_TEST')
130-            self._storage_engine = result[1]
131-        return self._storage_engine
132-
133-    def _can_introspect_foreign_keys(self):
134+        cursor = self.connection.cursor()
135+        cursor.execute('CREATE TABLE INTROSPECT_TEST (X INT)')
136+        # This command is MySQL specific; the second column
137+        # will tell you the default table type of the created
138+        # table. Since all Django's test tables will have the same
139+        # table type, that's enough to evaluate the feature.
140+        cursor.execute("SHOW TABLE STATUS WHERE Name='INTROSPECT_TEST'")
141+        result = cursor.fetchone()
142+        cursor.execute('DROP TABLE INTROSPECT_TEST')
143+        return result[1]
144+
145+    @cached_property
146+    def can_introspect_foreign_keys(self):
147         "Confirm support for introspected foreign keys"
148-        return self._mysql_storage_engine() != 'MyISAM'
149+        return self._mysql_storage_engine != 'MyISAM'
150 
151 class DatabaseOperations(BaseDatabaseOperations):
152     compiler_module = "django.db.backends.mysql.compiler"
153diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
154index 4fba304..db6adde 100644
155--- a/django/db/backends/sqlite3/base.py
156+++ b/django/db/backends/sqlite3/base.py
157@@ -18,6 +18,7 @@ from django.db.backends.sqlite3.client import DatabaseClient
158 from django.db.backends.sqlite3.creation import DatabaseCreation
159 from django.db.backends.sqlite3.introspection import DatabaseIntrospection
160 from django.utils.dateparse import parse_date, parse_datetime, parse_time
161+from django.utils.functional import cached_property
162 from django.utils.safestring import SafeString
163 from django.utils import timezone
164 
165@@ -85,7 +86,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
166     has_bulk_insert = True
167     can_combine_inserts_with_and_without_auto_increment_pk = True
168 
169-    def _supports_stddev(self):
170+    @cached_property
171+    def supports_stddev(self):
172         """Confirm support for STDDEV and related stats functions
173 
174         SQLite supports STDDEV as an extension package; so
175diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py
176index 109e1a5..9bee987 100644
177--- a/tests/regressiontests/backends/tests.py
178+++ b/tests/regressiontests/backends/tests.py
179@@ -403,8 +403,7 @@ class BackendTestCase(TestCase):
180         self.assertTrue(hasattr(connection.ops, 'connection'))
181         self.assertEqual(connection, connection.ops.connection)
182 
183-    def test_supports_needed_confirm(self):
184-        connection.features.confirm()
185+    def test_cached_db_features(self):
186         self.assertIn(connection.features.supports_transactions, (True, False))
187         self.assertIn(connection.features.supports_stddev, (True, False))
188         self.assertIn(connection.features.can_introspect_foreign_keys, (True, False))
189diff --git a/tests/regressiontests/transactions_regress/tests.py b/tests/regressiontests/transactions_regress/tests.py
190index 5972263..abd7a4c 100644
191--- a/tests/regressiontests/transactions_regress/tests.py
192+++ b/tests/regressiontests/transactions_regress/tests.py
193@@ -208,7 +208,7 @@ class SavepointTest(TransactionTestCase):
194         work()
195 
196     @skipIf(connection.vendor == 'mysql' and \
197-            connection.features._mysql_storage_engine() == 'MyISAM',
198+            connection.features._mysql_storage_engine == 'MyISAM',
199             "MyISAM MySQL storage engine doesn't support savepoints")
200     @skipUnlessDBFeature('uses_savepoints')
201     def test_savepoint_rollback(self):