Fix is_disconnect false positive for mssql+pyodbc

Fixed an issue where the ``is_disconnect`` function in the SQL Server
pyodbc dialect was incorrectly reporting the disconnect state when the
exception messsage had a substring that matched a SQL Server ODBC error
code.

Fixes: #5359
Change-Id: I450c6818405a20f4daee20d58fce2d5ecb33e17f
(cherry picked from commit ddff320473)
This commit is contained in:
Gord Thompson
2020-05-29 07:20:54 -06:00
parent b7bbbf0ff1
commit 2c2bdceab7
3 changed files with 54 additions and 5 deletions
+8
View File
@@ -0,0 +1,8 @@
.. change::
:tags: bug, mssql
:tickets: 5359
Fixed an issue where the ``is_disconnect`` function in the SQL Server
pyodbc dialect was incorrectly reporting the disconnect state when the
exception messsage had a substring that matched a SQL Server ODBC error
code.
+3 -3
View File
@@ -419,7 +419,8 @@ class MSDialect_pyodbc(PyODBCConnector, MSDialect):
def is_disconnect(self, e, connection, cursor):
if isinstance(e, self.dbapi.Error):
for code in (
code = e.args[0]
if code in (
"08S01",
"01002",
"08003",
@@ -430,8 +431,7 @@ class MSDialect_pyodbc(PyODBCConnector, MSDialect):
"HY010",
"10054",
):
if code in str(e):
return True
return True
return super(MSDialect_pyodbc, self).is_disconnect(
e, connection, cursor
)
+43 -2
View File
@@ -1,4 +1,5 @@
# -*- encoding: utf-8
from sqlalchemy import Column
from sqlalchemy import engine_from_config
from sqlalchemy import event
@@ -12,6 +13,8 @@ from sqlalchemy.dialects.mssql import base
from sqlalchemy.dialects.mssql import pymssql
from sqlalchemy.dialects.mssql import pyodbc
from sqlalchemy.engine import url
from sqlalchemy.exc import IntegrityError
from sqlalchemy.testing import assert_raises
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import assert_warnings
from sqlalchemy.testing import engines
@@ -321,7 +324,7 @@ class ParseConnectTest(fixtures.TestBase):
)
for error in [
MockDBAPIError("[%s] some pyodbc message" % code)
MockDBAPIError(code, "[%s] some pyodbc message" % code)
for code in [
"08S01",
"01002",
@@ -343,7 +346,9 @@ class ParseConnectTest(fixtures.TestBase):
eq_(
dialect.is_disconnect(
MockProgrammingError("not an error"), None, None
MockProgrammingError("Query with abc08007def failed"),
None,
None,
),
False,
)
@@ -526,3 +531,39 @@ class IsolationLevelDetectTest(fixtures.TestBase):
dialect.get_isolation_level,
connection,
)
class InvalidTransactionFalsePositiveTest(fixtures.TablesTest):
__only_on__ = "mssql"
__backend__ = True
@classmethod
def define_tables(cls, metadata):
Table(
"error_t",
metadata,
Column("error_code", String(50), primary_key=True),
)
@classmethod
def insert_data(cls, connection):
connection.execute(
cls.tables.error_t.insert(), [{"error_code": "01002"}],
)
def test_invalid_transaction_detection(self, connection):
# issue #5359
t = self.tables.error_t
# force duplicate PK error
assert_raises(
IntegrityError,
connection.execute,
t.insert(),
{"error_code": "01002"},
)
# this should not fail with
# "Can't reconnect until invalid transaction is rolled back."
result = connection.execute(t.select()).fetchall()
eq_(len(result), 1)