]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
catch exception for system_views also
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 15 Sep 2022 12:42:34 +0000 (08:42 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 15 Sep 2022 12:44:24 +0000 (08:44 -0400)
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)

doc/build/changelog/unreleased_14/8525.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mssql/base.py
test/dialect/mssql/test_engine.py

diff --git a/doc/build/changelog/unreleased_14/8525.rst b/doc/build/changelog/unreleased_14/8525.rst
new file mode 100644 (file)
index 0000000..3031ec3
--- /dev/null
@@ -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
index 0d0a4b8f5e09dd2aa3047022fb8d5d19ff4ae2e3..0c967b51670a0466ba84a535e0fe8fffea7c9122 100644 (file)
@@ -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()
 
index ea201a1aa0b930d3fe76eb16f215e2a3ff76bce0..32068e504b738a465dc76972e8a703ca73d3e12f 100644 (file)
@@ -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