]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Add full list of pyodbc error codes for MSSQL
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 28 Sep 2017 13:39:54 +0000 (09:39 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 28 Sep 2017 13:41:40 +0000 (09:41 -0400)
Moved the SQL server error codes out of connnectors/pyodbc.py
and into mssql/pyodbc.py.  Added complete list
of odbc-related disconnect codes.

Change-Id: Icd84a920dbfa1f188847f859654ff6f7a48170f1
Fixes: #4095
(cherry picked from commit 6a38697261e271b3600d8f1bbc56f663e5ee9890)

doc/build/changelog/unreleased_11/4095.rst [new file with mode: 0644]
lib/sqlalchemy/connectors/pyodbc.py
lib/sqlalchemy/dialects/mssql/pyodbc.py
test/dialect/mssql/test_engine.py

diff --git a/doc/build/changelog/unreleased_11/4095.rst b/doc/build/changelog/unreleased_11/4095.rst
new file mode 100644 (file)
index 0000000..17286fa
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: bug, mssql
+    :tickets: 4095
+    :versions: 1.2.0b3
+
+    Added a full range of "connection closed" exception codes to the
+    PyODBC dialect for SQL Server, including '08S01', '01002', '08003',
+    '08007', '08S02', '08001', 'HYT00', 'HY010'.  Previously, only '08S01'
+    was covered.
\ No newline at end of file
index ee8445dae4136216b07182ccefe451e5c5bec0a1..c5d46a8110b82fbac223b1bebe7af0e3b40ea282 100644 (file)
@@ -124,8 +124,6 @@ class PyODBCConnector(Connector):
         if isinstance(e, self.dbapi.ProgrammingError):
             return "The cursor's connection has been closed." in str(e) or \
                 'Attempt to use a closed connection.' in str(e)
-        elif isinstance(e, self.dbapi.Error):
-            return '[08S01]' in str(e)
         else:
             return False
 
index c6368f9696fd724523ea009d90de8fad18df1a74..5545e005c395aab8216075855862fa58b1c21d94 100644 (file)
@@ -289,4 +289,14 @@ class MSDialect_pyodbc(PyODBCConnector, MSDialect):
                     version.append(n)
             return tuple(version)
 
+    def is_disconnect(self, e, connection, cursor):
+        if isinstance(e, self.dbapi.Error):
+            for code in (
+                    '08S01', '01002', '08003', '08007',
+                    '08S02', '08001', 'HYT00', 'HY010'):
+                if code in str(e):
+                    return True
+        return super(MSDialect_pyodbc, self).is_disconnect(
+            e, connection, cursor)
+
 dialect = MSDialect_pyodbc
index 1021f4e99e3e2638fdc0af4a149fdf56d569b541..b69e62572e064a5fc580a02d3ebb2c72645607eb 100644 (file)
@@ -202,6 +202,35 @@ class ParseConnectTest(fixtures.TestBase):
 
         eq_(dialect.is_disconnect("not an error", None, None), False)
 
+    def test_pyodbc_disconnect(self):
+        dialect = pyodbc.dialect()
+
+        class MockDBAPIError(Exception):
+            pass
+
+        class MockProgrammingError(MockDBAPIError):
+            pass
+
+        dialect.dbapi = Mock(
+            Error=MockDBAPIError, ProgrammingError=MockProgrammingError)
+
+        for error in [
+            MockDBAPIError("[%s] some pyodbc message" % code)
+            for code in [
+                '08S01', '01002', '08003', '08007',
+                '08S02', '08001', 'HYT00', 'HY010']
+        ] + [
+            MockProgrammingError(message)
+            for message in [
+                "(some pyodbc stuff) The cursor's connection has been closed.",
+                "(some pyodbc stuff) Attempt to use a closed connection."
+            ]
+        ]:
+            eq_(dialect.is_disconnect(error, None, None), True)
+
+        eq_(dialect.is_disconnect(
+            MockProgrammingError("not an error"), None, None), False)
+
     @testing.requires.mssql_freetds
     def test_bad_freetds_warning(self):
         engine = engines.testing_engine()