Russian Qt Forum
Май 06, 2024, 21:01 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 3 [4] 5 6 ... 14   Вниз
  Печать  
Автор Тема: Транзакции Interbase  (Прочитано 145783 раз)
ax
Чайник
*
Offline Offline

Сообщений: 60


Просмотр профиля
« Ответ #45 : Февраль 26, 2010, 14:57 »

У меня с Qt SQL driver for Firebird with IBPP library косяк.
В базе есть поле NUMERIC(6, 3).
QFIREBIRD возвращает его, как QVariant(int), а вот QIBASE возвращает, как положено, QVariant(double).
Т.е., если в БД хранится число 3,14, то QFIREBIRD возвращает QVariant(int, 3140), QIBASE, как положено, вернёт QVariant(double, 3.14).


Firebird хранит NUMERIC и DECIMAL поля как целое число и его точность.
Драйвер так и возвращает поле.
QSqlField::type () вернет QVariant::qlonglong или QVariant::Int
QSqlField::precision () вернет значение точности, в Вашем случае 3
но
QSqlField::value () должен вернуть double 3,14

Свойство полей можно посмотреть в демо qt\demos\sqlbrowser\ правой кнопкой на таблице - Show Schema.

Драйвер обрабатывал только NUMERIC с большой длиной который хранился как longlong, то есть поля  типа NUMERIC(12,2) обрабатывал корректно. Ваш вариант NUMERIC(6, 3) храниться в Firebird как int, а NUMERIC(3, 1) как short. Они и не обрабатывались правильно.  Грустный

Короче...

Обновленная версия Qt SQL driver for Firebird with IBPP library.
http://code.google.com/p/qtfirebirdibppsqldriver

Изменения в версии 0.16
- fixed: NUMERIC and DECIMAL fields with small length return wrong value (Issue 7)

Записан
arial
Гость
« Ответ #46 : Февраль 26, 2010, 15:04 »

Всё прекрасно работает. Спасибо огромное!
Записан
sarbash
Гость
« Ответ #47 : Март 05, 2010, 17:32 »

Всем привет!
Кто пользует этот драйвер, может подскажете, что я делаю не так, я просто в ступоре уже...
(Лишнее поскипал.)

В main.cpp:
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("Windows-1251"));

В db.cpp:

db.setConnectOptions("CHARSET=UTF8");
...
query.prepare("insert into REA (NAME) values (:name)");
query.bindValue(":name", "test");
bool result = query.exec();

Получаю:

*** IBPP::SQLException ***
Context: Statement::Execute( insert into REA (NAME) values (?) )
Message: isc_dsql_execute2 failed

SQL Message : -802
Arithmetic overflow or division by zero has occurred.

Engine Code    : 335544321
Engine Message :
arithmetic exception, numeric overflow, or string truncation
Cannot transliterate character between character sets

Ткните, пожалуйста, что я не так делаю?
Вообще-то там в NAME название должно быть кириллицей, но я уже и так и так пробовал, всё равно ошибку выдаёт.

P.S. Даже с query.bindValue(":name", ""); вываливается ошибка. Грустный
« Последнее редактирование: Март 05, 2010, 17:36 от sarbash » Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #48 : Март 05, 2010, 18:09 »

может так:
Код
C++ (Qt)
query.bindValue(":name", "'test'");
Хотя с пустой строкой должно было нормально работать, если в БД ни какой проверки на этот счёт нет
Записан

Юра.
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #49 : Март 05, 2010, 20:59 »

можно DDL код создания таблицы REA ?
Записан
sarbash
Гость
« Ответ #50 : Март 05, 2010, 21:08 »

SET SQL DIALECT 3;

CREATE TABLE REA (
    NAME    VARCHAR(20) DEFAULT 'Укажите название АН',
    PHONE1  PHONE /* PHONE = VARCHAR(15) */,
    PHONE2  PHONE /* PHONE = VARCHAR(15) */,
    PHONE3  PHONE /* PHONE = VARCHAR(15) */,
    PHONE4  PHONE /* PHONE = VARCHAR(15) */
);

P.S. Однако, убрал [DEFAULT 'Укажите название АН'] - заработало!!! Но... только с английскими названиями. С русскими вылетает ошибка:

