Russian Qt Forum

Qt => Базы данных => Тема начата: xakpc от Февраль 05, 2009, 18:29



Название: Транзакции Interbase
Отправлено: xakpc от Февраль 05, 2009, 18:29
Здрасте всем.
Можно ли как-нибудь запустить несколько транзакций для Interbase на Qt? Очень хочется мне читающую и пишущую транзакции. А еще хочется установить уровень изолированности для транзакций, это возможно в Qt?

Может быть какие-нибудь плагины..


Название: Re: Транзакции Interbase
Отправлено: Пантер от Февраль 05, 2009, 19:15
Стандартный плагин позволяет только одну транзакцию. Можно напрямую исходники огнептица подключать, но тогда придется много доков читать. :) Или для каждой транзакции свое подключение.


Название: Re: Транзакции Interbase
Отправлено: vipet от Февраль 06, 2009, 00:12
Рекоммендую либу ibpp (www.ipbb.org) (http://www.ibpp.org/ )вместо ibase. Разобраться с ней просто.

На базе ibpp я даже написал qt-шные классы для БД, транзакций, запросов, полей (во многом схожие с VCL-овыми, мне нравилось как дельфи с БД работает), а также моделей и проч. (Но по опр. причинам поделиться этим кодом не могу.)


Название: Re: Транзакции Interbase
Отправлено: ритт от Февраль 06, 2009, 01:01
http://www.ipbb.org/ - обалденный сайтик...где-то я уже видел такое оформление :)

vipet, совсем никак не можешь поделиться этим кодом? а то была задумка сделать подобную приблуду с целью упрощения жизни - раз; и выявления слабых мест в QtSql - два. только пока всё времени на не хватает %(


Название: Re: Транзакции Interbase
Отправлено: vipet от Февраль 06, 2009, 06:46
Константин,
сорри, www.ibpp.org конечно же :)

Цитировать
vipet, совсем никак не можешь поделиться этим кодом?
К сожалению нет (специально об этом сразу написал), по крайней мере сейчас. Весь этот код весит порядка 40Kb, немного с одной стороны, а с другой - для всего хватало пока (несколько проектов в течение последнего года)



Название: Re: Транзакции Interbase
Отправлено: Alex03 от Февраль 06, 2009, 17:43
xakpc Несколько кривой способ (сам не пробовал):
Создаёшь несколько соединений (баз данных), в каждом своя транзакция.

Я тоже пользовал IBPP, только без всякий обёрток.


Название: Re: Транзакции Interbase
Отправлено: ax от Февраль 09, 2009, 19:12
Привет.
Есть свой Qt драйвер под Firebird/Interbase/
Писал с использованием IBPP. ( у меня IBPP 2.5.2.0 )
Можно указывать кодировку базы
Код:
    db.setConnectOptions("CHARSET=WIN1251");
Корректная работа с BLOB.
Позволяет указывать тип транзакции.
Код:

#define TRANSACTION(x) (QSqlDatabase::database().driver()->setProperty("Transaction",(x)))
#define TRANS_SELECT "TAM=amRead, TIL=ilReadCommitted, TLR=lrNoWait, TFF=0"
#define TRANS_UPDATE "TAM=amWrite, TIL=ilConcurrency, TLR=lrNoWait, TFF=0"
#define TRANS_REPORT "TAM=amRead, TIL=ilConcurrency, TLR=lrNoWait, TFF=0"
#define TRANS_DEFAULT "TAM=amWrite, TIL=ilConcurrency, TLR=lrWait, TFF=0"
// .............
TRANSACTION(TRANS_SELECT);
QSqlQuery query.prepare(".........



можно через один коннект открывать несколько транзакций.
....

Говори куда положить или закину в google code


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Февраль 09, 2009, 19:19
ты главное закидывай, а уж мы скачаем.

П.С. а события (уведомления) БД тоже реализованы?


Название: Re: Транзакции Interbase
Отправлено: Alex03 от Февраль 09, 2009, 20:02
Есть свой Qt драйвер под Firebird/Interbase/
Писал с использованием IBPP. ( у меня IBPP 2.5.2.0 )
Можно указывать кодировку базы
Код:
    db.setConnectOptions("CHARSET=WIN1251");

Вот это место у тролей вообще смешное. И вся проблема в том что для одной и той же кодировки в Qt и IB/FB используются разные имена.
Если передавать "ISC_DPB_LC_CTYPE=WIN1251" то эту кодировку не знает Qt и драйвер матерится ещё до передачи этого параметра клиенту БД.
Если передавать кудировку которую знает Qt (например "ISC_DPB_LC_CTYPE=Windows-1251"), то эту кодировку не знает клиет БД.

Самое простое добавить WIN1251 алиас на тексткодек, в файле QTDIR\src\corelib\codecs\qsimplecodec.cpp
Второе изменить проверку в драйвере.

Мне нельзя было править исходники Qt и драйвера, поэтому извращнулся таким способом - добавил новый кодек:
Код:
#include <QTextCodec>
class CTextCodecWIN1251 : public QTextCodec
{
private:
    QTextCodec *win1251Codec;

public:
    CTextCodecWIN1251();
    ~CTextCodecWIN1251();

    virtual QByteArray name() const;
    virtual QList<QByteArray> aliases() const;
    virtual int mibEnum() const;

protected:
    virtual QByteArray convertFromUnicode( const QChar * input, int number, ConverterState * state ) const;
    virtual QString convertToUnicode( const char * chars, int len, ConverterState * state ) const;
};
CTextCodecWIN1251::CTextCodecWIN1251()
{
    win1251Codec = QTextCodec::codecForName("Windows-1251");
}
CTextCodecWIN1251::~CTextCodecWIN1251()
{
}
QByteArray CTextCodecWIN1251::convertFromUnicode(const QChar * input, int number, ConverterState * state) const
{
    if(!win1251Codec)
        return QByteArray();
    return win1251Codec->fromUnicode(input, number, state);
}
QString CTextCodecWIN1251::convertToUnicode(const char * chars, int len, ConverterState * state) const
{
    if(!win1251Codec)
        return QString();
    return win1251Codec->toUnicode(chars, len, state);
}
QByteArray CTextCodecWIN1251::name() const
{
    return QByteArray("WIN1251");
}
QList<QByteArray> CTextCodecWIN1251::aliases() const
{
    QList<QByteArray> list;
    list << QByteArray("WIN-1251") // Эти алиасы не обязательны
         << QByteArray("CP1251")
         << QByteArray("CP-1251")
         << QByteArray("1251");
    return list;
}
int CTextCodecWIN1251::mibEnum() const
{
    if(!win1251Codec)
        return 0;
    return 2251;
}


...
    CTextCodecWIN1251 * p = new CTextCodecWIN1251();
...
    db.setConnectOptions("ISC_DPB_LC_CTYPE=WIN1251");


Название: Re: Транзакции Interbase
Отправлено: Alex03 от Февраль 09, 2009, 20:09
Привет.
Есть свой Qt драйвер под Firebird/Interbase/
Писал с использованием IBPP. ( у меня IBPP 2.5.2.0 )
Можно указывать кодировку базы
Корректная работа с BLOB.
Позволяет указывать тип транзакции.
можно через один коннект открывать несколько транзакций.
Говори куда положить или закину в google code
axax Драйвер несомненно интересен народу.
Что мешает выложить его здесь?


Название: Re: Транзакции Interbase
Отправлено: ритт от Февраль 09, 2009, 23:35
axax, мне кажется, лучше на гуглокод - там и ты владельцем проекта будешь, и любой сможет присоединиться к проекту или форкнуть код.
я знаю по-крайней мере двоих, кому было бы интересно развить сие чудо...


Название: Re: Транзакции Interbase
Отправлено: vipet от Февраль 10, 2009, 08:46
axax,

Выкладывай, заценим!

P.S. Почему ibpp 2.5.2.0 - просто так или нет? (Я юзаю 2.5.3.1)


Название: Re: Транзакции Interbase
Отправлено: ax от Февраль 10, 2009, 19:35
Всем привет.

Проект на гуглокоде     qtfirebirdibppsqldriver
Сейчас исходники закидываю.

>>Можно указывать кодировку базы
>>Код:
>>    db.setConnectOptions("CHARSET=WIN1251");
>>Вот это место у тролей вообще смешное. И вся проблема в том что для одной и той же кодировки в Qt и IB/FB используются разные имена.

Дак это , я думаю можно разрулить прям в db.setConnectOptions(...).

>>P.S. Почему ibpp 2.5.2.0 - просто так или нет? (Я юзаю 2.5.3.1)
драйвер писался для проекта два года назад (Firebird 1.5.*). и на тот момент ibpp была текущая :)
проект сдал и сейчас работаю с другими базами, поэтому библу и сам драйвер не пользую.
Скачаю новую и соберу - думаю проблем не будет.
Работает под Linux и Win. Тестил и на Солярисе.
С Firebird 2.* не гонял, надо попробывать.

....
О. собрался и с 2.5.3.1.  ;D ..... и запустился даже  :o






Название: Re: Транзакции Interbase
Отправлено: ax от Февраль 10, 2009, 20:09
ок.
Выложил сырцы в svn и скомпиленный под windows Qt 4.4.3 mingw. IBPP 2.5.3.1.
http://code.google.com/p/qtfirebirdibppsqldriver/ (http://code.google.com/p/qtfirebirdibppsqldriver/)

По вопросам стучите сюда.


Название: Re: Транзакции Interbase
Отправлено: ритт от Февраль 10, 2009, 20:15
первая закачка - моя :)

за публикацию отдельное "спасибо"!


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Февраль 10, 2009, 20:27
тогда я нумер два


Название: Re: Транзакции Interbase
Отправлено: vipet от Февраль 10, 2009, 21:06
Третий не знаю кто, а я - четвертый. Щяс заценим :)


Название: Re: Транзакции Interbase
Отправлено: vipet от Февраль 10, 2009, 21:51
Вобщем, что касается взаимодействия с IBPP, то у меня практически всё то же самое. (Это и немудрено, т.к. как я грил раньше, работать с либой просто http://www.ibpp.org/reference )

Отличие пока увидел при чтении блоба: можно читать максимальными кусками (используя void Blob::Info(int* size, int* largest, int* segments), а не по килобайту

у ахах'а:
Код:
                IBPP::Blob l_Blob = IBPP::BlobFactory(rp->iDb, rp->iTr);
                rp->iSt->Get(i, l_Blob);

                QByteArray l_QBlob;

                l_Blob->Open();
                int l_Read, l_Offset = 0;
                char buffer[1024];
                while ((l_Read = l_Blob->Read(buffer, 1024)))
                {
                    l_QBlob.resize(l_QBlob.size() + l_Read);
                    memcpy(l_QBlob.data() + l_Offset, buffer, l_Read);
                    l_Offset += l_Read;
                }
                l_Blob->Close();

                row[idx] = l_QBlob;
                break;

у меня:
Код:
		IBPP::Blob blob = IBPP::BlobFactory(m_Database->getIBPPDB(),
m_Transaction->getIBPPTransaction());

m_Statement->Get(FieldNum, blob);
blob->Open();

int bytesTotal;
int largestChunkSize;
int segmentsTotal;
int chunkSize;
int bytesRead = 0;

blob->Info(&bytesTotal, &largestChunkSize, &segmentsTotal);
data->resize(bytesTotal);

do
{
chunkSize = (bytesTotal - bytesRead) < largestChunkSize ?
(bytesTotal - bytesRead) : largestChunkSize;
bytesRead = blob->Read((void*)data->data(), chunkSize);
} while (bytesTotal != bytesRead);

blob->Close();

Также запись в блоб я сделал через Blob::Write(), а не через Statement::Set(). Не знаю лучше это или хуже (на момент написания просто не заметил, что блоб писать можно через Statement::Set()). В Blob::Write() можно писать чанками до 32-х килобайт (ограничение фиребёрда)


Название: Re: Транзакции Interbase
Отправлено: ax от Февраль 11, 2009, 15:37
Привет.

Изменил чуть проект для сбоки с компиляторами Microsoft и выложил собранный драйвер под VC 6.0 и 2008.
vipet. Твой вариант с блобом надо пробывать. Насколько помню был нюанс под linux.
http://code.google.com/p/qtfirebirdibppsqldriver (http://code.google.com/p/qtfirebirdibppsqldriver)


Название: Re: Транзакции Interbase
Отправлено: c00ker от Февраль 18, 2009, 13:49
Спасибо за выложенный труд, я уже с Firebird на последних версиях Qt затрахался. До этого пользовался 4.2.2 с QODBC, кодировка базы CP1251 и все было ок. На последних версиях Qt в этом же проекте при вводе данных все преобразуется в уникод, хз в чем проблема, может и в драйвере ODBC птицы.

Попробовал этот драйвер, заметил, что numRowsAffected возвращает все время -1. Версия Firebird-2.1.1.17910-0, Qt4.4.3. Чуть поменял кусок в драйвере (закомментил две строчки), заработало вроде :)

Код:
int QFBResult::numRowsAffected()
{
    int nra = -1;
   
    //if (isSelect())
     //   return nra;

    try
    {
        nra = rp->iSt->AffectedRows();
    }
    catch (IBPP::Exception& e)
    {}
    return nra;
}


Название: Re: Транзакции Interbase
Отправлено: ритт от Февраль 18, 2009, 14:48
c00ker, зачем закомментировал? там всё правильно :)
numRowsAffected должен возвращать -1 для селектов. а ты, похоже, говоришь про querySize


Название: Re: Транзакции Interbase
Отправлено: c00ker от Февраль 18, 2009, 15:17
Ну да, похоже нужно было комментить ф-ию QFBResult::size() :)
Код в size():

