LINUX.ORG.RU

[FreeTDS][Qt4] Опять руссие буковки для MS SQL Server'а


0

0

Здравствуйте!

По не зависящим от меня причинам приходится кодить для работы с MS SQL Server'ом 2005. Ограничения FreeTDS известны (нет результатов из хранимых процедур и тэдэ), с ограничениями Qt4 повеселее --- узнаю только после наступления на грабли.

Вот ещё не сталкивался с проблемой. Операция INSERT, в bindValue передаю строку QString с русскими символами (без них всё работает как и надо). При выполнении запроса выдаётся следующая ошибка:

[FreeTDS][SQL Server]The incoming tabular data stream (TDS) protocol stream is incorrect. The stream ended unexpectedly. [FreeTDS][SQL Server]Error converting characters into server's character set. Some character(s) could not be converted.

Если подставлять в bindValue() не саму строку, а типа преобразованную к 8-битной кодировке методами типа toAscii(), toLatin1() (кароче, QByteArray передаётся в bindValue()), то выдаёт ошибку

[FreeTDS][SQL Server]Operand type clash: image is incompatible with varchar.

что вроде бы логично --- ведь bindValue подставляет не строку, а набор байтов, что он понимает как изображение.

Как с этим делом бороться?

Локаль UTF-8. В freetds.conf client charset = UTF-8. В программе на Qt4 запускается QTextCodec::setCodecForCStrings(QTextCodec::codecForName(«UTF-8»));

Куда ещё можно копать? Заранее благодарен!

Ответ на: комментарий от anonymous

> N'string' ?

В SQL-коде? И что даст, если я буду использовать bindValue()? Или вообще без bindValue(), а составлять строку запроса конкатенацией?

Ay49Mihas ★★★★ ()
Ответ на: комментарий от Ay49Mihas

Сейчас при прямой записи в базу добавляются строки вида '?????? ??N??°N????????°N?'

Ay49Mihas ★★★★ ()

FreeTDS сама не занимается никакими перекодировками. Соответственно, строка запроса должна быть в той же кодировке, что и база, если речь о России, то с вероятностью близкой к 100% это CP1251.

archimag ★★★ ()
Ответ на: комментарий от archimag

> FreeTDS сама не занимается никакими перекодировками.

Соответственно, строка запроса должна быть в той же кодировке, что и база, если речь о России, то с вероятностью близкой к 100% это CP1251.

Я бы даже больше сказал, isql всё нормлаьно отрабатывает с русской кодировкой, и результаты select'ов, и insert'ы с русскими именами. А вот через qt4 не хочет. Видимо, это из-за слоя абстракции в qt, bindValue() принимает на вход QVariant.

Ay49Mihas ★★★★ ()
Ответ на: комментарий от Ay49Mihas

>>Обычный varchar. База старая, менять сейчас типы полей нельзя.

тогда как было сказано выше. юзай iconv для перегонки из utf-8 -> cp1251 и обратно.

exception13 ★★★★★ ()
Ответ на: комментарий от archimag

> Так в чём проблема передать строку запроса в cp1251?

Мне нужен комплексный подход, чтобы Interview работало потом спокойненько без костылей. Для получения результатов select'а уже подобрал комбинацию, а для передачи русских строк на сервер ещё нет.

Ay49Mihas ★★★★ ()
Ответ на: комментарий от exception13

> тогда как было сказано выше. юзай iconv для перегонки из utf-8 -> cp1251 и обратно.

Это мне как задействовать, используя QTextCodec, если у меня уже стоит QTextCodec::setCodecForCStrings(QTextCodec::codecForName(«UTF-8»)); ? При этом читаются все данные отлично.

Ay49Mihas ★★★★ ()

у меня история интереснее. есть SyBase версии 12.50 который [censored] не умеет использовать подзапросы ни в from ни в join. доступ к БД read only т.е. вьюхи сразу отпадают. да и с вьюхами будет много плясок с бубном ибо сертифицированный энтерпрайзный софт юзает таблицы вида tableNameYYYYMMDD >_<

exception13 ★★★★★ ()
Ответ на: комментарий от exception13

Кстати, сейчас попробовал на тестовой базе с nvarchar'ом. Один фиг не работает:

[FreeTDS][SQL Server]The incoming tabular data stream (TDS) protocol stream is incorrect. The stream ended unexpectedly. [FreeTDS][SQL Server]Error converting characters into server's character set. Some character(s) could not be converted

Ay49Mihas ★★★★ ()
Ответ на: комментарий от Ay49Mihas

Это если передавать в bindValue() параметр типа QString. А если QByteArray (типа та строка с toAscii()), то опять ругается:

[FreeTDS][SQL Server]Operand type clash: image is incompatible with nvarchar

Ay49Mihas ★★★★ ()
Ответ на: комментарий от exception13

> указывается только входная кодировка или можно указать выходную?

Видимо, нельзя указать выходную, но. QTextCodec::setCodecForCStrings() исползуется для перекодирования в QString::toAscii() и QString::fromAscii(), а при вызове bindValue() этого не происходит. Если туда передавать саму QString (а внутреннее представление у него в UTF-8), то ругаецо на то, что нифига не правильный поток данных к серверу. Если туда передавать QString::toAscii() (тип QByteArray), то оно подставляет его так, что невозможно преобразовать к типу varchar или nvarchar.