*** IBPP::SQLException ***
Context: Statement::Execute( insert into REA (NAME) values (?) )
Message: isc_dsql_execute2 failed

SQL Message : -802
Arithmetic overflow or division by zero has occurred.

Engine Code    : 335544321
Engine Message :
arithmetic exception, numeric overflow, or string truncation

P.P.S. Кажется все проблемы решил... Заработало изменением db.setConnectOptions с "CHARSET=UTF8" на "CHARSET=WIN1251", то бишь на тот, в котором локальные строки берутся.

Во-первых, непонятно, в какой кодировке IBExpert положил DEFAULT-значение.
Во-вторых, поле в БД в кодировке UTF8, я соединяюсь с чарсетом WIN1251, как бы проверить, что в базе данные корректно конвертятся в UTF8?...

2break: искренне благодарю за наводку. А то я уже себе мозг сломал на этой проблеме...
« Последнее редактирование: Март 05, 2010, 21:25 от sarbash » Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #51 : Март 05, 2010, 21:40 »

>>то длину VARCHAR надо рассчитывать исходя из (предполагаемое кол-во символов)*2?
Да, в firebirde длинна в байтах
Записан

Юра.
sarbash
Гость
« Ответ #52 : Март 05, 2010, 21:54 »

Благодарю за ответ.
Также я уже просветился немного на сайте "Unicode FAQ - InterBase, Firebird, Delphi 2009, 2010, C++Builder 2009, 2010". Улыбающийся
Там на самом деле 1-4b, для виндовой кириллицы 2b, значит мне нужно множить на 2.
Как я понял, либо сама Qt не умеет перед засылкой на сервер конвертить в UTF8, то ли это драйвер должен делать, а может мне надо в коде как-то преобразовать значение перед биндингом?
Невольно начинаю думать, а может перейти на win1251 и не парить себе мозг? А так хотелось юникода...
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #53 : Март 06, 2010, 00:22 »

Может вопрос в том в какой кодировке исходник?
Например у меня исходник в UTF-8 и в БД firebird UTF-8 - все работает без особых заморочек-перекодировок,
если у вас БД в utf-8 а исходник в Win-1251 - надо просто найти способ перед биндингом строки переводить в utf-8 (БД и драйвер не в силах наверное это сами сделать) - может использовать какие=то методы QString::fromUTF8(в смысле аналогичные)

кстати IBExpert много чем хорош но бесплатный с юникодом плохо дружит, а FlameRobin попроще - но там вроде все ОК.
Записан
sarbash
Гость
« Ответ #54 : Март 06, 2010, 08:47 »

Да, думаю вы правы.
Qt Creator исходники создаёт в системной кодировке, а в винде это win1251. Я подумал, что в принципе, в основном разработка идёт в винде, под линуксом, если я и буду что писать для этого проекта, то выбрать кодировку в креаторе недолго. Решение пришло простое и логичное - для этого проекта всё перевести на win1251.
Благодарю всех, кто принял участие в решении моей проблемы. Мой первый опыт, мои первые грабли.
В IBExpert-е есть то ли фича, то ли костыль, если надо юникодные данные править - встроенный юникодный редактор значения поля. Inplace там ансишный, а если ткнуть на комбобокс, то отображается отдельной формой редактор для юникода. Гриды в эксперте отображают юникод вроде бы корректно. Ещё у меня какая-то проблема с ним была, так что я чарсет соединения указывал не utf8, а unicode-fss, но уже не помню, в чём там дело было.
Записан
Tonal
Гость
« Ответ #55 : Март 09, 2010, 11:12 »

Добавил issue 8 в трекер проекта.
Записан
const
Гость
« Ответ #56 : Март 11, 2010, 17:58 »

Здравствуйте. Начал переводить свой проект из BCB6 и Firebird 2.x на Qt. Стал использовать плагин для Qt, на который здесь была выложена ссылка. Все основные операции работают, но вот с prepare возникла интересная проблема такого плана:
есть таблица БД:
Код:
CREATE TABLE Cans
( CANNUM SMALLINT NOT NULL,
  DTTM TIMESTAMP NOT NULL,
  CANVALUE DOUBLE PRECISION NOT NULL);