Код:
int QFBResult::size()
{
    int nra = -1;
    return nra;
...


Название: Re: Транзакции Interbase
Отправлено: vipet от Февраль 18, 2009, 18:07
Немного оффтопа:

А разве Firebird возвращает кол-во строк для SELECT-запроса? Т.е. разве можно узнать кол-во записей, пока все их не считали?


Название: Re: Транзакции Interbase
Отправлено: Dimich от Май 09, 2009, 18:21
axax,
можете ли перелицензировать qtfirebirdibppsqldriver под LGPL или двойной LGPL/GPL лицензией?


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Январь 21, 2010, 10:36
Уже достаточно давно пользуюсь Qt IPBB Sql Driver ( http://code.google.com/p/qtfirebirdibppsqldriver/ ). Постил на его страчинчку несколько предложений, и не я один, но вижу что давно не было ответов и работ. Нашел здесь на форуме сообщение чтоб по вопроам обращатся сюда. Вот и обращаюсь. Может кто подскажет судьбу этого проекта, он жив или уже нет?


Название: Re: Транзакции Interbase
Отправлено: ax от Январь 21, 2010, 11:29
Уже достаточно давно пользуюсь Qt IPBB Sql Driver ( http://code.google.com/p/qtfirebirdibppsqldriver/ ). Постил на его страчинчку несколько предложений, и не я один, но вижу что давно не было ответов и работ. Нашел здесь на форуме сообщение чтоб по вопроам обращатся сюда. Вот и обращаюсь. Может кто подскажет судьбу этого проекта, он жив или уже нет?

Проект в зимней спячке :)
Постараюсь до понедельника добраться.
Спасибо за предложения.
По обновлению напишу сюда.



Название: Re: Транзакции Interbase
Отправлено: gigabyte от Январь 21, 2010, 12:55
если надо я тоже мог бы подключится и немного попостить туда на google code


Название: Re: Транзакции Interbase
Отправлено: ax от Январь 25, 2010, 19:13
Свежая версия Qt SQL driver for Firebird with IBPP library.
http://code.google.com/p/qtfirebirdibppsqldriver (http://code.google.com/p/qtfirebirdibppsqldriver)

Изменения в версии 0.14
- fixed ASSERTION in qsqlcachedresult when calling stored procedure (Issue 1)
- fixed bug when blob contains '\0' char (Issue 2)
+ Add support of firebird ROLE (Issue 3)
+ change in IbppDriver.pro for  support debug and release builds (Issue 4)
- fixed bug when only "NONE" and "WIN1251" charset is set (Issue 5)
- compile warnings

Внимание: кодировка по умолчанию изменена на "NONE"

Также свежие сборки под Qt 4.6.1
gcc 4.4 http://qtfirebirdibppsqldriver.googlecode.com/files/qsqlfb_gcc_4.6.1.zip (http://qtfirebirdibppsqldriver.googlecode.com/files/qsqlfb_gcc_4.6.1.zip)
MS Visual C++ 2008 http://qtfirebirdibppsqldriver.googlecode.com/files/qsqlfb_2008_4.6.1.zip (http://qtfirebirdibppsqldriver.googlecode.com/files/qsqlfb_2008_4.6.1.zip)

Спасибо за пожелания и исправления. Новые принимаются на http://code.google.com/p/qtfirebirdibppsqldriver/issues/list (http://code.google.com/p/qtfirebirdibppsqldriver/issues/list) и на форуме.

P.S.
если надо я тоже мог бы подключится и немного попостить туда на google code
- написал в личку


Название: Re: Транзакции Interbase
Отправлено: xokc от Январь 25, 2010, 19:58
А ссылки на gcc и msvc версии одинаковы случайно или так и должно быть?


Название: Re: Транзакции Interbase
Отправлено: ax от Январь 25, 2010, 23:48
А ссылки на gcc и msvc версии одинаковы случайно или так и должно быть?
Упс...
Исправил.
Спасибо.


Название: Re: Транзакции Interbase
Отправлено: Dimich от Январь 27, 2010, 09:11
axax,
можете ли Вы перелицензировать qtfirebirdibppsqldriver под LGPL или двойной LGPL/GPL лицензией?
Qt, начинас с версии 4.5, поддерживет лицензию LGPL,  у IBPP BSD-подобная лицензия.
Многие дполнительные библиотеки к Qt перелицензировались под лицензией LGPL (Qwt, OpenRPT и т.д.). Может, логичнее было выпуск qtfirebirdibppsqldriver под лицензией LGPL?


Название: Re: Транзакции Interbase
Отправлено: sarbash от Февраль 12, 2010, 22:50
У меня установлена Qt версии 4.6.0
Попытался собрать плагин - собирается. Скопировал на место, пытаюсь запустить программу, получаю ошибку:

QSqlDatabase: QFIREBIRD driver not loaded
QSqlDatabase: available drivers: QIBASE QSQLITE QODBC3 QODBC
D:\projects\irr-ad\debug\irr-ad.exe завершился с кодом 1

Подскажите, пожалуйста, что сделать, чтобы он заработал?
Вроде бы правильно положил библиотеки:
%QTDIR%\plugins\sqldrivers\qsqlibase4.dll
%QTDIR%\plugins\sqldrivers\libqsqlibase4.a

В программе вызов делается так:

Код:
bool create_connection()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QFIREBIRD");
    db.setConnectOptions("ISC_DPB_LC_CTYPE=UTF8");
    // TODO после отладки установить пусть к бд:
    // db.setDatabaseName(qApp->applicationDirPath() + "db/IRR-AD.FDB");
    db.setDatabaseName("../db/IRR-AD.FDB");
    db.setUserName("sysdba");
    if (!db.open()) {
        QMessageBox::critical(0, qApp->applicationName(),
                              QString("Не удалось соединиться с БД:\n%1").arg(
                              db.lastError().databaseText()));
        return false;
    }
    return true;
}


Название: Re: Транзакции Interbase
Отправлено: ax от Февраль 13, 2010, 01:30
...
QSqlDatabase: available drivers: QIBASE QSQLITE QODBC3 QODBC
...
%QTDIR%\plugins\sqldrivers\qsqlibase4.dll
%QTDIR%\plugins\sqldrivers\libqsqlibase4.a
...
В программе вызов делается так:

Код:
    QSqlDatabase db = QSqlDatabase::addDatabase("QFIREBIRD");
...

судя по всему ты собрал драйвер для  IBASE из самого Qt.
Сырцы и собранные dll QFIREBIRD лежат на http://code.google.com/p/qtfirebirdibppsqldriver/ (http://code.google.com/p/qtfirebirdibppsqldriver/)



Название: Re: Транзакции Interbase
Отправлено: sarbash от Февраль 13, 2010, 10:24
Если бы всё так просто было...

Поскипаем неважное...
Код:
Содержимое папки C:\devel\Qt\2009.05\qt\plugins\sqldrivers
...
12.02.2010  22:29             2 200 libqsqlfirebird.a
...
12.02.2010  22:29           833 536 qsqlfirebird.dll
...
              15 файлов      5 451 375 байт
               2 папок  17 727 313 408 байт свободно

собирал из

Код:
svn checkout http://qtfirebirdibppsqldriver.googlecode.com/svn/trunk/ qtfirebirdibppsqldriver-read-only

Почему не видит не подхватывает - ума не приложу... попробую обновиться до 4.6.1
Постом выше я привёл функцию по установке коннекта - разве я там неправильно написал?


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Февраль 13, 2010, 10:58
Переименуй
libqsqlfirebird.a -> libqsqlfirebirdd.a
qsqlfirebird.dll -> qsqlfirebirdd.dll
И убедись что ти собираешь именно debug!!!!!


Название: Re: Транзакции Interbase
Отправлено: sarbash от Февраль 13, 2010, 13:31
Большое спасибо, простите за мою глупость, нельзя столько работать (это я о себе)... :(
Проблема была в том, что для драйвера собран был релиз (это по-умолчанию настроено), а рабочий проект с использованием драйвера собирается в дебаг-версии. Естественно, драйвер не был найден, а я вчера бился и понять не мог, что делаю не так. Вопрос решён, всем большое спасибо за участие!

Искренне благодарен за плагин, т.к. неизбежно пришлось бы самому писать, если бы не было готового. То, что идёт в комплекте, -- жалкое убожество, особенно после дельфёвых IBX компонент.

2gigabyte: Особая благодарность, Вы навели меня на верную мысль. А то у меня уже ум за разум заходить начал, но это личные проблемы, оффтоп.

P.S. Осталось разобраться с кодировками...
Код:
Запускается D:\projects\irr-ad\debug\irr-ad.exe...
HookingD:\PROJECTS\IRR-AD\DEBUG\IRR-AD.EXE
D:\PROJECTS\IRR-AD\DEBUG\IRR-AD.EXERPH:Injecting code at start up
done...
QFBDriver::open: Unknown connection attribute 'ISC_DPB_LC_CTYPE=UTF8'
D:\projects\irr-ad\debug\irr-ad.exe завершился с кодом 0


Название: Re: Транзакции Interbase
Отправлено: sarbash от Февраль 13, 2010, 13:36
...
QSqlDatabase: available drivers: QIBASE QSQLITE QODBC3 QODBC
...
%QTDIR%\plugins\sqldrivers\qsqlibase4.dll
%QTDIR%\plugins\sqldrivers\libqsqlibase4.a
...
В программе вызов делается так:

Код:
    QSqlDatabase db = QSqlDatabase::addDatabase("QFIREBIRD");
...

судя по всему ты собрал драйвер для  IBASE из самого Qt.
Сырцы и собранные dll QFIREBIRD лежат на http://code.google.com/p/qtfirebirdibppsqldriver/ (http://code.google.com/p/qtfirebirdibppsqldriver/)



Прошу прощения, я ввёл Вас в заблуждение, на самом деле я собирал естественно Ваш драйвер, а сюда ошибочно запостил листинг того, что в комплекте идёт. Я его до этого собирал. Это я вчера просто загнался, ещё раз простите великодушно. Я теперь уже разобрался, в чём был неправ.


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Февраль 13, 2010, 13:47
Цитировать
P.S. Осталось разобраться с кодировками...
см. Исходники драйвера и вместо
Код:
database.setConnectOptions("ISC_DPB_LC_CTYPE=WIN1251");
попробуй
Код:
database.setConnectOptions("CHARSET=WIN1251");


Название: Re: Транзакции Interbase
Отправлено: sarbash от Февраль 13, 2010, 16:58
Уже. Как я понял, здесь сорцы выступают в качестве мануала. :)


Название: Re: Транзакции Interbase
Отправлено: sarbash от Февраль 13, 2010, 17:38
Переименуй
libqsqlfirebird.a -> libqsqlfirebirdd.a
qsqlfirebird.dll -> qsqlfirebirdd.dll
И убедись что ти собираешь именно debug!!!!!


Вместо этого я разные таргеты в проекте указал для дебага и релиза, там в issue на гуглокоде есть по этому поводу.


Название: Re: Транзакции Interbase
Отправлено: ax от Февраль 15, 2010, 19:28
Обновленная версия Qt SQL driver for Firebird with IBPP library.
http://code.google.com/p/qtfirebirdibppsqldriver (http://code.google.com/p/qtfirebirdibppsqldriver)

Изменения в версии 0.15
- fixed Produce different targets depengind on config (Debug Release) ( Issue 6 )
+ license under LGPL version 2.1
+ license under GPL version 3.0

Спасибо за пожелания и исправления.
Новые принимаются на http://code.google.com/p/qtfirebirdibppsqldriver/issues/list (http://code.google.com/p/qtfirebirdibppsqldriver/issues/list) и на форуме.


Название: Re: Транзакции Interbase
Отправлено: arial от Февраль 16, 2010, 15:30
У меня с 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).


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Февраль 16, 2010, 21:59
>axax
Думаю следует обратить внимание на qIBaseTypeName2 в исходниках родного interbase драйвера


Название: Re: Транзакции Interbase
Отправлено: arial от Февраль 25, 2010, 15:43
Может уважаемый axax как-то прокомментирует пост о проблеме с полем numeric (http://www.prog.org.ru/index.php?topic=8509.msg79192#msg79192)?


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Февраль 25, 2010, 17:41
arial, напиши ему в ГуглоКод, может он там чаще мониторит


Название: Re: Транзакции Interbase
Отправлено: ax от Февраль 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 (http://code.google.com/p/qtfirebirdibppsqldriver)

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



Название: Re: Транзакции Interbase
Отправлено: arial от Февраль 26, 2010, 15:04
Всё прекрасно работает. Спасибо огромное!


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 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", ""); вываливается ошибка. :(


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Март 05, 2010, 18:09
может так:
Код
C++ (Qt)
query.bindValue(":name", "'test'");
Хотя с пустой строкой должно было нормально работать, если в БД ни какой проверки на этот счёт нет


Название: Re: Транзакции Interbase
Отправлено: break от Март 05, 2010, 20:59
можно DDL код создания таблицы REA ?


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 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: искренне благодарю за наводку. А то я уже себе мозг сломал на этой проблеме...


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Март 05, 2010, 21:40
>>то длину VARCHAR надо рассчитывать исходя из (предполагаемое кол-во символов)*2?
Да, в firebirde длинна в байтах


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 05, 2010, 21:54
Благодарю за ответ.
Также я уже просветился немного на сайте "Unicode FAQ - InterBase, Firebird, Delphi 2009, 2010, C++Builder 2009, 2010". :)
Там на самом деле 1-4b, для виндовой кириллицы 2b, значит мне нужно множить на 2.
Как я понял, либо сама Qt не умеет перед засылкой на сервер конвертить в UTF8, то ли это драйвер должен делать, а может мне надо в коде как-то преобразовать значение перед биндингом?
Невольно начинаю думать, а может перейти на win1251 и не парить себе мозг? А так хотелось юникода...


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

кстати IBExpert много чем хорош но бесплатный с юникодом плохо дружит, а FlameRobin попроще - но там вроде все ОК.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 06, 2010, 08:47
Да, думаю вы правы.
Qt Creator исходники создаёт в системной кодировке, а в винде это win1251. Я подумал, что в принципе, в основном разработка идёт в винде, под линуксом, если я и буду что писать для этого проекта, то выбрать кодировку в креаторе недолго. Решение пришло простое и логичное - для этого проекта всё перевести на win1251.
Благодарю всех, кто принял участие в решении моей проблемы. Мой первый опыт, мои первые грабли.
В IBExpert-е есть то ли фича, то ли костыль, если надо юникодные данные править - встроенный юникодный редактор значения поля. Inplace там ансишный, а если ткнуть на комбобокс, то отображается отдельной формой редактор для юникода. Гриды в эксперте отображают юникод вроде бы корректно. Ещё у меня какая-то проблема с ним была, так что я чарсет соединения указывал не utf8, а unicode-fss, но уже не помню, в чём там дело было.


Название: Re: Транзакции Interbase
Отправлено: Tonal от Март 09, 2010, 11:12
Добавил issue 8 (http://code.google.com/p/qtfirebirdibppsqldriver/issues/detail?id=8) в трекер проекта.


Название: Re: Транзакции Interbase
Отправлено: const от Март 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.

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

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

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


Название: Re: Транзакции Interbase
Отправлено: Tonal от Март 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();
 
Заодно и скорость чуть поднимется. :)


Название: Re: Транзакции Interbase
Отправлено: const от Март 12, 2010, 09:13
Цитировать
Вынеси транзакцию за цикл:
Пробовал, не помогает. К тому же дело в том, что этот абсурдный на первый взгляд код лишь демка, на которой я пытался выяснить в моём коде чтото не так или в другом.
Понятно, что кучу однотипных запросов лучше выполнить в одной транзакции. Но в оригинальном коде нужно чтобы каждый запрос именно своей транзакцией писался (там это не повлияет на скорость, запросов не много).
Опять же повторюсь, но
Цитировать
Убирал старт/коммит транзакции  - то же самое.
Я не понимаю почему он ругается на то, что ничего не было подготовлено. Если смотреть перед exec() в отладчике, то там видно, что значения параметров действительно в QQuery заносятся (в values). На момент перед выполнением запроса в поле error у QSqlQuery нет ошибки.


Название: Re: Транзакции Interbase
Отправлено: ax от Март 12, 2010, 11:39
Цитировать
Единственный вариант - это внести препаре в цикл, но тогда это уже не препаре получается.

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

Вопрос в драйвере. Зацепил эту штуку в одном из релизов. Проверил - в драйвере ок.
Хочу сегодня поправить и разобраться с кодировками.
Выложу исправление.


Название: Re: Транзакции Interbase
Отправлено: ax от Март 13, 2010, 15:27
Версия 0.17 Qt SQL driver for Firebird with IBPP library.
http://code.google.com/p/qtfirebirdibppsqldriver (http://code.google.com/p/qtfirebirdibppsqldriver)

Изменения в версии 0.17
+ "make install" will copy driver to [QT_INSTALL_PLUGINS]/sqldrivers
- fixed: character sets exception ( Issue 8 )
    Conversions between Firebird and Qt
      "ASCII" = "IBM 866"
      "BIG_5" = "Big5"
      "CYRL" = "KOI8-R"
      "DOS850" = "IBM 850"
      "DOS866" = "IBM 866"
      "EUCJ_0208" = "JIS X 0208"
      "GB_2312" = "GB18030-0"
      "ISO8859_[1-9, 13]" = "ISO 8859-[1-9, 13]"
      "KSC_5601" = "Big5-HKSCS"
      "SJIS_0208" = "JIS X 0208"
      "UNICODE_FSS" = "UTF-32"
      "UTF8" = "UTF-8"
      "WIN125[0-8]" = "Windows-125[1-8]"
    else use QTextCodec::codecForLocale()

по вопросу с query.prepare, query.bind: будет работать если prepare и цикл bind, exec обернуть транзакцией как в примере у Tonal

Вынеси транзакцию за цикл:
Код
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();
 
Заодно и скорость чуть поднимется. :)

Без транзакции каждый exec будет обернут в неявную транзакцию и комитится, очищая prepare

