summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2019-08-12 15:09:37 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2019-10-21 14:20:24 -0400
commitd76cb7213557c24609a1a75d8c391aea0179562a (patch)
tree83ff13ecbcb17b779e839671fcc0567b4a85e028 /lib
parentbb9a55b6416fdd654e85f65b1cef4d86a416b43e (diff)
downloadsqlalchemy-d76cb7213557c24609a1a75d8c391aea0179562a.tar.gz
Implment encoding_errors for cx_oracle
Added dialect-level flag ``encoding_errors`` to the cx_Oracle dialect, which can be specified as part of :func:`.create_engine`. This is passed to SQLAlchemy's unicode decoding converter under Python 2, and to cx_Oracle's ``cursor.var()`` object as the ``encodingErrors`` parameter under Python 3, for the very unusual case that broken encodings are present in the target database which cannot be fetched unless error handling is relaxed. The value is ultimately one of the Python "encoding errors" parameters passed to ``decode()``. Closes: #4801 Fixes: #4799 Change-Id: I1d542ba367bcd187347c54db1fee815f7890e71c
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/dialects/oracle/cx_oracle.py46
1 files changed, 43 insertions, 3 deletions
diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
index 2572a79b3..d7cd6dcfc 100644
--- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py
+++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py
@@ -78,6 +78,8 @@ The parameters accepted by the cx_oracle dialect are as follows:
* ``coerce_to_decimal`` - see :ref:`cx_oracle_numeric` for detail.
+* ``encoding_errors`` - see :ref:`cx_oracle_unicode_encoding_errors` for detail.
+
.. _cx_oracle_unicode:
Unicode
@@ -124,6 +126,23 @@ VARCHAR2, CHAR, and CLOB, the flag ``coerce_to_unicode=False`` can be passed to
delivered as VARCHAR2/CHAR/CLOB data.
+.. _cx_oracle_unicode_encoding_errors:
+
+Encoding Errors
+^^^^^^^^^^^^^^^
+
+For the unusual case that data in the Oracle database is present with a broken
+encoding, the dialect accepts a parameter ``encoding_errors`` which will be
+passed to Unicode decoding functions in order to affect how decoding errors are
+handled. The value is ultimately consumed by the Python `decode
+<https://docs.python.org/3/library/stdtypes.html#bytes.decode>`_ function, and
+is passed both via cx_Oracle's ``encodingErrors`` parameter consumed by
+``Cursor.var()``, as well as SQLAlchemy's own decoding function, as the
+cx_Oracle dialect makes use of both under different circumstances.
+
+.. versionadded:: 1.3.11
+
+
.. _cx_oracle_setinputsizes:
Fine grained control over cx_Oracle data binding performance with setinputsizes
@@ -760,12 +779,14 @@ class OracleDialect_cx_oracle(OracleDialect):
coerce_to_unicode=True,
coerce_to_decimal=True,
arraysize=50,
+ encoding_errors=None,
threaded=None,
**kwargs
):
OracleDialect.__init__(self, **kwargs)
self.arraysize = arraysize
+ self.encoding_errors = encoding_errors
if threaded is not None:
self._cx_oracle_threaded = threaded
self.auto_convert_lobs = auto_convert_lobs
@@ -823,6 +844,19 @@ class OracleDialect_cx_oracle(OracleDialect):
self._is_cx_oracle_6 = self.cx_oracle_ver >= (6,)
+ @property
+ def _cursor_var_unicode_kwargs(self):
+ if self.encoding_errors:
+ if self.cx_oracle_ver >= (6, 4):
+ return {"encodingErrors": self.encoding_errors}
+ else:
+ util.warn(
+ "cx_oracle version %r does not support encodingErrors"
+ % (self.cx_oracle_ver,)
+ )
+
+ return {}
+
def _parse_cx_oracle_ver(self, version):
m = re.match(r"(\d+)\.(\d+)(?:\.(\d+))?", version)
if m:
@@ -920,7 +954,7 @@ class OracleDialect_cx_oracle(OracleDialect):
):
if compat.py2k:
outconverter = processors.to_unicode_processor_factory(
- dialect.encoding, None
+ dialect.encoding, errors=dialect.encoding_errors
)
return cursor.var(
cx_Oracle.STRING,
@@ -929,7 +963,12 @@ class OracleDialect_cx_oracle(OracleDialect):
outconverter=outconverter,
)
else:
- return cursor.var(util.text_type, size, cursor.arraysize)
+ return cursor.var(
+ util.text_type,
+ size,
+ cursor.arraysize,
+ **dialect._cursor_var_unicode_kwargs
+ )
elif dialect.auto_convert_lobs and default_type in (
cx_Oracle.CLOB,
@@ -937,7 +976,7 @@ class OracleDialect_cx_oracle(OracleDialect):
):
if compat.py2k:
outconverter = processors.to_unicode_processor_factory(
- dialect.encoding, None
+ dialect.encoding, errors=dialect.encoding_errors
)
return cursor.var(
default_type,
@@ -951,6 +990,7 @@ class OracleDialect_cx_oracle(OracleDialect):
size,
cursor.arraysize,
outconverter=lambda value: value.read(),
+ **dialect._cursor_var_unicode_kwargs
)
elif dialect.auto_convert_lobs and default_type in (