По тексту ошибки гугленье выдало

we worked around this last time by making sure that FreeTDS used version
7.0 of the protocol rather than 8.0 .
It appears MS have changed that part of the 8.0 protocol with SQL 2005,
without implementing a new version number of the protocol.
edit the freetds.conf entry for that server so that tds version = 7.0

но указание версии протокола 7.0 ведёт к тому, что самые примитивные запросы не возвращают результаты в программу, и оно висит, ожидая результата.

Ay49Mihas ★★★★ ()

Чото в общем непонятно, что именно надо. Уже всю башку сломал.

Надо либо чтобы bindValue() воспринимало QByteArray в моём случае как строку, и подставляло его значение в кавычки и прочая, а оно видимо пытается его как BLOB впердолить. Либо надо, тчобы QString передавало валидную строку, а вот с этим чото косяки какие-то.

Ay49Mihas ★★★★ ()
Ответ на: комментарий от Ay49Mihas

> Либо надо, тчобы QString передавало валидную строку,

а вот с этим чото косяки какие-то.


Ну, дык, я никогда не использовал Qt, но вообще, ведь задача вроде тривиальная: взять c-строку, с помощью iconv конвертировать её в cp1251 и полученный результат скормить QString?

archimag ★★★ ()
Ответ на: комментарий от archimag

> Ну, дык, я никогда не использовал Qt, но вообще, ведь задача вроде тривиальная: взять c-строку, с помощью iconv конвертировать её в cp1251 и полученный результат скормить QString?

Не совсем. Так как мы используем обвязку Qt4 (для работы с СУБД и строками), то используем и его же средства для конвертации туды-сюды. Но что-то не дружит внутри Qt4 и freeTDS.

Почему я не хочу решать задачу в лоб? Потому что я хочу впоследствии применять с этой же СУБД части системы интервью (модель/вид), а оно не будет хитромудро чонить конвертировать, оно будет использовать стандартные средства.

Ay49Mihas ★★★★ ()
Ответ на: комментарий от Ay49Mihas

> Почему я не хочу решать задачу в лоб?

Ну ты бы сначала проверил, что так будет работать. Тогда ты точно будешь знать в чём дело. А то ты пытаешься решить проблему, причины которой тебе точно не известны. Это всё равно, что в бубен стучать.

archimag ★★★ ()
Ответ на: комментарий от archimag

QString qStr = «INSERT INTO Tabl (StrValue) values (» + QString::fromUtf8( «'ЖопаЖопа')» );

QString qStr = «INSERT INTO Tabl (StrValue) values (» + QString::fromUtf8( «'�������')» );

Дают разный результат в БД, но в обоих случаях он не читаем. �������

Ay49Mihas ★★★★ ()
Ответ на: комментарий от archimag

Это я непосредственно в исходнике на UTF-8 пишув базу стрку на UTF-8 (читаемая) и её же на cp1251 (нечитаемая). Всё преобразуется в Какой-то юникод, судя по знакам вопроса через символ (это я смотрю содержимое таблицы в базе через SQL Enterprise Manager.

Кароче, я в непонятках, в какой кодировке пихать эту строку в запрос...

Ay49Mihas ★★★★ ()
Ответ на: комментарий от Ay49Mihas

Надо строку из utf-8 преобразовать в cp1251, а QString сказать, что это utf-8, как-то, я не знаю, что там делает QString, но просто поставь несколько экспериментов и подбери правильную комбинацию преобразований.

archimag ★★★ ()
Ответ на: комментарий от archimag

> Надо строку из utf-8 преобразовать в cp1251, а QString сказать, что это utf-8

Именно это и пробовал:

QString qStr = «INSERT INTO Tabl (StrValue) values (» + QString::fromUtf8( «'�������')» );

Ay49Mihas ★★★★ ()

Надоело бродить в потьмах. Обновлюсь до 4.6.2 (заодно перекомпилирую поддержку unixODBC с версией 2), если баг останется --- запощу багрепорт.

Ay49Mihas ★★★★ ()

Попробуй так:

QTextEncoder *CP1251 = QTextCodec::codecForName("Windows-1251")->makeEncoder();
Query.bindValue(Position, CP1251->fromUnicode(String));

Kosyak ★★★★ ()
Ответ на: комментарий от Ay49Mihas

Значит проблема не в кодировке, или кодировка не та...

Как вы наверное догадались, мой код переводит из QString в QByteArray с CP1251 внутри...

Kosyak ★★★★ ()
Ответ на: комментарий от Kosyak

> Как вы наверное догадались, мой код переводит из QString в QByteArray с CP1251 внутри...

Я догадался :) Только у меня такое впечатление, что bindValue() опять внутри себя чото перекодирует... либо QSqlQuery::exec, передавая в unixODBC, перекодирует. Короче, кто-то там полёвка :)

Почти дообновлял qt4-4.6.2, скоро посмотрим чокаво

Ay49Mihas ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.