Вопросы и пожелания сюда и на http://code.google.com/p/qtfirebirdibppsqldriver/issues/list (http://code.google.com/p/qtfirebirdibppsqldriver/issues/list)


Название: Re: Транзакции Interbase
Отправлено: Dimich от Март 13, 2010, 20:18
axax, по моему, для кодировок ASCII, CYRL и UNICODE_FSS не верно указаны кодировки Qt
Могу сослаться на книгу -  Хелен Борри, Firebird - руководство разработчика. Там, в конце книги, указана таблица поддерживаемых Firebird кодировок. Аналогичная таблица приведена в статье "Кодовые страницы Firebird и Interbase"
http://www.ibprovider.com/rus/documentation/charsets_collations.html (http://www.ibprovider.com/rus/documentation/charsets_collations.html)

ASCII - это семибитная кодировка
CYRL - кодировка для совместимости с досовскими версиями Paradox и dBase
UNICODE_FSS - вариант UTF-8

Мой вариант:
ASCII - "ISO 8859-1"
CYRL - "IBM 866"
UNICODE_FSS - "UTF-8"


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Март 13, 2010, 20:33
Dimich, в части первых двух согласен с тобой.
А вот UNICODE_FSS меня смущает, т.к. в FB <=2.0 есть и UTF-8
Может там какие-то нюансы в UNICODE_FSS есть?


Название: Re: Транзакции Interbase
Отправлено: Dimich от Март 15, 2010, 10:12
Начиная с версии 2.0 в Firebird введены новые charset-ы
KOI8-R
KOI8-U
UTF8

В Firebird 1.5.xx UTF8 был всего лишь алиасом UNICODE_FSS
C версии  Firebird 2 UTF8 - новый charset, альтернативная (исправленная) реализация UTF-8

Вольный перевод:
У кодировки UNICODE_FSS много проблем - это старая версия UTF8, которая принимала некорректные строки и не правильно выдавала максимальную длину строки. В FB 1.5.x UTF8 является псевдоним к UNICODE_FSS.
Теперь, UTF8 - новая кодировка, без врожденных проблем UNICODE_FSS.

См: http://www.firebirdsql.org/rlsnotesh/rlsnotes20.html (http://www.firebirdsql.org/rlsnotesh/rlsnotes20.html)

Еще нестыковка:
KSC_5601 - южнокорейская кодировка (современное обозначение KS X 1001)
Big5-HKSCS - китайская кодировкая для диалекта распространенного в Гонконге

Возвращаясь к нашим баранам:
ASCII - "ISO 8859-1"
CYRL - "IBM 866"
UNICODE_FSS - "UTF-8"
UTF8 - "UTF-8"
KOI8-R - "KOI8-R"
KOI8-U - "KOI8-U"
KSC_5601 - ?


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Март 15, 2010, 15:20
>>KSC_5601 - ?
Тут можно пойти таким путём: в Qt основным ключом является код по IANA, а на её сайте можно посмотреть, что же это такое.


Название: Re: Транзакции Interbase
Отправлено: const от Март 17, 2010, 15:32
Цитировать
по вопросу с query.prepare, query.bind: будет работать если prepare и цикл bind, exec обернуть транзакцией как в примере у Tonal
Сразу отличия своего кода от кода Tonal не заметил. Внёс prepare в транзакцию и заработало. спасибо.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 18, 2010, 15:20
Когда делаешь mingw32-make install, в каталог с плагинами копируется только dll, без a-файла.
Неплохо бы поправить это дело, если это вообще реализуемо. Если нет, то тоже ничего страшного. :)
Спасибо.



Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 19, 2010, 15:20
Как я понял, этот драйвер не может QSqlDriver::lastInsertId().
Поделитесь, пожалуйста, кто как решает проблему с Primary Key при добавлении новой записи? У меня первая мысль - дёрнуть селектом генератор, и использовать полученное значение во вставке.
(Обсуждение можно вынести в отдельный топик, т.к. оно только косвенно касается этого драйвера).
Заранее благодарю.


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 19, 2010, 17:02
в программе:
Код:
insert into .... (primary_column) values (null)
А в триггере before insert
пишешь
Код:
if (primary_column is null) then primary_column = gen_id(primary_generator,1)


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Март 19, 2010, 17:11
gigabyte, тут даже вставлять в ПК и не надо, просто вставлять нужные поля нужные данные, а тригер сделает своё дело.


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 19, 2010, 18:53
ну да


Название: Re: Транзакции Interbase
Отправлено: xokc от Март 19, 2010, 19:38
И все-таки, как при этом узнать id последней вставленной записи?


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Март 19, 2010, 19:42
>>id последней вставленной записи?
Например так:

select max(id)
from tablename


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 19, 2010, 20:30
всем спасибо за участие.
я решил кошерным методом - дернул генератор, полученное значение идёт в качестве id новой записи.
насколько я понимаю ситуацию, именно таким методом это работает и в датасетах дельфёвых, с коими я имел (не)счастье иметь дело в начале пути.
А другого пути просто нету. Триггер - это несомненно хорошо, но он не отдаст полученный id, как вы его узнаете?

P.S. Ещё раз вернулся к книжке "Мир Interbase", дабы освежить воспоминания, там тоже говорится, что при использовании триггера значение id узнать невозможно, остается только дёргать генератор. :)

P.P.S. Думаю, на этом данный вопрос можно закрыть.

P.P.P.S. Ага, а вот темы с "The RETURNING Clause" мы тут не вспомнили, хотя вроде в форуме её где-то вскользь касались... А ведь это ещё один способ получить id, хотя он и относится только к Птице 2.1 версии и только к singleton set. Интересно, в QSQlQuery это будет работать? Надо бы проверить...


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 19, 2010, 20:30
>>id последней вставленной записи?
Например так:

select max(id)
from tablename
Так можно делать только если id - простое число, если же этот id формируэтся но некоему алгоритму:
AABBBBCCCC, где АА - номер отдела, BBBB - тип документа, СССС - собственно инкремент
то такой алгоритм не подойдет


Название: Re: Транзакции Interbase
Отправлено: break от Март 19, 2010, 21:48
Цитировать
Так можно делать только если id - простое число, если же этот id формируэтся но некоему алгоритму:
AABBBBCCCC, где АА - номер отдела, BBBB - тип документа, СССС - собственно инкремент
то такой алгоритм не подойдет

То что вы описали не является СУРРОГАТНЫМ ключем - для того чтобы не было головняка при работе с таблицей нужен именно суррогатный ключ!!! Это многие опытные разработчики в своих книгах описывают. То есть если есть серия паспорта - то это не суррогатный ключ и его мы как PK не берем - и пусть формируется по какому угодно алгоритму. А суррогатный пусть формирует БД!

Я для себя завел строгое правило - все таблицы имеют такой PK - как правило поле называется ROW_ID имеет триггер как раз описанный выше. Это также помогает написать универсальное окошко  "справочник" которое при удалении - изменении - создание записей дергает этот ROW_ID.

Теперь на клиенте дергаю генератор через

SELECT GEN_ID( <GeneratorName>, 1 ) FROM RDB$DATABASE;
Цитировать
http://www.firebirdsql.org/manual/generatorguide-sqlsyntax.html

при этом у меня в каждой таблице триггер есть но он не отрабатывает т.к. действительно нам нужен ID записи на клиенте - а если его создаст сервер триггером то мы его не получим до первого селекта (а переоткрывать запрос нехотелось бы), но он нужен для тех случаев когда запись будет вставлять не справочник - а например когда будет пакетный импорт из снешнего источника и ID как раз нужно будет сгенерить...


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Март 19, 2010, 22:15
>>А другого пути просто нету. Триггер - это несомненно хорошо, но он не отдаст полученный id, как вы его узнаете?
есть такой концепт - авто инкремент, класcика для Firebird - это связка Генератор + Тригер.
Выглядит так:
Код
SQL
/* создаём таблицу */
CREATE TABLE ENTITIES
(
 ID Integer NOT NULL,
 PARENT_ID Integer,
 SINGULAR_NAME D_NAME NOT NULL,
 PLURAL_NAME D_NAME,
 CONSTRAINT PK_ENTITIES PRIMARY KEY (ID)
);
/* создаём для неё генератор искусственного ПК */
CREATE GENERATOR GEN_ENTITIES;
 
/* Создаем тригер для вставки в таблицу искусственного ПК */
SET TERM ^ ;
CREATE TRIGGER T_ENTITIES_ID FOR ENTITIES ACTIVE
BEFORE INSERT POSITION 0
AS
BEGIN
 
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(GEN_ENTITIES, 1);
END^
SET TERM ; ^
SET TERM ^ ;
 
Далее в таблицу вставляются значения, но ПК при вставке не используется, им полностью занимается тригер


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 19, 2010, 22:23
Вы наверное меня недопоняли немного... :)
Я говорил о случае, когда клиенту нужно знать pk только что вставленной записи. Триггер её вам не отдаст.
А вот такая штука, как "RETURNING <column_list> [INTO <variable_list>]" в Firebird 2.1 - это уже интересно... Сейчас и проверю.
В общем, всех интересующихся отсылаю к "Firebird_v2.1.3.ReleaseNotes.pdf" :)


Название: Re: Транзакции Interbase
Отправлено: break от Март 19, 2010, 22:58
Я действительно значит недопонял

1) нужно значение только что вставленной записи на клиенте - без переоткрытия набора - делаем SELECT GEN_ID( <GeneratorName>, 1 ) FROM RDB$DATABASE и вставляем уже с этим полученным увеличенным на 1 новым значением генератора - при этом мы его знаем
2) не нужен - просто не указываем в полях для вставки ROW_ID и вставится базой

мне кажется механизм автоинкремента через генератор + before_insert триггер нужен обязательно в БД - создаю его для всех таблиц

Так получается

MY_Table ( таблица с обязательным полем ROW_ID - суррогатным)

MY_TABLE_GEN ( генератор для новых значений ROW_ID )

MY_TABLE_BI ( стандартный триггер Before Insert для вставки нововго значения генератора MY_TABLE_GEN в ROW_ID если текущее NULL)


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 19, 2010, 23:25
Всё это мне было ясно сразу, как Божий день. :)
Так вот, вскрытие показало, что пациент умер от вскрытия... Firebird-овский returning оказался useless на данном этапе его реализации. Запрос отрабатывается, но вытащить значение я не смог, т.к. там ограничение на into :variable, into работает только для psql, а значит, меня жестко побрили.

Итак, я вижу два способа решения проблемы pk на клиенте:
1) вставка через процедуру, которая и будет возвращать нам значение ПК только что вставленной записи.
2) дергать селектом генератор и использовать полученное значение.

Собственно, второй способ у меня и был реализован. Итак, похоже, тема выглядит исчерпанной. Выглядит так, что QSqlQuery ничего не может сделать с "RETURNING", либо это от драйвера зависит и в нём надо допиливать, или это ограничение самой квэри, ну тут уж я не силён, я с Qt совсем недавно...


Название: Re: Транзакции Interbase
Отправлено: MoPDoBoPoT от Март 20, 2010, 00:53
Выглядит так, что QSqlQuery ничего не может сделать с "RETURNING", либо это от драйвера зависит и в нём надо допиливать, или это ограничение самой квэри, ну тут уж я не силён, я с Qt совсем недавно...
Не знаю как в Firebird, но в Oracle конструкция "INSERT INTO <table_name> (column_list) VALUES (values_list) RETURNING <value_name> INTO <variable_name" работает. Если драйвер поддерживает связываемые переменные (подготовленный запрос), то должно работать.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 20, 2010, 10:22
Что ж, за Oracle можно порадоваться... Ну а мы пока имеем:

1. The INTO part (i.e. the variable list) is allowed in PSQL only, for assigning the output set to local variables.
It is rejected in DSQL.
2. The presence of the RETURNING clause causes an INSERT statement to be described by the API as
isc_info_sql_stmt_exec_procedure rather than isc_info_sql_stmt_insert. Existing connectivity
drivers should already be capable of supporting this feature without special alterations.

2axax: твой драйвер "supporting this feature"? Если нет, очень хотелось бы увидеть реализацию. Готов помочь, чем могу. А может, это надо допиливать ibpp? А с другой стороны думаю - если "It is rejected in DSQL", то как вообще получить возвращаемое значение, если нельзя забиндить на переменную? Тупик какой-то...


Название: Re: Транзакции Interbase
Отправлено: Tonal от Март 21, 2010, 16:21
RETURNING оч. правильный вариант, но его должен поддерживать драйвер.
Если используешь qtfirebirdibppsqldriver можно автора попросить допилить. :)


Название: Re: Транзакции Interbase
Отправлено: xokc от Март 21, 2010, 19:44
Если используешь qtfirebirdibppsqldriver можно автора попросить допилить. :)
Так об этом тут последние постов 20 и просят :)


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 22, 2010, 23:33
Попросить автора не сложно, тут загвоздка в другом - в "returning" невозможно забиндить переменные. Получается, драйвер должен распознать такой запрос и обрабатывать его каким-то особым образом, плюс, насколько я могу это представить, биндинг всё-таки должен быть доступен, но драйвер должен уметь транслировать запрос в форму, доступную для dsql, суметь получить возвращённые значения и перетранслировать всё обратно так, чтобы эмулированный биндинг работал. То есть, как я вижу, драйверу придётся эмулировать биндинг.
Ну, может, всё намного проще, и я просто чего-то не знаю или недопонимаю, но мои эксперименты с "returning" меня привели к нулевому результату. С "into" я получаю неподготовленный запрос, без "into" запрос исполняется, но я ничего не получаю обратно, ведь биндинга нету, логично? Вот такие пироги...

P.S. ...Так что пока просто продолжаю дёргать генератор селектом.


Название: Re: Транзакции Interbase
Отправлено: Tonal от Март 23, 2010, 08:35
Вызов INSERT ... RETURNING эквивалентен вызову процедуры.
Собственно, насколько я в курсе, после prepare сервер так флаги и устанавливает.
Так что никаких сильно мудрёных и уникальных телодвижений тут не нужно.
Вопрос только в том, поддерживает это ibpp или нет.
Если нет, придётся его авторов пинать.

П. С. В драйвере к Python это реализовали сразу, как только RETURNING появился. :)


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 23, 2010, 23:23
Вот, я тут написал в мэйл-лист ibpp:

Le 23 mars 2010 à 07:13, Сергей Сарбаш a écrit :
> Hello, All.
>
> I suppose you know about this new feature of the Firebird 2.1 server.
> So, just the question. Has anyone already tried to implement this?
> Thank you.

There is nothing to implement in IBPP to use this nice feature.  I use it everyday.  The server returns the "returning" value just as it would do for a stored procedure returning a single value.  So just Statement->Get(...) after your Execute() and you're done.

The code sample by Borr says it all, too.

Enjoy :)
--
Olivier Mascia

P.S. Как видно из текста, ibpp поддерживает returning. Осталось подкрутить драйвер...


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 24, 2010, 16:22
Посмотрел я сегодня IBPP.
returning он НЕ ПОДДЕРЖИВАЕТ!!!!!


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 24, 2010, 16:44
Значит так, чтобы можно было выполнить такой  запрос:
Код:
INSERT INTO SYS$ACTIONS(ID,CAPTION) VALUES(NULL,'CAPTION') RETURNING ID
и при этом обработать возврат:
Код:
        while(q.next())
            qDebug() << "Value: " << q.value(0);
Я сделал следующее:
Файл В qsqlfirebird qsql_ibpp.cpp:
Код:
bool QFBResultPrivate::isSelect()
{
    bool iss = false;
    try
    {
        iss = (iSt->Type() == IBPP::stSelect) || ((iSt->Type() == IBPP::stExecProcedure) && (iSt->Columns()>0));
    }
    catch (IBPP::Exception& e)
    {
        setError("Unable get type of statement", e, QSqlError::StatementError);
    }
    return iss;
}
Файлы в IBPP 2.5.3.1:
файл _ibpp.h в клаcсе StatementImpl добавить поля:
Код:
        bool mIsSingleResult;
        bool mIsSingleResultDone;
