From: Mike Bayer Date: Thu, 15 Sep 2022 12:42:34 +0000 (-0400) Subject: catch exception for system_views also X-Git-Tag: rel_1_4_42~26^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8f1d47df752db35009269b7edd6da59805230c3b;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git catch exception for system_views also Fixed yet another regression in SQL Server isolation level fetch (see :ticket:`8231`, :ticket:`8475`), this time with "Microsoft Dynamics CRM Database via Azure Active Directory", which apparently lacks the ``system_views`` view entirely. Error catching has been extended that under no circumstances will this method ever fail, provided database connectivity is present. Fixes: #8525 Change-Id: I76a429e3329926069a0367d2e77ca1124b9a059d (cherry picked from commit 0ee7d693b805c0f1aea0da5ebc11ea6e52b42c71) --- diff --git a/doc/build/changelog/unreleased_14/8525.rst b/doc/build/changelog/unreleased_14/8525.rst new file mode 100644 index 0000000000..3031ec378c --- /dev/null +++ b/doc/build/changelog/unreleased_14/8525.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: bug, mssql, regression + :tickets: 8525 + + Fixed yet another regression in SQL Server isolation level fetch (see + :ticket:`8231`, :ticket:`8475`), this time with "Microsoft Dynamics CRM + Database via Azure Active Directory", which apparently lacks the + ``system_views`` view entirely. Error catching has been extended that under + no circumstances will this method ever fail, provided database connectivity + is present. \ No newline at end of file diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py index 0d0a4b8f5e..0c967b5167 100644 --- a/lib/sqlalchemy/dialects/mssql/base.py +++ b/lib/sqlalchemy/dialects/mssql/base.py @@ -2829,10 +2829,13 @@ class MSDialect(default.DefaultDialect): def get_isolation_level(self, dbapi_connection): cursor = dbapi_connection.cursor() + view_name = "sys.system_views" try: cursor.execute( - "SELECT name FROM sys.system_views WHERE name IN " - "('dm_exec_sessions', 'dm_pdw_nodes_exec_sessions')" + ( + "SELECT name FROM {} WHERE name IN " + "('dm_exec_sessions', 'dm_pdw_nodes_exec_sessions')" + ).format(view_name) ) row = cursor.fetchone() if not row: @@ -2843,37 +2846,33 @@ class MSDialect(default.DefaultDialect): view_name = "sys.{}".format(row[0]) - try: - cursor.execute( - """ - SELECT CASE transaction_isolation_level - WHEN 0 THEN NULL - WHEN 1 THEN 'READ UNCOMMITTED' - WHEN 2 THEN 'READ COMMITTED' - WHEN 3 THEN 'REPEATABLE READ' - WHEN 4 THEN 'SERIALIZABLE' - WHEN 5 THEN 'SNAPSHOT' END - AS TRANSACTION_ISOLATION_LEVEL - FROM {} - where session_id = @@SPID - """.format( - view_name - ) - ) - except self.dbapi.Error as err: - util.raise_( - NotImplementedError( - "Can't fetch isolation level; encountered " - "error {} when " - 'attempting to query the "{}" view.'.format( - err, view_name - ) - ), - from_=err, + cursor.execute( + """ + SELECT CASE transaction_isolation_level + WHEN 0 THEN NULL + WHEN 1 THEN 'READ UNCOMMITTED' + WHEN 2 THEN 'READ COMMITTED' + WHEN 3 THEN 'REPEATABLE READ' + WHEN 4 THEN 'SERIALIZABLE' + WHEN 5 THEN 'SNAPSHOT' END + AS TRANSACTION_ISOLATION_LEVEL + FROM {} + where session_id = @@SPID + """.format( + view_name ) - else: - row = cursor.fetchone() - return row[0].upper() + ) + except self.dbapi.Error as err: + util.raise_( + NotImplementedError( + "Can't fetch isolation level; encountered error {} when " + 'attempting to query the "{}" view.'.format(err, view_name) + ), + from_=err, + ) + else: + row = cursor.fetchone() + return row[0].upper() finally: cursor.close() diff --git a/test/dialect/mssql/test_engine.py b/test/dialect/mssql/test_engine.py index ea201a1aa0..32068e504b 100644 --- a/test/dialect/mssql/test_engine.py +++ b/test/dialect/mssql/test_engine.py @@ -649,7 +649,12 @@ class RealIsolationLevelTest(fixtures.TestBase): class IsolationLevelDetectTest(fixtures.TestBase): - def _fixture(self, view_result, simulate_perm_failure=False): + def _fixture( + self, + view_result, + simulate_perm_failure=False, + simulate_no_system_views=False, + ): class Error(Exception): pass @@ -664,8 +669,13 @@ class IsolationLevelDetectTest(fixtures.TestBase): ): result[:] = [] if "SELECT name FROM sys.system_views" in stmt: - if view_result: - result.append((view_result,)) + if simulate_no_system_views: + raise dialect.dbapi.Error( + "SQL Server simulated no system_views error" + ) + else: + if view_result: + result.append((view_result,)) elif re.match( ".*SELECT CASE transaction_isolation_level.*FROM sys.%s" % (view_result,), @@ -711,6 +721,23 @@ class IsolationLevelDetectTest(fixtures.TestBase): connection, ) + @testing.combinations(True, False) + def test_no_system_views(self, simulate_perm_failure_also): + dialect, connection = self._fixture( + "dm_pdw_nodes_exec_sessions", + simulate_perm_failure=simulate_perm_failure_also, + simulate_no_system_views=True, + ) + + assert_raises_message( + NotImplementedError, + r"Can\'t fetch isolation level; encountered error SQL Server " + r"simulated no system_views error when attempting to query the " + r'"sys.system_views" view.', + dialect.get_isolation_level, + connection, + ) + def test_dont_have_table_perms(self): dialect, connection = self._fixture( "dm_pdw_nodes_exec_sessions", simulate_perm_failure=True