]> 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:39:54 +0000 (09:39 -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
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 b95b2964f4bbd2fdaaa7bfc52a1dd3c87c36eef9..3e1d1a330eff5f9a201bb6ecfe72697beb2b845c 100644 (file)
@@ -111,8 +111,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 a667b671e91a7dbfbdd5c66ac932e33d219d9ab0..6fd4fc5543877b2f27ad5c7bec182252aa1b989e 100644 (file)
@@ -275,4 +275,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()