Файл Statement.cpp изменить метод Fetch() вот на это:
Код:
bool StatementImpl::Fetch()
{
        if((mIsSingleResult) && (!mIsSingleResultDone)) {
            IBS status;
            int code = (*gds.Call()->m_dsql_fetch)(status.Self(), &mHandle, 1, mOutRow->Self());
            if (status.Errors())
            {
                    Close();
                    throw SQLExceptionImpl(status, "Statement::Fetch",
                            _("isc_dsql_fetch failed."));
            }
            mIsSingleResultDone = true;
            return true;
        }
        else if ((mIsSingleResultDone) && (mIsSingleResult)) {
            CursorFree();
            mIsSingleResult = false;
            mIsSingleResultDone = false;
            CursorFree();
            return false;
        }

        if (! mResultSetAvailable)
throw LogicExceptionImpl("Statement::Fetch",
_("No statement has been executed or no result set available."));

IBS status;
int code = (*gds.Call()->m_dsql_fetch)(status.Self(), &mHandle, 1, mOutRow->Self());
if (code == 100) // This special code means "no more rows"
{
mResultSetAvailable = false;
// Oddly enough, fetching rows up to the last one seems to open
// an 'implicit' cursor that needs to be closed.
mCursorOpened = true;
CursorFree(); // Free the explicit or implicit cursor/result-set
return false;
}
if (status.Errors())
{
Close();
throw SQLExceptionImpl(status, "Statement::Fetch",
_("isc_dsql_fetch failed."));
}
return true;
}
Файл Statement.cpp изменить метод Execute() вот на это:
Код:
void StatementImpl::Execute(const std::string& sql)
{
if (! sql.empty()) Prepare(sql);

if (mHandle == 0)
throw LogicExceptionImpl("Statement::Execute",
_("No statement has been prepared."));

// Check that a value has been set for each input parameter
if (mInRow != 0 && mInRow->MissingValues())
throw LogicExceptionImpl("Statement::Execute",
_("All parameters must be specified."));

CursorFree(); // Free a previous 'cursor' if any

IBS status;
        if (mType == IBPP::stSelect)
{
// Could return a result set (none, single or multi rows)
(*gds.Call()->m_dsql_execute)(status.Self(), mTransaction->GetHandlePtr(),
&mHandle, 1, mInRow == 0 ? 0 : mInRow->Self());
if (status.Errors())
{
//Close(); Commented because Execute error should not free the statement
std::string context = "Statement::Execute( ";
context.append(mSql).append(" )");
throw SQLExceptionImpl(status, context.c_str(),
_("isc_dsql_execute failed"));
}
if (mOutRow != 0)
{
mResultSetAvailable = true;
mCursorOpened = true;
                        mIsSingleResult = false;
                        mIsSingleResultDone = false;
}
}
        else
            if((mType == IBPP::stExecProcedure) && (mOutRow->Columns() != 0))
        {
            (*gds.Call()->m_dsql_execute)(status.Self(), mTransaction->GetHandlePtr(),
                    &mHandle, 1, mInRow == 0 ? 0 : mInRow->Self());
            if (status.Errors())
            {
                    //Close(); Commented because Execute error should not free the statement
                    std::string context = "Statement::Execute( ";
                    context.append(mSql).append(" )");
                    throw SQLExceptionImpl(status, context.c_str(),
                            _("isc_dsql_execute failed"));
            }
            if (mOutRow != 0)
            {
                mIsSingleResult = true;
                mIsSingleResultDone = false;
            }
        }
        else
{
// Should return at most a single row
                (*gds.Call()->m_dsql_execute2)(status.Self(), mTransaction->GetHandlePtr(),
&mHandle, 1, mInRow == 0 ? 0 : mInRow->Self(),
mOutRow == 0 ? 0 : mOutRow->Self());               
if (status.Errors())
{
//Close(); Commented because Execute error should not free the statement
std::string context = "Statement::Execute( ";
context.append(mSql).append(" )");
throw SQLExceptionImpl(status, context.c_str(),
_("isc_dsql_execute2 failed"));
}
}
}
Проверял шас сижу, проверяю вроде ничего не поламалось, select-ы работают, insert-ы тоже
через isql пробовал сделать returning нескольких строк но получил multiple rows in singleton select  (Пример из документации Firebird 2.1: delete from sys$accounts returning id;) так что дальше в плане возвраoения многих строк я не копал.


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 24, 2010, 16:49
There is nothing to implement in IBPP to use this nice feature.  I use it everyday.  The server returns the "returning" value just as it would do for a stored procedure returning a single value.  So just Statement->Get(...) after your Execute() and you're done.

Мдас в сторону Statements->Get() также не копал кому надо будет посмотрите


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 24, 2010, 18:19
А нужно ли было так всё усложнять? Вот то, что мне ответили ранее:

"std::string sql = "INSERT INTO Main (Name)"
                            " Values(\'? ? ?\') RETURNING ID";
        st->Prepare(sql.c_str());
        st->Execute();
        st->Get(1, DocInf.ID);
        tr->Commit();//Commit (здесь было много вопросительных знаков - у автора проблема с кодировкой) ID

I'm sorry but with English I have a problem"

Насколько я понимаю, достаточно где-то что-то подправить в драйвере, не трогая ibpp, т.к. проблема не с ним, что мне продемонстрировали этим примером, да и сам автор ведь написал понятно - он пользует RETURNING постоянно.


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 24, 2010, 18:23
Вот именно где-то что-то а оно бы вилилось в много всякого. а так получилось чуть чуть и везде  :)
Ну просто мне так легче было исправить. Ваше желание принимать или нет


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 24, 2010, 18:31
Ничего не имею против ваших корректировок, не подумайте. :)
однако, осмелюсь заметить, что если где-то что-то нужное и правильно подпилить, то это никак не повредит делу и не выльется в что-то трагическое, а как раз наоборот, будет багфикс.
Ладно, простите меня великодушно за пустую демагогию, кто бы подарил мне немного времени покопаться во внутренностях драйвера... :(


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 24, 2010, 22:12
А нужно ли было так всё усложнять? Вот то, что мне ответили ранее:

"std::string sql = "INSERT INTO Main (Name)"
                            " Values(\'? ? ?\') RETURNING ID";
        st->Prepare(sql.c_str());
        st->Execute();
        st->Get(1, DocInf.ID);
        tr->Commit();//Commit (здесь было много вопросительных знаков - у автора проблема с кодировкой) ID

I'm sorry but with English I have a problem"
Шото мне этот пример не нравится Вы его сами пробовали?
Я шас чутьчуть посидел вместо st->Get(1, DocInf.ID); поставил IsNull - так он true показывает а это как понимаэте не то что надо.
        rp->iSt->Get(1,i);
        qDebug() << i;
выписывает совсем левые данные
Если сделать st->Fetch() тоже не получится так как там по коду throw exception рисуется.
Может случайно примерчик не полный? Или все таки IBPP


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 25, 2010, 00:08
Как я понял, это неполный примерчик с использованием ibpp. Кстати, там должно быть в запросе что-то типа
"INSERT INTO Main (Name) Values(\'Боря, у которого траблы с кодировками в мыле\') RETURNING ID;"
У товарища вопросы вместо русских символов, как я понял.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 26, 2010, 13:58
Шото мне этот пример не нравится Вы его сами пробовали?
Я шас чутьчуть посидел вместо st->Get(1, DocInf.ID); поставил IsNull - так он true показывает а это как понимаэте не то что надо.
        rp->iSt->Get(1,i);
        qDebug() << i;
выписывает совсем левые данные
Если сделать st->Fetch() тоже не получится так как там по коду throw exception рисуется.
Может случайно примерчик не полный? Или все таки IBPP

Из принципа попробовал:
test.cpp
Код:
int main(int argc, char *argv[])
{
    IBPP::Database db1;
    db1 = IBPP::DatabaseFactory("localhost", "D:\\projects\\test\\realtyad.fdb", "sysdba", "masterkey");
    db1->Connect();
    IBPP::Transaction tr1 = IBPP::TransactionFactory(db1,
                            IBPP::amWrite, IBPP::ilConcurrency, IBPP::lrWait);
    tr1->Start();
    IBPP::Statement st1 = IBPP::StatementFactory(db1, tr1);
    st1->Execute("insert into R (NAME, PHONE1) values ('John Doe', '58-29-58') returning ID");
    tr1->Commit();

    int test_id;
    st1->Get(1, test_id);
    std::cout << "returned id is " << test_id << std::endl;
    db1->Disconnect();
    return 0;
}

Так вот. Всё работает. ID возвращает исправно, проверял IBExpert-ом возвращаемые значения - не врёт, однако. Что будем делать? В перспективе релиза 3.0 IBPP не думаю, что это будет разумным, трогать IBPP, логичней допилить драйвер для нормальной работы с RETURNING.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 26, 2010, 15:37
Итак, результат моих родовых мук.
Прилагаю патч, для того, чтобы можно было брать возвращаемое RETURNING значение из синглтона.
Сразу предупреждаю - реализация сделана согласно доки птицевской, то бишь, RETURNING рассчитан на синглтон и никак иначе.
Пробуйте, проверяйте, тестируйте, ругайте, высказывайте замечания, шлите патчи. ;)

2gigabyte: это ничего, что реализацию ::isSelect() я просто скопировал из твоего поста? ;)

2axax: патчил, глядя на qsql_ibase.cpp, почти скопипастил логику. Если всё будет ок - можно закомитить в репозиторий.

Всем удачи и хорошего настроения! :)

P.S. Немного патч подправил, почти незаметно.


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 26, 2010, 16:20
Итак, результат моих родовых мук.
Прилагаю патч, для того, чтобы можно было брать возвращаемое RETURNING значение из синглтона.
Сразу предупреждаю - реализация сделана согласно доки птицевской, то бишь, RETURNING рассчитан на синглтон и никак иначе.
Пробуйте, проверяйте, тестируйте, ругайте, высказывайте замечания, шлите патчи. ;)

2gigabyte: это ничего, что реализацию ::isSelect() я просто скопировал из твоего поста? ;)

2axax: патчил, глядя на qsql_ibase.cpp, почти скопипастил логику. Если всё будет ок - можно закомитить в репозиторий.

Всем удачи и хорошего настроения! :)

P.S. Немного патч подправил, почти незаметно.

