diff options
| author | mike bayer <mike_mp@zzzcomputing.com> | 2022-02-24 14:44:44 +0000 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@ci3.zzzcomputing.com> | 2022-02-24 14:44:44 +0000 |
| commit | 381894b50ea7e16b4950ecbdda72c0fa45de8d1c (patch) | |
| tree | cff92f26b61576dd209127a15d8e41886f83a702 | |
| parent | 11333602c0f844e32f12af114f1dfcb160408fcf (diff) | |
| parent | 8f9e971f10dee0614054671e0c284f0acace2d04 (diff) | |
| download | sqlalchemy-381894b50ea7e16b4950ecbdda72c0fa45de8d1c.tar.gz | |
Merge "support cx_Oracle DPI disconnect codes" into main
| -rw-r--r-- | doc/build/changelog/unreleased_14/7748.rst | 7 | ||||
| -rw-r--r-- | lib/sqlalchemy/dialects/oracle/cx_oracle.py | 21 | ||||
| -rw-r--r-- | test/dialect/oracle/test_dialect.py | 54 |
3 files changed, 75 insertions, 7 deletions
diff --git a/doc/build/changelog/unreleased_14/7748.rst b/doc/build/changelog/unreleased_14/7748.rst new file mode 100644 index 000000000..d9d6bf236 --- /dev/null +++ b/doc/build/changelog/unreleased_14/7748.rst @@ -0,0 +1,7 @@ +.. change:: + :tags: bug, oracle, regression + :tickets: 7748 + + Added support to parse "DPI" error codes from cx_Oracle exception objects + such as ``DPI-1080`` and ``DPI-1010``, both of which now indicate a + disconnect scenario as of cx_Oracle 8.3. diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py index 3f8109a12..a390099ae 100644 --- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py +++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py @@ -1233,7 +1233,14 @@ class OracleDialect_cx_oracle(OracleDialect): ) and "not connected" in str(e): return True - if hasattr(error, "code"): + if hasattr(error, "code") and error.code in { + 28, + 3114, + 3113, + 3135, + 1033, + 2396, + }: # ORA-00028: your session has been killed # ORA-03114: not connected to ORACLE # ORA-03113: end-of-file on communication channel @@ -1241,9 +1248,15 @@ class OracleDialect_cx_oracle(OracleDialect): # ORA-01033: ORACLE initialization or shutdown in progress # ORA-02396: exceeded maximum idle time, please connect again # TODO: Others ? - return error.code in (28, 3114, 3113, 3135, 1033, 2396) - else: - return False + return True + + if re.match(r"^(?:DPI-1010|DPI-1080)", str(e)): + # DPI-1010: not connected + # DPI-1080: connection was closed by ORA-3113 + # TODO: others? + return True + + return False def create_xid(self): """create a two-phase transaction ID. diff --git a/test/dialect/oracle/test_dialect.py b/test/dialect/oracle/test_dialect.py index 5383ffc0c..e827fa56c 100644 --- a/test/dialect/oracle/test_dialect.py +++ b/test/dialect/oracle/test_dialect.py @@ -1,6 +1,7 @@ # coding: utf-8 import re +from unittest import mock from unittest.mock import Mock from sqlalchemy import bindparam @@ -30,7 +31,6 @@ from sqlalchemy.testing import config from sqlalchemy.testing import engines from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures -from sqlalchemy.testing import mock from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table from sqlalchemy.testing.suite import test_select @@ -56,7 +56,7 @@ class DialectTest(fixtures.TestBase): exc.InvalidRequestError, "cx_Oracle version 5.2 and above are supported", cx_oracle.OracleDialect_cx_oracle, - dbapi=Mock(), + dbapi=mock.Mock(), ) with mock.patch( @@ -64,13 +64,61 @@ class DialectTest(fixtures.TestBase): "_parse_cx_oracle_ver", lambda self, vers: (5, 3, 1), ): - cx_oracle.OracleDialect_cx_oracle(dbapi=Mock()) + cx_oracle.OracleDialect_cx_oracle(dbapi=mock.Mock()) class DialectWBackendTest(fixtures.TestBase): __backend__ = True __only_on__ = "oracle" + @testing.combinations( + ( + "db is not connected", + None, + True, + ), + ( + "ORA-1234 fake error", + 1234, + False, + ), + ( + "ORA-03114: not connected to ORACLE", + 3114, + True, + ), + ( + "DPI-1010: not connected", + None, + True, + ), + ( + "DPI-1010: make sure we read the code", + None, + True, + ), + ( + "DPI-1080: connection was closed by ORA-3113", + None, + True, + ), + ( + "DPI-1234: some other DPI error", + None, + False, + ), + ) + @testing.only_on("oracle+cx_oracle") + def test_is_disconnect(self, message, code, expected): + + dialect = testing.db.dialect + + exception_obj = dialect.dbapi.InterfaceError() + exception_obj.args = (Exception(message),) + exception_obj.args[0].code = code + + eq_(dialect.is_disconnect(exception_obj, None, None), expected) + def test_hypothetical_not_implemented_isolation_level(self): engine = engines.testing_engine() |