если добавлять в неё данные инсертом 1 раз, то всё выполняется. но вот такой код:
Код:
QSqlDatabase DBStoreWrite= QSqlDatabase::addDatabase("QFIREBIRD","DBStoreWrites");
    DBStoreWrite.setConnectOptions("CHARSET=WIN1251");
    DBStoreWrite.setDatabaseName("DBStore");


    DBStoreWrite.open("SYSDBA","masterkey");

    QSqlQuery SqlTest(DBStoreWrite);
    SqlTest.prepare("INSERT INTO Cans (CANNUM,DTTM,CANVALUE) VALUES (:CANNUM,'NOW',:CANVALUE)");
    for (int i=0;i<2;i++)
    {
        SqlTest.bindValue(0,1);
        SqlTest.bindValue(1, i);

        DBStoreWrite.transaction();
        SqlTest.exec();
        DBStoreWrite.commit();
    }

    DBStoreWrite.close();


приводит к появлению ошибок:
Цитировать
*** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared.

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

Причём первый инсерт выполняется корректно (в таблицу данные заносятся), а вот остальные - нет. Соответственно количество ошибок равно количеству запросов -1.

Проверял на вставку в другие таблицы с другими типами полей, всё то же самое.
Пробовал обращаться к параметрам запроса по номеру, по имени - тоже ничего не меняется.
Убирал старт/коммит транзакции  - то же самое.

Единственный вариант - это внести препаре в цикл, но тогда это уже не препаре получается.

Всю голову сломал уже, пришел к выводу, что это какая то проблема в плагине.
Может тут кто сталкивался с такой проблемой? если сталкивались, то как решали?
Записан
Tonal
Гость
« Ответ #57 : Март 12, 2010, 08:03 »

Вынеси транзакцию за цикл:
Код
C++ (Qt)
   QSqlDatabase DBStoreWrite= QSqlDatabase::addDatabase("QFIREBIRD","DBStoreWrites");
   DBStoreWrite.setConnectOptions("CHARSET=WIN1251");
   DBStoreWrite.setDatabaseName("DBStore");
 
 
   DBStoreWrite.open("SYSDBA","masterkey");
 
   QSqlQuery SqlTest(DBStoreWrite);
   DBStoreWrite.transaction();
   SqlTest.prepare("INSERT INTO Cans (CANNUM,DTTM,CANVALUE) VALUES (:CANNUM,'NOW',:CANVALUE)");
   for (int i=0;i<2;i++)
   {
       SqlTest.bindValue(0,1);
       SqlTest.bindValue(1, i);
 
       SqlTest.exec();
   }
   DBStoreWrite.commit();
 
   DBStoreWrite.close();
 
Заодно и скорость чуть поднимется. Улыбающийся
Записан
const
Гость
« Ответ #58 : Март 12, 2010, 09:13 »

Цитировать
Вынеси транзакцию за цикл:
Пробовал, не помогает. К тому же дело в том, что этот абсурдный на первый взгляд код лишь демка, на которой я пытался выяснить в моём коде чтото не так или в другом.
Понятно, что кучу однотипных запросов лучше выполнить в одной транзакции. Но в оригинальном коде нужно чтобы каждый запрос именно своей транзакцией писался (там это не повлияет на скорость, запросов не много).
Опять же повторюсь, но
Цитировать
Убирал старт/коммит транзакции  - то же самое.
Я не понимаю почему он ругается на то, что ничего не было подготовлено. Если смотреть перед exec() в отладчике, то там видно, что значения параметров действительно в QQuery заносятся (в values). На момент перед выполнением запроса в поле error у QSqlQuery нет ошибки.
Записан
ax
Чайник
*
Offline Offline

Сообщений: 60


Просмотр профиля
« Ответ #59 : Март 12, 2010, 11:39 »

Цитировать
Единственный вариант - это внести препаре в цикл, но тогда это уже не препаре получается.

Всю голову сломал уже, пришел к выводу, что это какая то проблема в плагине.
Может тут кто сталкивался с такой проблемой? если сталкивались, то как решали?

Вопрос в драйвере. Зацепил эту штуку в одном из релизов. Проверил - в драйвере ок.
Хочу сегодня поправить и разобраться с кодировками.
Выложу исправление.
« Последнее редактирование: Март 13, 2010, 15:29 от axax » Записан
Страниц: 1 2 3 [4] 5 6 ... 14   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.091 секунд. Запросов: 23.