Вечером попробую. а ты сам его уже пробовал?


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 26, 2010, 16:41
Вечером попробую. а ты сам его уже пробовал?
:)))
Это банально, но мой ответ очень предсказуем: "У меня всё работает." :)
Я решил, что не стоит трогать IBPP, и внёс изменения в код драйвера. Я сделал по тому же принципу, как это реализовано в драйвере QIBASE, который в комплекте с SDK идёт. Единственное сомнение у меня по поводу процедур... Если верить написанному:
Код:
bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
{
    ISC_STATUS stat = 0;

    // Stored Procedures are special - they populate our d->sqlda when executing,
    // so we don't have to call isc_dsql_fetch
    if (d->queryType == isc_info_sql_stmt_exec_procedure) {
        // the first "fetch" shall succeed, all consecutive ones will fail since
        // we only have one row to fetch for stored procedures
то проблем быть не должно, а как оно на практике будет, тут я не могу ничего сказать...

P.S. Ещё раз перечитал главу о хранимых процедурах из "Мир Interbase" и понял - "всё правильно сделал!"
Так оно и должно работать.


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 26, 2010, 17:25
Цитировать
Это банально, но мой ответ очень предсказуем: "У меня всё работает."
У меня не пошло  :(
А конкретно дошло зашло в
Код:
        if (rp->iSt->IsNull(i))
        {
            // null value
            QVariant v;
            v.convert(qIBPPTypeName(rp->iSt->ColumnType(i)));
            row[idx] = v;
            continue;
        }
и соответственно выдало пустой вариант в qDebug()
Код:
Value:  QVariant(, )
Проверял следующим образом:
Код:
        QSqlQuery q("INSERT INTO SYS$ACTIONS(ID,CAPTION) VALUES(NULL,'CAPTION') RETURNING ID",db);
        while(q.next())
            qDebug() << "Value: " << q.value(0);


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 26, 2010, 17:41
А что за база? большая? (намекаю на поделиться для теста)
А поле точно автоинкрементное?
А что за версия ibpp? я использую 2.5.3.1
Firebird точно >=2.1?


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 26, 2010, 17:50
Предлагаю для верности эксперимента зааттачить тестовую базу, на которой и будем мучить RETURNING. Если у нас обоих не пойдёт - значит явно глюк, а так невозможно выяснить, в чём дело. У меня всё нормально заработало с пропатченным драйвером.
На всякий случай вот нормальные фрагменты, не diff-ом:
Код:
строки 681-697

    bool stat = true;

    if (IBPP::stExecProcedure == rp->iSt->Type())
    {
    if (0 != rowIdx)
    stat = false;
    }
    else
        try
        {
            stat = rp->iSt->Fetch();
        }
        catch (IBPP::Exception& e)
        {
            rp->setError("Could not fetch next item", e, QSqlError::StatementError);
            return false;
        }

строка 410

        iss = (iSt->Type() == IBPP::stSelect || (iSt->Type() == IBPP::stExecProcedure && 0 < iSt->Columns()));


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 26, 2010, 19:02
diff у меня сел нормально
аттачу table.sql для генерации таблицы с триггерами
проверрять я буду так:
Код:
        QSqlQuery q("INSERT INTO SYS$ACTIONS(ID,CAPTION) VALUES(NULL,'CAPTION') RETURNING ID",db);
        QSqlQuery q("SELECT ID FROM SYS$ACTIONS",db);
        while(q.next())
            qDebug() << "Value: " << q.value(0);
1.  собсно для проыверки работы
2.  для проверки того не на@бнулось ли что-то


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 26, 2010, 21:31
"SYS$UIDGENERATOR" - это где брать?

/*******************************************************************************
The next statement causes the following error:

Undefined name.
Dynamic SQL Error.
SQL error code = -204.
Procedure unknown.
SYS$UIDGENERATOR.
*******************************************************************************/
CREATE OR ALTER TRIGGER SYS$ACTIONS_BI FOR SYS$ACTIONS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
    IF ((NEW.ID IS NULL) OR (NEW.ID = 0)) THEN
        EXECUTE PROCEDURE SYS$UIDGENERATOR 'SYS$ACTIONS' RETURNING_VALUES NEW.ID;
END;


З.Ы. Зачем всё так сложно?... у меня ПК генерится обычным триггером перед вставкой обычным генератором с помощью GEN_ID().


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 26, 2010, 21:42
sys$uidgenerator
Код:
SET TERM ^ ;

CREATE OR ALTER PROCEDURE SYS$UIDGENERATOR (
    UIDNAME VARCHAR(40))
RETURNS (
    UID BIGINT)
AS
DECLARE VARIABLE TEMPUID BIGINT;
begin
  SELECT VAL FROM SYS$UIDS WHERE ID = :UIDNAME INTO :TEMPUID;
  UPDATE SYS$UIDS SET VAL = :TEMPUID + 1  WHERE ID = :UIDNAME;
  UID = :TEMPUID;
  SUSPEND;
end^

SET TERM ; ^

GRANT SELECT,UPDATE ON SYS$UIDS TO PROCEDURE SYS$UIDGENERATOR;

GRANT EXECUTE ON PROCEDURE SYS$UIDGENERATOR TO SYSDBA;
Таблица SYS$UIDS:
Код:
CREATE TABLE SYS$UIDS (
    ID   VARCHAR(40),
    VAL  BIGINT DEFAULT 0 NOT NULL
);


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 26, 2010, 22:08
И что, стесняюсь спросить, лежит в SYS$UIDS до того, как процедура туда сунется? там же пусто изначально...
Всё же мне не понятно - зачем всё так усложнять?

P.S. А чем не устраивает такая банальность, как

Код:
as
begin
  if (new.id is null) then
    new.id = gen_id(gen_r_id,1);
end

??? К чему весь этот изврат?


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 26, 2010, 22:19
Эту логику я скопировал из одного очень хорошего приложения видимо ее автор имел очень веские причины чтоб так написать,а в той таблице 2 пола название и значени.
Одним словом изврат извртом а сделал через простоц генератор потому что итак не пошло на том ще месте остановилось IsNull - true и пустой QVariant


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 26, 2010, 22:31
автор, видать, большой извращенец... хотя, куда там мне, со свиным рылом да в калашный ряд...
А подумать, прежде чем тупо копировать что-то откуда-то, нужно ли оно так?
У тебя проблемы в базе, ты попробуй в эксперте запрос сделать и посмотри, работает оно там или нет? у меня вот ничего не идёт с твоим скриптом, одни проблемы. То базу вручную создавай, то таблицы не все, то процедуру ты не дал. Сдается мне, драйвер тут вообще ни при чём. Вот сам подумай, что брать из пустой SYS$UIDS? NULL и получишь.
В общем, народ, что, больше никому не нужен этот RETURNING? Подожду отзывов от других.
И на тест надо было брать 100%-работающий пример, а ты взял какой-то глюк, который и сам не тестил у себя, и мне даёшь.
Несерьёзно как-то, извини...


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 26, 2010, 22:37
Это ты канечно извини не хотелось переходить на личности, то если у тебя не хватает опыта протитать тот триггер и соответственно добавить одну недостающую запись в таблицу. То тогда есессно ты мены извини. Я к стати только что проповал на простом генераторе проделать то же самоэ. НЕ ИДЕТ
Код:
/******************************************************************************/
/***               Generated by IBExpert 26.03.2010 21:36:59                ***/
/******************************************************************************/

SET SQL DIALECT 3;

SET NAMES NONE;



/******************************************************************************/
/***                                 Tables                                 ***/
/******************************************************************************/


CREATE GENERATOR GEN_REPORTS_ID;

CREATE TABLE REPORTS (
    REPORTID      INTEGER NOT NULL,
    REPORTNAME    INTEGER,
    REPORTSOURCE  VARCHAR(255),
    REPORTBODY    BLOB SUB_TYPE 1 SEGMENT SIZE 16384,
    REPORTPARAMS  VARCHAR(255)
);




/******************************************************************************/
/***                                Triggers                                ***/
/******************************************************************************/


SET TERM ^ ;


/******************************************************************************/
/***                          Triggers for tables                           ***/
/******************************************************************************/



/* Trigger: REPORTS_BI */
CREATE OR ALTER TRIGGER REPORTS_BI FOR REPORTS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
  IF (NEW.REPORTID IS NULL) THEN
    NEW.REPORTID = GEN_ID(GEN_REPORTS_ID,1);
END
^


SET TERM ; ^



/******************************************************************************/
/***                               Privileges                               ***/
/******************************************************************************/

Так ты вроде хотел?

Может ты свой код скинеш и пример для теста?


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 26, 2010, 22:55
Так же спешу уведомить что вобравши ваш пример без использования QtFirebirdsql а именно:
Код:
#include "core/ibpp.h"
#include <iostream>
#include <string>
int main(int argc, char *argv[])
{
    IBPP::Database db1;
    db1 = IBPP::DatabaseFactory("localhost", "D:\\bookstore.fdb", "sysdba", "masterkey");
    db1->Connect();
    IBPP::Transaction tr1 = IBPP::TransactionFactory(db1,
                            IBPP::amWrite, IBPP::ilConcurrency, IBPP::lrWait);
    tr1->Start();
    IBPP::Statement st1 = IBPP::StatementFactory(db1, tr1);
    st1->Execute("INSERT INTO REPORTS(REPORTID,REPORTNAME) VALUES(NULL,11) RETURNING REPORTID");
    tr1->Commit();

    int test_id = -1024;
    st1->Get(1, test_id);
    std::cout << "returned id is " << test_id << std::endl;
    db1->Disconnect();
    return 0;
}
немного подкоректировав значение test_id провел опыт !!!!! С ИСПОЛЬЗОВАНИЕМ ПРОСТЫХ ГЕНЕРАТОРОВ !!!! и в ответ получил есессно результат -1024. который был - неправильным.
И еще меня бы очень интересовало на чем пишите у меня к примеру :
Qt 4.6.0+mingw 4.4.0+Firebird 2.1


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 26, 2010, 23:31
Вы в IBPP не вносили изменений, случаем? А драйвер патченный пересобирали? А не забыли его скопировать в $$[QT_INSTALL_PLUGINS]/sqldrivers? И зачем вставляете NULL в REPORTID?

У меня всё работает!!! И ваш последний пример с "CREATE TABLE REPORTS" работает!
Не знаю, что я делаю не так, но у меня всё работает...
Всё, жду отзывов от других.

P.S. Приаттачил работающий пример. Разбирайтесь в своей консерватории, что там у вас не так. :)
Чуть подчистил аттач.
В строке db.setDatabaseName("TEST.FDB"); укажите полный путь к базе, где она у вас будет, иначе не приконнектится.


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 26, 2010, 23:42
Цитировать
И зачем вставляете NULL в REPORTID?

Вообще-то без разницы вставляю я туда нул или система его вставляет по умолчанию если я опускаю этот параметр.
Не катит оно.
Ладно раз вы ждете откликов от других то не буду вам мешать.
Но этот патч не работает по крайней мере у меня и проблема там именно в IBPP


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 27, 2010, 01:25
Цитировать
И зачем вставляете NULL в REPORTID?

Вообще-то без разницы вставляю я туда нул или система его вставляет по умолчанию если я опускаю этот параметр.
Согласен абсолютно. Из принципа в insert-е передал NULL и получил на выходе реальный ПК.
У вас какой-то неправильный IBPP... Вы мне совершенно не мешаете, зря вы так думаете. Просто хотелось услышать, как у других патч прижился...
Я использовал последний архив ibpp с сайта, а именно "ibpp-2-5-3-1-src.zip" и последнюю ревизию драйвера из свн гуглокода.
В исходники IBPP никаких изменений не вносилось, правки касались только одного файла драйвера - "qsql_ibpp.cpp".
В последнем аттаче я прикрепил работающий пример, которым я проверял, всё ли в порядке. Как ни странно, всё нормально у меня работает...


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 27, 2010, 09:07
Я сприциально вчера пересобрал из старого архива ibpp-2-5-3-1-src.zip (размер 152.882 байт) начисто все. Результат тотже, шас попробую скачать свежий с их сайта может они что-то там подправили а меня в извесность не поставили :)


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 27, 2010, 10:54
Ничего не понимаю... у меня такой же IBPP.
Драйвер QFIREBIRD: чекаут от March 13, 2010: 0.17
Qt: qt-sdk-win-opensource-2010.01.exe
MinGW к нему отдельно не прикручивал, всё использую из комплекта.
Firebird: 2.1.3  (Windows Build) (Firebird-2.1.3.18185_0_Win32.exe)
WinXP Prof SP2 Russian.

P.S. Кстати, вы перед пересборкой qsqlfirebird, mingw32-make clean делаете? Я в общем, ничего не понимаю, в чём может быть проблема... Версия Firebird?


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 27, 2010, 11:14
make clean
delete
fsck
format
:)
Все перепробовал


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 27, 2010, 18:53
Добавил issue, если вдруг случайно кого-нибудь заинтересует функционал...
issue 9 (http://code.google.com/p/qtfirebirdibppsqldriver/issues/detail?id=9)

(Что-то я не разобрался, как настройки issue поменять.)


Название: Re: Транзакции Interbase
Отправлено: Tonal от Март 30, 2010, 08:29
Эту логику я скопировал из одного очень хорошего приложения видимо ее автор имел очень веские причины чтоб так написать,а в той таблице 2 пола название и значени.
А ты в курсе, что приведённая тобой процедура при одновременном вызове из параллельных транзакций будет генерить одинаковые номера?
Или это так и задумывается? :)


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 30, 2010, 09:03
Когда
Эту логику я скопировал из одного очень хорошего приложения видимо ее автор имел очень веские причины чтоб так написать,а в той таблице 2 пола название и значени.
А ты в курсе, что приведённая тобой процедура при одновременном вызове из параллельных транзакций будет генерить одинаковые номера?
Или это так и задумывается? :)
Когда до этого дойдет - подправлю. А пока для тестов сойдет


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 30, 2010, 09:20
Когда
Эту логику я скопировал из одного очень хорошего приложения видимо ее автор имел очень веские причины чтоб так написать,а в той таблице 2 пола название и значени.
А ты в курсе, что приведённая тобой процедура при одновременном вызове из параллельных транзакций будет генерить одинаковые номера?
Или это так и задумывается? :)

Да к стати конкретнее можно на примере как это оно даст одинаковый номер а то я чото запускаю паралельно 2 трансакции а они - собаки этакие ЖДУТ одна другую и пока я не закомичу предыдущую другая данные не получает. :) А после комита есессно - появляются правильные циферки.


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Март 30, 2010, 10:42
>>а они - собаки этакие ЖДУТ одна другую и пока я не закомичу предыдущую другая данные не получает
Загадка:
Куча народу зависла в очередь в кассы, т.к. одна из касирш не завершила транзакцию ( неважно почему) и пошла на горшок.
Вопрос, что будет программеру, который выбрал такой режим транзакций?

:)


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 30, 2010, 11:49
А нифига не будет потому что в реальной ситуации эта трансакция отработает за доли секунды и нихто этого не заметит


Название: Re: Транзакции Interbase
Отправлено: Tonal от Март 30, 2010, 19:48
Не ждут - просто выполняются последовательно.
При параллельном выполнении все, кроме первой получат отлуп.

Ну и сценарий весьма прост:
 1. Одновременно стартуют 2 транзакции.
 2. Обе выполняют первый селект
  SELECT VAL FROM SYS$UIDS WHERE ID = :UIDNAME INTO :TEMPUID;
и получают одно и тоже число.
 3. Первая выполняет
  UPDATE SYS$UIDS SET VAL = :TEMPUID + 1  WHERE ID = :UIDNAME;
вторая на этом обламывается.

Для того, чтобы увидеть, нужно просто запустить одновременно несколько клиентов с разных машин. Или на одной с несколькими процессорами/ядрами.
Клиентам достаточно просто в цикле звать эту процедуру.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Март 31, 2010, 10:30
Короче, генераторы рулят.
Никто мой патч не проверял, кроме gigabyte?


Название: Re: Транзакции Interbase
Отправлено: gigabyte от Март 31, 2010, 12:44
Видимо нет :(


Название: Re: Транзакции Interbase
Отправлено: sarbash от Апрель 01, 2010, 15:46
Предлагаю рассмотреть необходимость и возможность реализации именованных транзакций.
Это пожелание.


Название: Re: Транзакции Interbase
Отправлено: sne от Май 19, 2010, 13:59
axax, прежде всего хочу выразить благодарность за хорошее рабочее решение :)
Далее, хотел бы спросить, при открытии несуществующей БД, qtfirebirdibppsqldriver успешно меня обламывает даже не пытаясь создать новую БД.
Хотелось бы увидеть поведение подобное sqlite плагину, который создает новую БД.

Что-то вроде:
Код:
        dp->iDb->Connect();
    }
    catch (IBPP::Exception& e)
    {
        if (db.indexOf(QRegExp(QLatin1String("[\\\\/]"))) != -1
            && !QFile::exists(db)) {
            // possibly file path
            try {
                dp->iDb->Create(3);
                dp->iDb->Connect();

                setOpen(true);
                return true;
            }
            catch (IBPP::Exception& e) {
                setOpenError(true);
                dp->setError("Unable to create and connect", e, QSqlError::ConnectionError);
                return false;
            }
        }

        setOpenError(true);
        dp->setError("Unable to connect", e, QSqlError::ConnectionError);
        return false;
    }

Очень надеюсь на ответ, будет-ли введен пордобный функционал в следующие версии и/или есть какой другой способ создания несуществующего файла БД?


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Май 19, 2010, 14:17
>>Хотелось бы увидеть поведение подобное sqlite плагину, который создает новую БД.
это особенность самого SQLite, драйвер тут не причём.


Название: Re: Транзакции Interbase
Отправлено: sne от Май 19, 2010, 15:25
lit-uriy, я понимаю, но иначе БД не создать впринципе. Не подключать же ibpp к своему проекту еще раз, если используешь плагин уже  сним :)

Если есть иные варианты создания базы, помимо ее восстановления из бэкапа, внимательно слушаю.


Название: Re: Транзакции Interbase
Отправлено: crossly от Май 19, 2010, 15:37
люди издревле используют isql


Название: Re: Транзакции Interbase
Отправлено: sne от Май 19, 2010, 16:19
люди издревле используют isql
Этот способ немногим лучше gbak, т.к. предполагает поиск всех запущеных IB серверов (а их может быть не один), определение путей и вызов с перенаправлением потока ввода/вывода...


Название: Re: Транзакции Interbase
Отправлено: const от Май 25, 2010, 09:47
Хотел спросить про создание базы, но sne меня опередил. :) . Теперь по существу.
В таблицу базы:
Код:
CREATE TABLE Journal
( IDX INTEGER NOT NULL PRIMARY KEY,
  DTTM TIMESTAMP NOT NULL,
  WHOSEND VARCHAR(10) NOT NULL,
  NAME VARCHAR(50) NOT NULL,
  MESS VARCHAR(50) NOT NULL);

В своей проге пишу данные таким запросом:
Код:
"INSERT INTO Journal (DTTM,WHOSEND,NAME,MESS) VALUES ('NOW',:WHOSEND,:NAME,:MESSAGE)"
Всё нормально записывается.

Потом читаю
Код:
"select DTTM, WHOSEND, NAME, MESS from JOURNAL ORDER BY IDX ASC"

При выполнении
Код:
query.value(0).toDateTime().toString("dd.MM.yy hh:mm:ss")
Он дату читает правильно, а с временем творится какая то фигня.
В большинстве случаев он возвращает 00:00:00 (ну то есть например "25.05.10 00:00:00"). Но иногда (1/50 записей, случайно) он возвращяет правильное время.
При этом если базу открыть EMS Sql manager-ом и принудительно из него поменять какое-нибудь поле дата-время, то в программе оно прочитается правильно (проверяли опытным путём вместе со sne).
Подскажите в какую стророну копать, а то уже замучался... Моя прога? QT? firebirdsqlibppdriver? Firebird?


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Май 25, 2010, 11:40
const, ну а в БД пишется правильно? что реально записывается?
попробуй с помощью демки sqlbrowser, записать/прочитать


Название: Re: Транзакции Interbase
Отправлено: const от Май 26, 2010, 16:21
значение времени в базу формирует сам сервер (см. запрос.), при этом если базу открыть EMS SQL Manager-ом то читаются корректно И дата, И время. А в моей программе время нулями...


