我能够在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服务器并获得了相同的结果。
同一查询的“位置64-65”始终相同(即使有时查询返回正确的结果)。
ibm-iaccess-1.1.0.11-1.0
答案 0 :(得分:1)
最后找到了。
在堆栈的某些地方,列名别名最多可以包含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')