pyODBC + unixodbc + Db2 для iSeries = UnicodeDecodeError, недопустимый суррогат UTF-16 - PullRequest
0 голосов
/ 02 июля 2019

Я могу успешно использовать pyODBC с SQLAlchemy в моем док-контейнере для подключения к DB2 для 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» всегда одинакова для одного и того же запроса (хотя иногда запрос возвращает правильные результаты).

Версии:

  • pyodbc: 4.0.26
  • unixodbc: 2.3.4-1 (debian)
  • SQLAlchemy: 1.3.5
  • Драйвер iAccess: ibm-iaccess-1.1.0.11-1.0

1 Ответ

1 голос
/ 10 июля 2019

Наконец нашел его.

Где-то в стеке существует ограничение в 30 символов для псевдонимов имен столбцов.Я предполагаю, что это pyodbc (db2 поддерживает имена и псевдонимы столбцов длиной 128), и я поднял проблему на 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')
...