Название: Re: Транзакции Interbase
Отправлено: const от Июнь 30, 2010, 11:19
Мда, вопрос про время так и висит открытым. Толи люди все в отпусках (везёт :-( ) толи просто не знает никто, толи пишу не туда.


Название: Re: Транзакции Interbase
Отправлено: arial от Июнь 30, 2010, 11:24
На гуглокод напиши.


Название: Re: Транзакции Interbase
Отправлено: varkon от Июль 06, 2010, 17:04
Подскажите пожалуйста в чем моя ошибка. Скачал файлы проекта и фалы ibpp, как и написано в ридми - добавил папку core в папку соотвествующей версии  - в данном случае  - ibpp2531, добавил в файл ibpp.pri
Код:
HEADERS += $$PWD/core/ibpp.h \
    $$PWD/core/ibpp.h \
    $$PWD/core/iberror.h \
    $$PWD/core/ibase.h \
    $$PWD/core/_ibpp.h \
    $$PWD/core/ibpp.h \
    $$PWD/core/iberror.h \
    $$PWD/core/ibase.h \
    $$PWD/core/_ibpp.h \
    $$PWD/core/ibpp.h \
    $$PWD/core/iberror.h \
    $$PWD/core/ibase.h \
    $$PWD/core/_ibpp.h
SOURCES += $$PWD/core/all_in_one.cpp \
    $$PWD/core/transaction.cpp \
    $$PWD/core/time.cpp \
    $$PWD/core/statement.cpp \
    $$PWD/core/service.cpp \
    $$PWD/core/row.cpp \
    $$PWD/core/exception.cpp \
    $$PWD/core/events.cpp \
    $$PWD/core/dbkey.cpp \
    $$PWD/core/date.cpp \
    $$PWD/core/database.cpp \
    $$PWD/core/blob.cpp \
    $$PWD/core/array.cpp \
    $$PWD/core/all_in_one.cpp \
    $$PWD/core/_tpb.cpp \
    $$PWD/core/_spb.cpp \
    $$PWD/core/_rb.cpp \
    $$PWD/core/_ibs.cpp \
    $$PWD/core/_ibpp.cpp \
    $$PWD/core/_dpb.cpp \
    $$PWD/core/user.cpp

выполнил qmake, пытаюсь собрать проект - получаю кучу предупреждений
Цитировать
build/debug/all_in_one.o:e:/qt/2010.02.1/mingw/bin/../lib/gcc/mingw32/4.4.0/include/c++/exception:62: multiple definition of `ibpp_internals::GDS::Call()'
build/debug/all_in_one.o:e:/qt/2010.02.1/mingw/bin/../lib/gcc/mingw32/4.4.0/include/c++/new:101: first defined here
...
и ошибок:
Код:
build/debug/all_in_one.o:all_in_one.cpp::-1: error: multiple definition of `ibpp_internals::DPB::BUFFERINCR'

что я делаю не правильно?


Название: Re: Транзакции Interbase
Отправлено: arial от Июль 07, 2010, 06:48
В ibpp.pri ничего добавлять не надо.


Название: Re: Транзакции Interbase
Отправлено: varkon от Июль 07, 2010, 07:11
В ibpp.pri ничего добавлять не надо.
Ну может быть.
В принципе разобрался в чем причина. В ридми прописано:
Цитировать
2. Copy IBPP source code to project/ibpp* dir,
На самом деле надо копировать не все - в директории сорцов ibpp лежит файл howtobuild - в которым черным по белому написано:
Цитировать
All the other code files (*.cpp) of the 'ibpp/core' folder must be compiled and
linked with your application as if they were original portions of your
application, except the file 'all_in_one.cpp'.
Т.е. надо либо все файлы, кроме "все в одном", либо только его. Я остановился на первом варианте, хотя может и второй удобнее. Ну и не забыть убрать цели сборки all_in_one из всех остальных файлов.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Июль 07, 2010, 08:43
Я тупо распаковал архив "ibpp-2-5-3-1-src.zip" в "..\qtfirebirdibppsqldriver-read-only\AxQtFbIbppSqlDriver\ibpp2531\" и собрал драйвер. Никаких дополнительных телодвижений не потребовалось. Да, еще либу от сервера положил в "\lib" (fbclient.lib).

P.S. Инструкция по сборке в "README.txt" драйвера, чтиво из "ibpp-2-5-3-1-src.zip" не нужно для сборки драйвера.


Название: Re: Транзакции Interbase
Отправлено: varkon от Июль 09, 2010, 09:43
Я тупо распаковал архив "ibpp-2-5-3-1-src.zip" в "..\qtfirebirdibppsqldriver-read-only\AxQtFbIbppSqlDriver\ibpp2531\" и собрал драйвер. Никаких дополнительных телодвижений не потребовалось. Да, еще либу от сервера положил в "\lib" (fbclient.lib).

P.S. Инструкция по сборке в "README.txt" драйвера, чтиво из "ibpp-2-5-3-1-src.zip" не нужно для сборки драйвера.

Я так сделал под Linux - все собралось нормально. Единственное - в файле _ibpp.h
мне пришлось добавить один инклад:
Код:
#include <cstring>


Название: Re: Транзакции Interbase
Отправлено: sarbash от Июль 13, 2010, 16:16
Тот Патч http://code.google.com/p/qtfirebirdibppsqldriver/issues/detail?id=9 (http://code.google.com/p/qtfirebirdibppsqldriver/issues/detail?id=9), что я выкладывал, в общем, он глючный и пользоваться им не следует. Надеюсь, кроме меня никто не успел его попользовать, но на всякий случай решил отметить.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Июль 13, 2010, 21:13
В догонку к предыдущему сообщению.
В справке написано, что QIBASE поддерживает возвращаемое значение от ХП. Неплохо было бы допилить и этот драйвер... Моя попытка оказалась не удачной, может кому больше повезёт? Функционал, вообще-то, очень нужный. Да и тот же RETURNING тогда бы работал. У кого какие соображения по этому поводу? В списке рассылки по ibpp мне ответили, что данный функционал поддерживается, а здесь мне только SELECT-ом удалось получить значение от процедуры...


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Июль 13, 2010, 22:51
>>а здесь мне только SELECT-ом удалось получить значение от процедуры...
А процедура какая была, процедура выбора или выполняемая процедура?


Название: Re: Транзакции Interbase
Отправлено: varkon от Июль 14, 2010, 03:27
В догонку к предыдущему сообщению.
В справке написано, что QIBASE поддерживает возвращаемое значение от ХП. Неплохо было бы допилить и этот драйвер... Моя попытка оказалась не удачной, может кому больше повезёт? Функционал, вообще-то, очень нужный. Да и тот же RETURNING тогда бы работал. У кого какие соображения по этому поводу? В списке рассылки по ibpp мне ответили, что данный функционал поддерживается, а здесь мне только SELECT-ом удалось получить значение от процедуры...

вероятно в процедуре у тебя присутствует suspend. Именно поэтому работает только select для получения возвращаемого значения. Это нормально. :) 


Название: Re: Транзакции Interbase
Отправлено: sarbash от Июль 14, 2010, 07:18
вероятно в процедуре у тебя присутствует suspend. Именно поэтому работает только select для получения возвращаемого значения. Это нормально. :) 
Ага! Точно! Так и есть. Процедуры я делал в "Эксперте", там в шаблоне по-умолчанию suspend стоит. Похоже, я плохо с ними разобрался... Прошу прощения, ушёл учить матчасть...


Название: Re: Транзакции Interbase
Отправлено: sarbash от Июль 14, 2010, 13:34
>>а здесь мне только SELECT-ом удалось получить значение от процедуры...
А процедура какая была, процедура выбора или выполняемая процедура?
Из селективной процедуры вроде бы значение можно получить, а вот из исполняемой пока мне значение выудить не удалось. :(
Не понимаю, что делать?.. Остается только все делать селективными и селектами брать значения. Хотя, теоретически, исполняемая должна же синглтон хотя бы возвращать, или на бумаге одно, а на практике как повезёт? Кому-нибудь удалось вообще получить возвращаемые значения из исполняемых процедур или это я один такой счастливчик?

Код:
q.exec("execute procedure GET_AGENCY_NAME")
...
q.first();
qDebug() << q.value(0);

Вывод:
QSqlQuery::value: not positioned on a valid record
QVariant(, )


SOS.


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Июль 14, 2010, 21:05
я через ODBC-драйвер делал execute procedure, всё как в аптеке работало.
А через QIBASE не пробовал, сейчас того исходника нет, чтобы быстро проверить.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Июль 15, 2010, 00:12
Меня больше интересует, как получить возвращаемое значение в драйвере, обсуждаемом в топике? То, что написано в справке про QIBASE имеет очень косвенное отношение к QFIREBIRD. Понятно, что там возвращаемое значение извлекается, как если бы это был набор данных, но как это реализовано здесь и реализовано ли вообще?
Подразумеваю "EXECUTE PROCEDURE proc_name" с возвращаемыми значениями. Или кроме меня никто это не использует?


Название: Re: Транзакции Interbase
Отправлено: varkon от Июль 15, 2010, 07:23
Меня больше интересует, как получить возвращаемое значение в драйвере, обсуждаемом в топике? То, что написано в справке про QIBASE имеет очень косвенное отношение к QFIREBIRD. Понятно, что там возвращаемое значение извлекается, как если бы это был набор данных, но как это реализовано здесь и реализовано ли вообще?
Подразумеваю "EXECUTE PROCEDURE proc_name" с возвращаемыми значениями. Или кроме меня никто это не использует?

я использую в основном селективные возвращаемые значения - т.е. которые с suspend - если критично именно возвращаемое  - проверю сегодня-завтра отпишусь.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Июль 15, 2010, 08:23
В общем-то, я думаю, не очень критично, просто не во всех случаях есть необходимость в селективных ХП, но если по-другому не работает, то выбор остается небольшой... Мне интересно, можно ли вообще получить с QFIREBIRD возвращаемые значения из исполняемой ХП? То есть, на самом деле, это не просто любопытство, а есть в этом необходимость. Особенно это касается поддержки RETURNING, т.к. оно возвращает значения точно так же как и исполняемые ХП -- синглтоном. Если ХП и можно придать селективность, то что делать с RETURNING?

P.S. Я тут подумал и решил... Функционал по получению RETURN-значений от ХП критичен, можно, конечно, разными обходными путями вопрос решить, но зачем? Или ткните меня носом, если я в упор не вижу, что мне делать, чтобы извлечь RETURN-параметры, или я ещё раз попытаюсь допилить драйвер, чтобы всё работало и без глюков.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Июль 16, 2010, 16:47
В общем, еще одна попытка решить проблему с возвращаемыми значениями ХП.
Прошлый патч я не сохранил, не помню, что там нагородил, этот вроде нормально работает.
Просьба потестить и оставить отзыв... Если всё это вообще кому-то ещё нужно, кроме меня.  ;D


Название: Re: Транзакции Interbase
Отправлено: varkon от Июль 16, 2010, 17:34
В общем, еще одна попытка решить проблему с возвращаемыми значениями ХП.
Прошлый патч я не сохранил, не помню, что там нагородил, этот вроде нормально работает.
Просьба потестить и оставить отзыв... Если всё это вообще кому-то ещё нужно, кроме меня.  ;D
Слушай, прежде чем тестировать патч - а как ты получаешь это возвращаемое значение? Как именно оно у тебя не работает?


Название: Re: Транзакции Interbase
Отправлено: sarbash от Июль 16, 2010, 20:54
Слушай, прежде чем тестировать патч - а как ты получаешь это возвращаемое значение? Как именно оно у тебя не работает?

Из моей переписки в ibpp-discuss@lists.sourceforge.net:
Цитировать
Le 23 mars 2010 à 07:13, Сергей Сарбаш a écrit :

> Hello, All.
>
> I suppose you know about this new feature of the Firebird 2.1 server.
> So, just the question. Has anyone already tried to implement this?
> Thank you.


There is nothing to implement in IBPP to use this nice feature.  I use it everyday.  The server returns the "returning" value just as it would do for a stored procedure returning a single value.  So just Statement->Get(...) after your Execute() and you're done.

The code sample by Borr says it all, too.

Enjoy :)
--
Olivier Mascia

После "EXECUTE PROCEDURE"-query возвращаемые значения возвращаются процедурой. :)
Вот коммент из qsql_ibase.cpp по этому поводу:
Код:
    // Stored Procedures are special - they populate our d->sqlda when executing,
    // so we don't have to call isc_dsql_fetch

Проще говоря, как написано в справке по QIBASE:
Цитировать
QIBASE Stored procedures

InterBase/Firebird return OUT values as result set, so when calling stored procedure, only IN values need to be bound via QSqlQuery::bindValue(). The RETURN/OUT values can be retrieved via QSqlQuery::value(). Example:

Код:
 QSqlQuery q;
 q.exec("execute procedure my_procedure");
 q.next();
 qDebug() << q.value(0); // outputs the first RETURN/OUT value

И чтобы всё именно так и работало, необходимый функционал реализован в qsql_ibase.cpp.
Я попытался подобный функционал реализовать и для QFIREBIRD. Без моего патча из НЕселективной процедуры получить возвращаемые значения никак. Подобная ситуация и с "INSERT ... RETURNING".

И последнее. Возможно, нужно ещё допилить и QFBResult::exec(), но тут я пока не уверен, возможно, всё уже сделано в недрах ibpp.


Название: Re: Транзакции Interbase
Отправлено: varkon от Июль 17, 2010, 11:39
Проще говоря, как написано в справке по QIBASE:
Цитировать
QIBASE Stored procedures

InterBase/Firebird return OUT values as result set, so when calling stored procedure, only IN values need to be bound via QSqlQuery::bindValue(). The RETURN/OUT values can be retrieved via QSqlQuery::value(). Example:

Код:
 QSqlQuery q;
 q.exec("execute procedure my_procedure");
 q.next();
 qDebug() << q.value(0); // outputs the first RETURN/OUT value

И чтобы всё именно так и работало, необходимый функционал реализован в qsql_ibase.cpp.
Я попытался подобный функционал реализовать и для QFIREBIRD. Без моего патча из НЕселективной процедуры получить возвращаемые значения никак. Подобная ситуация и с "INSERT ... RETURNING".

И последнее. Возможно, нужно ещё допилить и QFBResult::exec(), но тут я пока не уверен, возможно, всё уже сделано в недрах ibpp.

стоп-стоп. Я прошу прощения -  ввиду объема своих задач не все успеваю - ну так а где здесь возвращаемый параметр? Точнее где его бинд? Или это должно делаться в вызове метода?


Название: Re: Транзакции Interbase
Отправлено: varkon от Июль 17, 2010, 11:46
Я попробую пояснить чего имею ввиду. К примеру борландовские компоненты ставят в 0-позицию $RETURNING_VALUE для мссиквела - и что бы его считать - соотвественно надо обратится к параметру по имени или по индексу. В твоем коде почему то допущен нонсенс (ИМХО). Какое может быть value у запроса?


Название: Re: Транзакции Interbase
Отправлено: sarbash от Июль 17, 2010, 19:57
Я вижу вашу загруженность, сам тоже завален.
Нонсенс допущен тролями. Не знаю, что там у мссиквела за $RETURNING_VALUE, честно, не работал с ним.
Борландовские компоненты и Qt -- это несколько разные библиотеки. Запрос возвращает value, не понимаю, что не так с этим?
Реализация такая. Ещё раз прочитайте мой пост, особенно цитату из справки на тему "QIBASE Stored procedures". Возвращаемое значение будет в резолт-сете, по-любому. Либо синглтон, чего на данный момент в драйвере просто нету, почему я и создал столько суеты вокруг ХП, либо multirow-набор. Вообще, в QIBASE хитро сделано, чтобы с помощью query.next() получить OUT-значения неселективных ХП. Там и isSelect() и exec() и gotoNext() для этого соответственным образом переопределены.
Я понадеялся, что всё необходимое для exec() уже есть в ibpp, достаточно лишь немного подпилить QFIREBIRD по аналогии с QIBASE.
Вообще, в этом плане использование ibpp в драйвере намного удобнее, чем свой велосипед изобретать...

P.S. Из справки:
Цитировать
Stored procedures that uses the return statement to return values, or return multiple result sets, are not fully supported. For specific details see SQL Database Drivers.
Наверное, можно было возврат значений сделать через биндинг, но мне проще было реализацию копировать с QIBASE, при этом опять-таки возможности зависят от конкретных драйверов конкретных БД, о чём и в справке сказано.


Название: Re: Транзакции Interbase
Отправлено: varkon от Июль 18, 2010, 01:17
Борландовские компоненты и Qt -- это несколько разные библиотеки.
Верю.
Так таки можно все же привести код который не работает но должен?


