pyODBC + unixodbc + Db2 for iSeries = UnicodeDecodeError,非法 UTF-16 代理项
pyODBC + unixodbc + Db2 for iSeries = UnicodeDecodeError, illegal UTF-16 surrogate
我能够在我的 docker 容器中成功地使用 pyODBC 和 SQLAlchemy 连接到 DB2 for iSeries(7.2 版)。它有效,但我会间歇性地 运行 查询并返回以下回溯:
>>> Groups.query.get(group_id)
Traceback (most recent call last):
...
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 154, in reraise
raise value
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1244, in _execute_context
cursor, statement, parameters, context
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 550, in do_execute
cursor.execute(statement, parameters)
UnicodeDecodeError: 'utf-16-le' codec can't decode bytes in position 64-65: illegal UTF-16 surrogate
有时这种情况会连续发生很多次然后突然停止。它并不总是发生在同一组查询中,我已经尝试了两个几乎相同的 DB2 服务器并得到了相同的结果。
对于相同的查询,'position 64-65' 总是相同的(即使有时查询 returns 正确的结果)。
版本:
- pyodbc: 4.0.26
- unixodbc: 2.3.4-1 (debian)
- SQLAlchemy:1.3.5
- iAccess 驱动程序:
ibm-iaccess-1.1.0.11-1.0
终于找到了。
在堆栈的某处,列名别名有 30 个字符的限制。我猜这是 pyodbc(db2 支持 128 长度的列名和别名),我已经 raised an issue on GitHub 跟踪这个问题。
超过 30 个字符的限制时,pyodbc 仍会尝试使用列名的原始长度解码字符串,因此它会尝试解码垃圾数据,有时会导致 UnicodeDecodeError(其他所有时间都会返回垃圾数据。
这是特定于列名的(因此 cursor.keys()
将显示垃圾列名)。
我的解决方法是使用自定义方言强制 SQLAlchemy 截断列别名。
customdb2.py:
from ibm_db_sa.pyodbc import AS400Dialect_pyodbc
class CustomAS400Dialect(AS400Dialect_pyodbc):
max_identifier_length = 30
registry.register('db2.pyodbc400_custom', 'customdb2', 'CustomAS400Dialect')
我能够在我的 docker 容器中成功地使用 pyODBC 和 SQLAlchemy 连接到 DB2 for iSeries(7.2 版)。它有效,但我会间歇性地 运行 查询并返回以下回溯:
>>> Groups.query.get(group_id)
Traceback (most recent call last):
...
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 154, in reraise
raise value
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1244, in _execute_context
cursor, statement, parameters, context
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 550, in do_execute
cursor.execute(statement, parameters)
UnicodeDecodeError: 'utf-16-le' codec can't decode bytes in position 64-65: illegal UTF-16 surrogate
有时这种情况会连续发生很多次然后突然停止。它并不总是发生在同一组查询中,我已经尝试了两个几乎相同的 DB2 服务器并得到了相同的结果。
对于相同的查询,'position 64-65' 总是相同的(即使有时查询 returns 正确的结果)。
版本:
- pyodbc: 4.0.26
- unixodbc: 2.3.4-1 (debian)
- SQLAlchemy:1.3.5
- iAccess 驱动程序:
ibm-iaccess-1.1.0.11-1.0
终于找到了。
在堆栈的某处,列名别名有 30 个字符的限制。我猜这是 pyodbc(db2 支持 128 长度的列名和别名),我已经 raised an issue on GitHub 跟踪这个问题。
超过 30 个字符的限制时,pyodbc 仍会尝试使用列名的原始长度解码字符串,因此它会尝试解码垃圾数据,有时会导致 UnicodeDecodeError(其他所有时间都会返回垃圾数据。
这是特定于列名的(因此 cursor.keys()
将显示垃圾列名)。
我的解决方法是使用自定义方言强制 SQLAlchemy 截断列别名。
customdb2.py:
from ibm_db_sa.pyodbc import AS400Dialect_pyodbc
class CustomAS400Dialect(AS400Dialect_pyodbc):
max_identifier_length = 30
registry.register('db2.pyodbc400_custom', 'customdb2', 'CustomAS400Dialect')