Проблема
Для работы с базой данных MSSQL Server 2005 в кодировке UTF-16(UCS2) я использую скрипт, написанный на python. Этот скрипт использует для работы с базой данных следующий набор инструментов:
- unixODBC
- FreeTDS
- pyodbc
- sqlachemy
И тут появилась трудность: при получении строковых данных из базы (поля nvarchar, ntext) неправильно обрабатывается юникод.
Как выяснилось, установленный у меня питон был собран с UCS4 юникодом. Методы получения типа юникода в сборка python хорошо описаны в данном вопросе на stackoverflow. Т.е, если выполнить следующую строчку в терминале:
python -c "import sys;print 'UCS4' if sys.maxunicode > 65536 else 'UCS2'"
то мы получаем версию сборки юникода для python.В моем случае это было UCS4. Что это за собой тянет:
- unixODBC вызывая соответствующие функции работы с базой данных с аппендиксом W (например, SQLExecDirectW()), получает результаты. в которых один символ текста занимает 2 байта(UCS2)
- pyodbc получает результаты от ODBC-драйвера, и в свою очередь сохраняет результаты в переменную с типом unicode
- Таким образом 1 символ результата, по мнению pyodbc, составляет 4 байта(UCS4). Именно так и сохраняется результат. полученный из ODBC-драйвера.
Драйвер возвращает данные, в которых символ занимает 2 байта, а pyodbc переделывает эти данные так, что символ занимает 4 байта. Все бы хорошо, если бы было какое-либо преобразование, но данные просто сохраняются как массив байтов в переменную с типом unicode, что несет неприятные последствия: символ результата по-сути содержит 2 символа того результата, который вернул ODBC-драйвер.
Читать полностью »