Название: Re: Транзакции Interbase
Отправлено: varkon от Июль 18, 2010, 01:20
Наверное, можно было возврат значений сделать через биндинг
ну вообщето уат-параметр  - его таки надо биндить.


Название: Re: Транзакции Interbase
Отправлено: sarbash от Июль 18, 2010, 18:22
Так таки можно все же привести код который не работает но должен?

Код:
q.exec("insert into RNAMES (NAME) values (:NAME) returning ID");

Ваши предложения по получению ID?


Название: Re: Транзакции Interbase
Отправлено: const от Сентябрь 15, 2010, 10:07
Я тут выше писал про проблемы с прочтением времени с базы. Выяснилось что дело в том, что файрбёрд хранит данные о милисекундах в виде 10-х долей. Соответвтеснно если получать время то получим из базы чтото типа 12:12:12:1210. Qt при перекодировании в Qtime проверяет её на входимость в диапазоны, в частности входимость милисекунд в диапазон ms<1000. При этом естественно большинство значений туда не попадает.
Как я понимаю, данное свойство файрбёрда необходимо учесть на уровне плагина. Отпишите плиз автору на гуглокод, у меня там аккаунта нет, а то мало ли тут не увидит.


Название: Re: Транзакции Interbase
Отправлено: Urvin от Сентябрь 28, 2010, 17:13
Пожалуйста, откомпилируйте под Qt 4.7!


Название: Re: Транзакции Interbase
Отправлено: lit-uriy от Сентябрь 28, 2010, 22:47
>>Пожалуйста, откомпилируйте под Qt 4.7!
зачем?


Название: Re: Транзакции Interbase
Отправлено: sarbash от Октябрь 21, 2010, 14:46
А что у нас с поддержкой массивов? Или никому не приходилось с ними иметь дело?
Что-то меня смутил простой break; на 627-й строке qsql_ibpp.cpp...


Название: Re: Транзакции Interbase
Отправлено: vlad-mal от Ноябрь 12, 2010, 09:58
Попробовал сегодня поработать (Qt 4.7 /MinGW/ + FB2.5) со "стандартным" драйвером QIBASE: нормально возвращает значение returning, только next() выполнить нужно, а с QFIREBIRD - фиквам, с ошибкой.
Цитировать
QSqlQuery::value: not positioned on a valid record

Недопилено еще...:(


Название: Re: Транзакции Interbase
Отправлено: sarbash от Декабрь 19, 2010, 00:58
Попробовал сегодня поработать (Qt 4.7 /MinGW/ + FB2.5) со "стандартным" драйвером QIBASE: нормально возвращает значение returning, только next() выполнить нужно, а с QFIREBIRD - фиквам, с ошибкой.
Цитировать
QSqlQuery::value: not positioned on a valid record

Недопилено еще...:(
Фикс есть у меня, если нужен патч, могу поделиться. Работает по тому же принципу, что и QIBASE. Однако, до этого времени никто не проявил интерес к этому функционалу, из чего я решил, что никому, кроме меня он и не нужен. :)

P.S. На всякий случай...


Название: Re: Транзакции Interbase
Отправлено: vlad-mal от Декабрь 21, 2010, 19:25
1. Да вы что, как так "нет интереса"? Все "Qt-интербейзники" везде только на эту ветку и ссылаются. :)

2. Распреспасибищще!


Название: Re: Транзакции Interbase
Отправлено: sne от Декабрь 22, 2011, 07:15
Собственно, до автора смог кто до автора достучаться? Просто если он не поддерживает проект, может добавит мемберов, или остается форкнуть, да потихонечку дописывать??


Название: Re: Транзакции Interbase
Отправлено: Whiplash от Апрель 10, 2012, 15:41
Озадачился тут намедни работой с guid из Firebird... Долго рассказывать, но для комфортной работы пришлось слегка модифицировать драйвер QFIREBIRD. Давно этим драйвером пользуюсь, выражаю своё почтение автору :)
GUID'ы в FB принято хранить в виде CHAR(16) OCTETS. Попытка работы с таким "сырым" гуидом с помощью этого драйвера провалилась - в нём все строки преобразовываются в QString и использованием текстового кодека. А в случае гуидов это не строка, а фиксированный набор байт, который с сервера приходит как строка. Да ещё и 0x00 в середине легко попасться может.
В общем, в модифицированном драйвере:
1. Зарегистрирован и декларирован тип QUuid, чтобы можно было им пользоваться в QVariant.
2. Проводится автоматическое распознавание столбца GUID по следующим условиям:
    - домен называется UUID
    - это CHAR (16) OCTETS
3. Фактически, при открытии соединения с базой делается служебный запрос по метаданным и заполняется хэш, где каждому столбцу каждой таблицы присваивается признак true или false. В дальнейшем для доопределения типа столбца с гуид этот столбец сверяется с хэшем.
4. При помещении в запрос (bindValue) тип QUuid сериализуется в 16-байтный std::string.
5. К сожалению, для комфортного использования нужно в своём приложении не забыть написать Q_DECLARE_METATYPE(QUuid). В каком-нибудь хидере.

Примерно так можно пользоваться:
В запросе
Код
SQL
SELECT id, name FROM dir d
id - это UUID
Выполняем запрос, получаем данные:
Код:
    QSqlQuery q(db);
    q.exec("select id, name from dir d");
    q.next();
    QUuid uid=q.value(0).value<QUuid>();

Передаём данные в запрос:
Код:
    QUuid id;
    QSqlQuery q(db);
    db.transaction();
    q.prepare("select dscr from dir where id=?");
    q.bindValue(0,QVariant::fromValue(id));

Так как QUuid нестандартный для QVariant тип данных, то приходится делать всякие QVariant::fromValue(id) и value<QUuid>().
Для удобства я оперделил макрос
Код:
#define VUUID(variant) variant.value<QUuid>()
Так-что могу делать вот так:
Код:
QUuid uid=VUUID(q.value(0));
вместо
Код:
QUuid uid=q.value(0).value<QUuid>();

Даёшь GUID!

*** Блин, забыл в начале про селективные процедуры :) Сейчас поправил - гуиды работают и из селективных процедур.


Название: Re: Транзакции Interbase
Отправлено: Tonal от Апрель 11, 2012, 08:37
Для справки про uid-ы: в версии 2.1 появилась функция GEN_UUID() - генерация uuid-ов, а в 2.5 UUID_TO_CHAR и CHAR_TO_UUID - конвертаця uid-ов в строку и обратно. :)
Код:
CHAR_TO_UUID
Function:
    Converts the CHAR(32) ASCII representation of an UUID
    (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX) to the CHAR(16) OCTETS
    representation (optimized for storage).
Format:
    CHAR_TO_UUID( <string> )
Example:
    select char_to_uuid('93519227-8D50-4E47-81AA-8F6678C096A1') from rdb$database;

Ну и по хорошему, нужно для любого столбца с символьным типом и кодировками OCTETS или NONE возвращать QByteArray вместо QString - иначе, с большой вероятностью, получится каша...


Название: Re: Транзакции Interbase
Отправлено: Whiplash от Апрель 11, 2012, 15:55
Ну так потому и озаботился, что сейчас в ФБ появилась номальная поддержка UID.
Насчёт того, что для любого столбца с OCTETS или NONE возвращать ByteArray вместо строки - просто отличная идея. Время будет - так и сделаю. Чего уж, расковырял малёха драйвер так не останавливаться же.
Может, автор драйвера сделает какой-нить официальный билд с этими изменениями?


Название: Re: Транзакции Interbase
Отправлено: Tonal от Апрель 12, 2012, 09:04
Может на githab склонировать?
Там как-то попроще с управление проектом и форканьем. :)


Название: Re: Транзакции Interbase
Отправлено: eJinn от Май 13, 2013, 22:43
Всем привет.

Версия Qt:
qt-windows-opensource-5.0.2-mingw47_32-x86-offline

Драйвер QFIREBIRD не собирается.
Выдает ошибку
D:\Qt Projects\AxQtFbIbppSqlDriver\src\main.cpp:62: ошибка: expected constructor, destructor, or type conversion before 'enum'
на строчку
Q_EXPORT_PLUGIN2(qsqlfb, QFBDriverPlugin)

qsqlfirebird.dll + переименованный в qsqlfirebirdd.dll, , положенные к [Qt-dir]\5.0.2\mingw47_32\plugins\sqldrivers не подцепляется.

Win7 x64, Firebird-2.5.2.26540-0_Win32

Какие будут идеи?


Название: Re: Транзакции Interbase
Отправлено: Whiplash от Май 14, 2013, 00:28
Не соберётся драйвер для 4 версии под 5. Надо переписывать.


Название: Re: Транзакции Interbase
Отправлено: eJinn от Май 14, 2013, 07:01
Версия Qt:
qt-windows-opensource-5.0.2-mingw47_32-x86-offline

