Skip to content

Commit e13d614

Browse files
committed
Cache sql_server_version & to_azure_sql_db between instances
Fix michiya#80 by caching these property values on the DatabaseWrapper class so that they don't need to be re-evaluated each time Django creates a new database connection. The cache is keyed by database alias since it will be used for all DatabaseWrapper instances.
1 parent 4df37f3 commit e13d614

File tree

1 file changed

+32
-12
lines changed

1 file changed

+32
-12
lines changed

sql_server/pyodbc/base.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -392,20 +392,40 @@ def schema_editor(self, *args, **kwargs):
392392
return DatabaseSchemaEditor(self, *args, **kwargs)
393393

394394
@cached_property
395-
def sql_server_version(self):
396-
with self.temporary_connection() as cursor:
397-
cursor.execute("SELECT CAST(SERVERPROPERTY('ProductVersion') AS varchar)")
398-
ver = cursor.fetchone()[0]
399-
ver = int(ver.split('.')[0])
400-
if not ver in self._sql_server_versions:
401-
raise NotImplementedError('SQL Server v%d is not supported.' % ver)
402-
return self._sql_server_versions[ver]
395+
def sql_server_version(self, _known_versions={}):
396+
"""
397+
Get the SQL server version
398+
399+
The _known_versions default dictionary is created on the class. This is
400+
intentional - it allows us to cache this property's value across instances.
401+
Therefore, when Django creates a new database connection using the same
402+
alias, we won't need query the server again.
403+
"""
404+
if self.alias not in _known_versions:
405+
with self.temporary_connection() as cursor:
406+
cursor.execute("SELECT CAST(SERVERPROPERTY('ProductVersion') AS varchar)")
407+
ver = cursor.fetchone()[0]
408+
ver = int(ver.split('.')[0])
409+
if not ver in self._sql_server_versions:
410+
raise NotImplementedError('SQL Server v%d is not supported.' % ver)
411+
_known_versions[self.alias] = self._sql_server_versions[ver]
412+
return _known_versions[self.alias]
403413

404414
@cached_property
405-
def to_azure_sql_db(self):
406-
with self.temporary_connection() as cursor:
407-
cursor.execute("SELECT CAST(SERVERPROPERTY('EngineEdition') AS integer)")
408-
return cursor.fetchone()[0] == EDITION_AZURE_SQL_DB
415+
def to_azure_sql_db(self, _known_azures={}):
416+
"""
417+
Whether this connection is to a Microsoft Azure database server
418+
419+
The _known_azures default dictionary is created on the class. This is
420+
intentional - it allows us to cache this property's value across instances.
421+
Therefore, when Django creates a new database connection using the same
422+
alias, we won't need query the server again.
423+
"""
424+
if self.alias not in _known_azures:
425+
with self.temporary_connection() as cursor:
426+
cursor.execute("SELECT CAST(SERVERPROPERTY('EngineEdition') AS integer)")
427+
_known_azures[self.alias] = cursor.fetchone()[0] == EDITION_AZURE_SQL_DB
428+
return _known_azures[self.alias]
409429

410430
def _execute_foreach(self, sql, table_names=None):
411431
cursor = self.cursor()

0 commit comments

Comments
 (0)