qsqlfirebird.dll + переименованный в qsqlfirebirdd.dll, , положенные к [Qt-dir]\5.0.2\mingw47_32\plugins\sqldrivers не подцепляется.
И не подцепится :(((
Цитировать
Подключаемые модули, слинкованные с библиотекой Qt, имеющей меньший главный номер версии, не будут загружены библиотекой имеющей больший главный номер версии.
Пример: Qt 4.3.1 не будет загружать подключаемый модуль, собранный с Qt 3.3.1.
http://doc.crossplatform.ru/qt/4.7.x/deployment-plugins.html (http://doc.crossplatform.ru/qt/4.7.x/deployment-plugins.html)

Пичалька...
Upd: написал Issue на эту проблему на страничке Ах`а. Может он откликнется.


Название: Re: Транзакции Interbase
Отправлено: break от Май 23, 2014, 17:41
Вот модифицированный main.cpp

Код:
#include <qsqldriverplugin.h>
#include <qstringlist.h>
#include "qsql_ibpp.h"

#include <QDebug>

class QFBDriverPlugin : public QSqlDriverPlugin
{
Q_PLUGIN_METADATA( IID "org.qt-project.Qt.QSqlDriverFactoryInterface" )
public:
QFBDriverPlugin();

QSqlDriver* create(const QString &);
QStringList keys() const;
};

QFBDriverPlugin::QFBDriverPlugin()
: QSqlDriverPlugin()
{
qDebug() << "111";
}

QSqlDriver* QFBDriverPlugin::create(const QString &name)
{
qDebug() << "222";

if (name == QLatin1String("QFIREBIRD")) {
        QFBDriver* driver = new QFBDriver();
        return driver;
    }
    return 0;
}

QStringList QFBDriverPlugin::keys() const
{
qDebug() << "333";

QStringList l;
l  << QLatin1String("QFIREBIRD");
    return l;
}

Драйвер компилится под QT 5  - но мне никак не удается его заставить работать - и в релизе и в дебаге собирал и его и программу пытающуюся его использовать, вообще не хочет загружаться в QT.

Прилагаю так же проект драйвера - может не хватает каких-то опций в pro-шнике.

Проблема пока не решена, буду рад помощи!


Название: Re: Транзакции Interbase
Отправлено: break от Май 27, 2014, 14:08
Починил - компилится под QT5 и работает !

Причина в том, что в QT5 теперь вместо виртуальной ф-ци keys возвращающей имя идентификатор плагина есть файл json. Но чтобы он увиделся надо, чтобы класс был описан в h-нике, т.к. макрос Q_PLUGIN_METADATA обрабатывается MOC-ом, который натравливается только на h-ники.

Подправленный проект прилагаю!


Название: Re: Транзакции Interbase
Отправлено: break от Май 27, 2014, 14:42
Кто мне подскажет как автор предполагал использовать несколько транзакций внутри одного соединения QSqlDatabase ?

Я не вижу как это возможно - мпакрос TRANSACTION это всего лишь установка свойства драйвера, QSqlDatabase::database().driver()->setProperty("Transaction",(x)) и оно применится к застартованной после транзакции. Внутри одного QSqlDatabase мы вроде можем иметь только одну запущенную транзакцию....

Все таки прийдется создавать разные подключения к БД через QSqlDatabase с разным connectionName - чтобы создать изолированную транзакцию?

Простейший пример - БД - основная программа главное окно - дересья, таблички - все в одной основной транзакции. Открываем конкретный документ - хочется естественно иметь изолированную транзакцию для работы с ним - отдельное диалоговое окно с его свойствами, и две кнопки ОК (Commit), Cancel (Rollback).

 Я правильно понял, что архитектура интерфейса Qt сегодня не позволяет это сделать через один QSqlDatabase - точнее один connectionName?


Название: Re: Транзакции Interbase
Отправлено: break от Май 28, 2014, 16:49
Прикольно, но лучше собирать драйвер из консоли, а не из креатора - а то как результат MOC может и не натравиться - и опять не работает...

https://github.com/qreal/qreal/issues/209


Название: Re: Транзакции Interbase
Отправлено: break от Май 28, 2014, 17:21
Разобрался с транзакциями в этом драйвере - вызов функции transaction() стартует новую транзакцию и кладет ее в стек, штатный драйвер не делал этого. Далее commit или rollback могут работать с последней транзакцией из стека. В принцепе это удобно при вызове диалоговых окон и частично решает проблему, но в более сложном интерфейсе где все равно нужно управление отдельными параллельно живущими транзакциями прийдется делать несколько коннекшенов QSqlDatabase - ф-ция cloneDatabase  в помощь...

Все же маловат апи Qt - транзакции должны быть именованными (ф-я transaction() должна возвращать ID транзакции, с которым потом можно работать) внутри одного QSqlDatabase, а сам QSqlDatabse должен использовать разные коннекшены только для доступа к разным БД.


Название: Re: Транзакции Interbase
Отправлено: lesav от Июнь 01, 2014, 15:02
Прикольно, но лучше собирать драйвер из консоли, а не из креатора....
Все в норме

Перелопатил IbppDriver, теперь собирается в Qt4 и Qt5, в консоле и креаторе

http://Lesav.ru/prog.org.ru/AxQtFbIbppSqlDriver.7z

В архиве собранные и проверенные драйверы для:
  • qt486_win32.x86_mingw482
  • qt486_win32.x86_msvc2010
  • qt530_win32.x86_mingw482
  • qt530_win32.x86_msvc2010


Название: Re: Транзакции Interbase
Отправлено: break от Июнь 01, 2014, 15:36
Ibpp тут не при чем. При сборке в креаторе не всегда вызывается moc на нужные файлы - корректная сборка в случае с плагином будет происходить через раз по случайному принципу. Ссылку почему дал.


Название: Re: Транзакции Interbase
Отправлено: lesav от Июнь 01, 2014, 17:56
Чтобы вызвался moc необходимо чтобы в файле был Q_OBJECT

В вашем main.cpp  Q_OBJECT небыло


Название: Re: Транзакции Interbase
Отправлено: break от Июнь 01, 2014, 18:25
Нет - опять не верно. Q_OBJECT  есть в предке, да и в наследнике он был - и MOC все равно не вызывался - я дал ссылку на ошибку QTCreator-а по причине которой вызывался qmake -r вместо qmake и именно из-за этого не всегда происходила правильная сборка. Вам следует изучить предоставленный материал!

https://github.com/qreal/qreal/issues/209

И для справки - MOC  натравливается только на H файлы. Первый рабочий вариант, который я показал - до выяснения проблемы со сборкой - я уже перенес описание класса в H файл!

В вашем случае МОК наравливается на CPP  хаком через "#include MAIN.MOC"


Название: Re: Транзакции Interbase
Отправлено: lesav от Июнь 02, 2014, 05:42
В вашем случае МОК наравливается на CPP  хаком через "#include MAIN.MOC"
MAIN.MOC это выхлоп от moc.exe.   Ну да ладно. 


У вас проблем с драйвером нет ? В частности корректно отображаются поля TIMESTAMP ?

Я заметил, что моя JS-обертка драйвера возвращает в QScriptEngin данные типа "02-06-2014 00:00:00" вместо необходимого "02-06-2014 06:40:35"

У вас таких проблем нет ?


Название: Re: Транзакции Interbase
Отправлено: break от Июнь 02, 2014, 16:19
Да похоже тоже ошибка присутствует...  :(

Вывод:

QDateTime("2014-06-02 00:00:00.000 MSK Qt::LocalTime")

в БД:

02.06.2014, 17:15:36.117


Название: Re: Транзакции Interbase
Отправлено: break от Июнь 02, 2014, 16:28
Странно... Драйвер возвращает количество миллисекунд на порядок большее чем надо (число мсек * 10 )

QDateTime fromIBPPTimeStamp(IBPP::Timestamp&) 154 | 17 15 36 1170

Легко поправляется в исходнике драйвера - интересно раньше эта проблема тоже была?

Код:
static QDateTime fromIBPPTimeStamp(IBPP::Timestamp &dt)
{
    int y,m,d,h,min,s,ms;
    dt.GetDate(y,m,d);
    dt.GetTime(h,min,s,ms);
    return QDateTime(QDate(y,m,d), QTime(h,min,s,ms/10));
}


Название: Re: Транзакции Interbase
Отправлено: break от Июнь 02, 2014, 16:43
Кстати удобнее использовать не ilReadCommited  константу, а константу ilReadDirty в параметрах настройки уровня изоляции транзакции. Это ReadCommited с опцией RecordVersion

#define TRANS_SELECT "TAM=amRead, TIL=ilReadDirty, TLR=lrNoWait, TFF=0"

Цитировать
READ COMMITTED (константа read_committed) - уровень изоляции ReadCommitted. Т.е. в данной транзакции все изменения, которые были подтверждены другими транзакциями, будут видны немедленно. Имеет две опции:

NO RECORD_VERSION (константа no_rec_version) - если при чтении пакета версий записи (о версионности "в двух словах см. www.ibase.ru/devinfo/mga.htm) обнаруживается non-committed версия, то выдается или deadlock (в режиме no wait) или транзакция зависает на блокировке (в режиме wait). По умолчанию для режима READ COMMITTED в IB API.

RECORD_VERSION (константа REC_VERSION) - игнорирует non-committed версии, читая последнюю committed-версию (см. выше no_rec_version). Именно этот режим является умолчательным в BDE (начиная с версии BDE 4.01. см. документ), и рекомендуется для нормальной работы в режиме read committed.

примечание: как выяснилось (в 2010) году, многие разработчики драйверов (Firebird ODBC, Firebird .Net driver (DNET-337) и т.д.) почему-то считают, что для read_committed нормальным является режим no record_version, вызывающий блокировки по чтению non-committed данных. Это является неестественным, т.к. InterBase и Firebird ни при каком уровне изолированности не допускают чтения non-committed данных. Более того, версионность в первую очередь предназначена для того, чтобы обеспечивать бесконфликтное чтение подтвержденных (committed) данных.
В любом случае, если вы видите deadlock при чтении, значит ваш драйвер или компоненты используют именно no record_version для read committed. Если возможно (позволяет драйвер или компоненты), попытайтесь это исправить настройками параметров транзакции.
В большинстве компонентов прямого доступа (IBX, FIBPlus и т.д.) умолчательным для режима ReadCommitted как раз является record_version, не выдающий блокировок при чтении non-committed данных.

http://www.ibase.ru/devinfo/ibtrans.htm


Название: Re: Транзакции Interbase
Отправлено: lesav от Июнь 04, 2014, 11:29
Подправил драйвер (что исправлено (http://www.prog.org.ru/index.php?topic=8509.msg196275#msg196275))

http://Lesav.ru/prog.org.ru/AxQtFbIbppSqlDriver.7z

В архиве собранные и проверенные драйверы для:
  • qt485_win32.x86_mingw440
  • qt485_win32.x86_mingw481
  • qt485_win32.x86_msvc2010
  • qt486_win32.x86_mingw482
  • qt486_win32.x86_msvc2010
  • qt520_win32.x86_mingw480
  • qt520_win32.x86_msvc2010
  • qt521_win32.x86_mingw480
  • qt521_win32.x86_msvc2010
  • qt530_win32.x86_mingw482
  • qt530_win32.x86_msvc2010


Название: Re: Транзакции Interbase
Отправлено: eJinn от Июнь 06, 2014, 15:35
У вас проблем с драйвером нет ? В частности корректно отображаются поля TIMESTAMP ?
Это известная ошибка драйвера
Необходимо изменить код драйвера src/sql/drivers/ibase/qsql_ibase.cpp
 тут:
Код:
static QDateTime fromTimeStamp(char *buffer)
{
    static const QDate bd(1858, 11, 17);
    // !!!! QTime t;
    QTime t(0,0,0,0);
    QDate d;
и, аналогично, тут:
Код:
static QTime fromTime(char *buffer)
и пересобрать драйвер.

PS К моему великому сожалению у меня потребовали переделать проект под MySQL. Вот так.


Название: Re: Транзакции Interbase
Отправлено: break от Февраль 27, 2015, 17:04
Столкнулся с такой ситуацией - не получается "правильно" использовать метод prepare класса QSqlQuery

То есть нельзя полсе exec снова сделать множественные bindValue и снова запустить exec - возвращается ошибка "No statement have been prepared" - приходится делать prepare запроса с параметрами каждый раз, что сводит смысл использования prepare на нет.....


Так же не работает привязка через bindValue если плейсхолдеры были указаны в запросе и переданы QSqlQuery в конструкторе... Но это мелочь конечно.

Кто нибудь сталкивался?


Название: Re: Транзакции Interbase
Отправлено: break от Февраль 27, 2015, 18:28
Вообще-то работает если до создания QSqlQuery стартовать транзакцию явно через db.transaction();
тогда до следующего commit-а все работает

Если не стартовать - то не работает, со стандартным драйвером работало, что и запутало при переводе очередного проекта на этот драйвер. Кто нибудь знает какие параметры транзакции использует стандартный драйвер?


Название: Re: Транзакции Interbase
Отправлено: break от Июнь 10, 2015, 20:07
Интересные наблюдения в продолжение двух предыдущих моих сообщений. В зависимости от того явно или не явно управлять стартом транзакций, запросы на чтение и запросы на обновление данных работают по разному. Как будто QSqlQuery делает внутри себя commit в случае запроса на изменение данных.

Например такой код работает всегда:

QSqlQuery q;
q.prepare( "select * from TEMP_TBL_1 where PROCESS_CODE = :PROCESS_CODE" );
q.bindValue( ":PROCESS_CODE", 123 );
q.exec();
q.bindValue( ":PROCESS_CODE", 123 );
q.exec();


Выполнятся оба запроса без ошибок. А такой не работает, если предварительно не стартовать транзакцию вручную через db.transaction();

QSqlQuery q;
q.prepare( "INSERT INTO TEMP_TBL_1(WORK_ROW_ID, PROCESS_CODE) VALUES(:WORK_ROW_ID, :PROCESS_CODE)" );
q.bindValue( ":WORK_ROW_ID", i );
q.bindValue( ":PROCESS_CODE", 123 );
q.exec();
q.bindValue( ":WORK_ROW_ID", i );
q.bindValue( ":PROCESS_CODE", 123 );
q.exec();


Выполнится только первый запрос, а на второй выведется ошибка

void QFBResultPrivate::setError(const string&, IBPP::Exception&, QSqlError::ErrorType) 403 | *** IBPP::LogicException ***
Context: Statement::Execute
Message: No statement has been prepared


А если сделать так - то все работает гладко


dbManager()->startTransaction();
QSqlQuery q;
q.prepare( "INSERT INTO TEMP_TBL_1(WORK_ROW_ID, PROCESS_CODE) VALUES(:WORK_ROW_ID, :PROCESS_CODE)" );
q.bindValue( ":WORK_ROW_ID", i );
q.bindValue( ":PROCESS_CODE", 123 );
q.exec();
q.bindValue( ":WORK_ROW_ID", i );
q.bindValue( ":PROCESS_CODE", 123 );
q.exec();
dbManager()->commit_DB();


Это все в продвинутом фаерберд драйвере, но предположу, что не от драйвера qt это зависит (пока нет возможности проверить). Может этому есть логичное объяснение - и все так и должно быть?


Название: Re: Транзакции Interbase
Отправлено: break от Июнь 11, 2015, 17:12
Проверил со стандартным драйвером IBase - там такого поведения нет - всем кто будет использовать продвинутый рекомендую об этом помнить )


Название: Re: Транзакции Interbase
Отправлено: break от Июнь 11, 2015, 17:34
Подтверждение в исходниках QFBDriverPlugin - автор так и планировал

bool QFBResult::exec()
Код:
    if (!rp->isSelect())
        rp->commit();

bool QFBResultPrivate::commit()
Код:
    if (!localTransaction)
        return true;


Название: Re: Транзакции Interbase
Отправлено: joker от Август 19, 2015, 14:27
Наткнулся еще на один артефакт - для сборки под Linux зачем то закоментирована линковка lfbclient. Для правильной сборки диез (#) нужно убрать

ibpp.pri

Код:
DEPENDPATH  += $$PWD/core
INCLUDEPATH += $$PWD/core
HEADERS     += $$PWD/core/ibpp.h
SOURCES     += $$PWD/core/all_in_one.cpp

unix{
  #LIBS    += -lfbclient  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< вот тут
  DEFINES += IBPP_LINUX
  DEFINES += IBPP_GCC
}


Название: Re: Транзакции Interbase
Отправлено: xokc от Сентябрь 21, 2015, 23:18
Проверил со стандартным драйвером IBase - там такого поведения нет - всем кто будет использовать продвинутый рекомендую об этом помнить )
А вот у меня и со стандартным похожий косяк.
Код
C++ (Qt)
m_query->prepare("insert into RESULTS (RES_ID) values (?)");
QSqlDatabase::database().transaction();
for (const SigPac &sig : sigs) {
   m_packets[sig.id] = sig;
   m_query->addBindValue(sig.id);
   if (!m_query->exec()) {
       qCritical() << m_query->lastError();
   }
}
QSqlDatabase::database().commit();
При первом срабатывании этого участка кода всё в порядке - вставляется некоторое количество записей, а вот для второго и далее имею при вызове exec ошибку:
QSqlError("-901", "Unable to execute query", "invalid transaction handle (expecting explicit transaction start)").
Как это лечить?


Название: Re: Транзакции Interbase
Отправлено: break от Май 02, 2016, 05:41
Мучения с драйверами БД в QT привели к мысли написания своих классов работы с БД. За основу взял код этого драйвера (по сути тащил все нужные методы, чтобы с нуля не разбираться с IBPP). И интересный вопрос а вообще есть вменяемая и подробная инструкция по написанию плагинов - драйверов БД. Я что-то не встречал - может упустил... Или каждый желающий разбирается сам? Особенно радует, что от версии к версии QSqlCashedResult и другие потроха меняются, и приходится свои классы-плагины БД все время перепиливать, по ходу разбираясь как это будет правильно сделать...

Хотя в текущей системе Qt писать такой плагин все равно нет никакого желания из-за одного огромного ограничения - НЕТ ВОЗМОЖНОСТИ ЯВНОГО УПРАВЛЕНИЯ ТРАНЗАКЦИЯМИ (Как они вообще это упустили? Что за программу можно более менее серьезную без явного управления транзакциями написать?).

С одной стороны такая возможность косвенно есть

 - вариант первый через описанный в этой теме драйвер - то есть при каждом вызове функции transaction() будет стартовать новая транзакция (но не будет удаляться старая в отличие от стандартного драйвера) и автор даже умудрился придумать как костылем туда передавать ее параметры (чего кстати тоже очень не хватает в Qt системе). НО все последующие созданные QSqlQuery будут уже выполняться в контексте последней созданной транзакции и этого через текущую систему Qt не изменить - а что тут плохого? А вот что - если есть основная программа (к примеру берем главное окно), и нам нужно открыть модальное диалоговое окно которое будет работать в контексте своей транзакции - тогда при открытии окна мы вызываем transaction, работаем с окном, при закрытии окна вызывается commit() или rollback() - и все нормально, А вот если окно нам нужно не модальное - то все плохо. Т.к. если это окошко (ил процесс какой-то) запустил транзакцию, то и в главном окне все последующие созданные QSqlQuery будут работать в контексте этой запущенной последней транзакции, что совсем не хорошо, и может привести к очень запутанным ошибкам в самой программе. Ведь параметры основной транзакции и той, что в конкретном диалоговом окне могут быть совсем разные. Окна только для примера - то же самое с любыми условно параллельными процессами в программе.

- вариант второй использовать во всех местах, где нужна отдельная транзакция новое соединение с БД - то есть не экземпляр QSqlDatabase, а именно новое соединение с новым "connection name" пусть даже созданное через функцию clone. На первый взгляд приемлемо - но на деле тормоза, т.к. запрашивается новое соединение с БД на сервере, со всеми вытекающими, да и работать с этим совершенно неудобно.

Естественно я пробовал оба эти варианта притворить в жизнь. Мое мнение - КОСТЫЛИ, да и только.

Что нам надо в реальности:

класс БД
класс Транзакцию, которая создается на основе БД, в которую можно передавать параметры транзакций Firebird
класс Query, который явно связывается с транзакцией, с простым кешем для реализации seek  и как следствие first, next  и т.д.

Этот минимум можно дополнить классом-одиночкой DBManager который вернет по алиасу нужный класс БД и нужную транзакцию в любом месте программы, чтобы не передавать это добро в качестве параметров в конструкторы диалоговых окон и т.д.

Все это реализуемо через IBPP. Голый IBPP  не хочется использовать, т.к. это неудобно хочется все проверки с эксепшенами оставить в тонкой обертке, на выходе которой будут понятные и простые для любого программиста функции bool.

Может я запутался и не прав? Или каждый свои такие классы давно уже наваял и никто не делится?


Название: Re: Транзакции Interbase
Отправлено: break от Май 02, 2016, 05:45
Проверил со стандартным драйвером IBase - там такого поведения нет - всем кто будет использовать продвинутый рекомендую об этом помнить )
А вот у меня и со стандартным похожий косяк.
Код
C++ (Qt)
m_query->prepare("insert into RESULTS (RES_ID) values (?)");
QSqlDatabase::database().transaction();
for (const SigPac &sig : sigs) {
   m_packets[sig.id] = sig;
   m_query->addBindValue(sig.id);
   if (!m_query->exec()) {
       qCritical() << m_query->lastError();
   }
}
QSqlDatabase::database().commit();
При первом срабатывании этого участка кода всё в порядке - вставляется некоторое количество записей, а вот для второго и далее имею при вызове exec ошибку:
QSqlError("-901", "Unable to execute query", "invalid transaction handle (expecting explicit transaction start)").
Как это лечить?
Наверное поздно я сюда заглянул - ну так на первый взгляд как раз то о чем я и говорил, у Вас создается QSqlQuery и припарится в контексте одной транзакции, а потом стартуется другая и стандартный драйвер видимо пытается выполнить ваш Query в новосозданной транзакции, но отпрепаренный в другой - предыдущей. И голову у него сносит... Это все следствие кривости архитектуры, как будто методы transaction, commit и rollback  были потом сбоку придуманы... Я давно не пользовался стандартным драйвером, но он вроде как не может иметь в одном соединении несколько транзакций, а значит... значит надо глубоко копать, что именно происходит, но явно ничего с текущей системой красиво сделать не получится... или пусть меня кто-то поправит...
Лечить костылями... Эх...


Название: Re: Транзакции Interbase
Отправлено: break от Июль 13, 2016, 02:48
Ввиду того, что никто не сказал, что я все таки запутался - написал свои тонкие обертки над IBPP как и планировал выше, полностью выкинул из проекта QtSql  и пользуюсь с удобством и удовольствием уже длительное время.