crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

2 страниц V   1 2 >  
Ответить в данную темуНачать новую тему
> QSqlQuery не позволяет загружать в БД большие бинарники, =(
Stanislaus
  опции профиля:
сообщение 3.9.2008, 15:54
Сообщение #1


Студент
*

Группа: Новичок
Сообщений: 17
Регистрация: 23.4.2008
Пользователь №: 156

Спасибо сказали: 0 раз(а)




Репутация:   0  


Маленькие файлики записываются без проблем, хотя и подвисает операция вставки секунд на 5...

При попытке записать в БД бинарник большого размера (напр. около 30 мегабайт)...

    q.prepare("select file_share.add_single_file(?, ?, ?, ?, ?, ?, null,?,?);");
    QByteArray ba;
    QFile file(getFilePath());
    if (file.open(QIODevice::ReadOnly)){
        ba = file.readAll();
        file.close();
    }
    q.bindValue(0,ba,QSql::In|QSql::Binary); // Здесь все пучком
    q.bindValue(1,getGroupID());
    if (getInsurer() != 0) q.bindValue(2,getInsurer());
    else q.bindValue(2,QVariant(QVariant::Int));
    q.bindValue(3,getDescription());
    q.bindValue(4,getFileName());
    q.bindValue(5,getWWW());
    q.bindValue(6,getCity());
    q.bindValue(7,mask);
    if (!q.exec()) { // тут виснет секунд на 30 и Unhandled exception at 0x1026f3e0 in project.exe: 0xC0000005: Access violation reading location 0xf272f6c4.
        qDebug() << q.lastError() << q.executedQuery();
        return false;
    }


Далее следует виновник эксепшена...

QString& QString::insert(int i, const QChar *unicode, int size)
{
    if (i < 0 || size <= 0)
        return *this;

    const ushort *s = (const ushort *)unicode;
    if (s >= d->data && s < d->data + d->alloc) {
        // Part of me - take a copy
        ushort *tmp = static_cast<ushort *>(qMalloc(size * sizeof(QChar)));
        memcpy(tmp, s, size * sizeof(QChar));
        insert(i, reinterpret_cast<const QChar *>(tmp), size);
        qFree(tmp);
        return *this;
    }

    expand(qMax(d->size, i) + size - 1);

    ::memmove(d->data + i + size, d->data + i, (d->size - i - size) * sizeof(QChar)); // <--- Эксепшн вылетает во время этой операции
    memcpy(d->data + i, s, size * sizeof(QChar));
    return *this;
}


Подключение к БД
QSqlDatabase db_b = QSqlDatabase::addDatabase("QPSQL", "b"); 
db_b.setHostName("10.10.1.123");
db_b.setPort(5433);
db_b.setDatabaseName("DBName");
db_b.setUserName("user");
db_b.setPassword("password");


Если кто сталкивался, помогите плиз.

Собираю на Microsoft Visual Studion 2008 Express Edition, Qt 4.4.0 Open Source.
Причина редактирования: используйте параметр, code=cpp
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 3.9.2008, 16:53
Сообщение #2


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Stanislaus @ 3.9.2008, 19:54) *
При попытке записать в БД бинарник большого размера (напр. около 30 мегабайт)...
а БД поддерживает такой размер?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Stanislaus
  опции профиля:
сообщение 3.9.2008, 17:30
Сообщение #3


Студент
*

Группа: Новичок
Сообщений: 17
Регистрация: 23.4.2008
Пользователь №: 156

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата(Litkevich Yuriy @ 3.9.2008, 17:53) *
а БД поддерживает такой размер?


Из того, что мне удалось найти, bytea поддерживает примерно до 1Gb (комментарий к документации PostgreSQL 7.4), поэтому смею предположить, что тут проблема не в ограничениях БД (PostgreSQL 8.2.*), а в ограничениях Qt... Может быть ограничения QString, который используется в QSqlQuery?


В принципе, как обходной вариант, можно раздробить файл на фрагменты, записать фрагментами в БД и там уже сконкантенировать в единое целое, но уж очень удобно было бы, если бы он единым целым сразу записывался.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 3.9.2008, 17:37
Сообщение #4


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


вобще непонятно причем здесь QString. Вдь ты использушь двоичный масив и поидее должна вызыватся функция:
void QSqlQuery::bindValue ( int pos, const QVariant & val, QSql::ParamType paramType = QSql::In ) в ней нет QString

Я незнаком с Постгре, но есть такая заметка:

Binary Large Objects (BLOB) are supported through the BYTEA field type in PostgreSQL server versions >= 7.1.

Может тебе понятно о чем речь?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Stanislaus
  опции профиля:
сообщение 3.9.2008, 17:43
Сообщение #5


Студент
*

Группа: Новичок
Сообщений: 17
Регистрация: 23.4.2008
Пользователь №: 156

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата(Litkevich Yuriy @ 3.9.2008, 18:32) *
вобще непонятно причем здесь QString. Вдь ты использушь двоичный масив и поидее должна вызыватся функция:
void QSqlQuery::bindValue ( int pos, const QVariant & val, QSql::ParamType paramType = QSql::In ) в ней нет QString

Именно она и вызывается. Но, насколько я понимаю, QSqlQuery пытается скомпоновать запрос из

select file_share.add_single_file(?, ?, ?, ?, ?, ?, null,?,?);


в

select file_share.add_single_file('\\134\\104\\134.........', 2, 3, 'Commentary is here...', 'file.bmp', true, null,1,0);


что в итоге окажется QString, который отправляется на сервер, но QString в случае большого файла вылезает за какие-то нормы или открывает некий баг... или все по другому происходит?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 3.9.2008, 17:45
Сообщение #6


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


И к стати, ты не пробывал вызвать такую функцию:
db_b.driver().hasFeature (QSqlDriver::BLOB)
что он скажет, имеет драйвер такую возможность или нет?
Может она толком не реализована.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Stanislaus
  опции профиля:
сообщение 3.9.2008, 18:10
Сообщение #7


Студент
*

Группа: Новичок
Сообщений: 17
Регистрация: 23.4.2008
Пользователь №: 156

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата(Litkevich Yuriy @ 3.9.2008, 18:45) *
И к стати, ты не пробывал вызвать такую функцию:
db_b.driver().hasFeature (QSqlDriver::BLOB)
что он скажет, имеет драйвер такую возможность или нет?
Может она толком не реализована.


db_b.driver()->hasFeature(QSqlDriver::BLOB) возвращает true


Вот к чему привел дебаггинг... Во время обработки первого параметра, которым является бинарник....
bool QSqlResult::exec()
{
    bool ret;
    // fake preparation - just replace the placeholders..
    QString query = lastQuery();
    if (d->binds == NamedBinding) {
        int i;
        QVariant val;
        QString holder;
        for (i = d->holders.count() - 1; i >= 0; --i) {
            holder = d->holders.at(i).holderName;
            val = d->values.value(d->indexes.value(holder));
            QSqlField f(QLatin1String(""), val.type());
            f.setValue(val);
            query = query.replace(d->holders.at(i).holderPos,
                                   holder.length(), driver()->formatValue(f));
        }
    } else {
        QString val;
        int i = 0;
        int idx = 0;
        for (idx = 0; idx < d->values.count(); ++idx) {
            i = query.indexOf(QLatin1Char('?'), i);
            if (i == -1)
                continue;
            QVariant var = d->values.value(idx);
            QSqlField f(QLatin1String(""), var.type());
            if (var.isNull())
                f.clear();
            else
                f.setValue(var);
            val = driver()->formatValue(f); // тут ненадолго задумывается....
            query = query.replace(i, 1, driver()->formatValue(f)); // и тут вылетает ексепшн...
            i += val.length();
        }
    }

    // have to retain the original query with placeholders
    QString orig = lastQuery();
    ret = reset(query);
    d->executedQuery = query;
    setQuery(orig);
    d->resetBindCount();
    return ret;
}
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 3.9.2008, 18:20
Сообщение #8


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Цитата(Stanislaus @ 3.9.2008, 16:54) *
::memmove(d->data + i + size, d->data + i, (d->size - i - size) * sizeof(QChar)); // <--- Эксепшн вылетает во время этой операции
Что-то мне не нравится этот код, а ты уверен, что не выходишь за область выделенной памяти? :)

Может быть так:
::memmove(d->data + i + size, d->data + i, (d->size - size) * sizeof(QChar));
?
И какого типа у тебя d->data?

Извини, отставить d->size - size, перепутал местами Src и Dest... :)

Проверь выходит ли за область и всегда ли в i или size правильные значения.

Сообщение отредактировал ViGOur - 3.9.2008, 18:16
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 3.9.2008, 18:41
Сообщение #9


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(ViGOur @ 3.9.2008, 22:20) *
Что-то мне не нравится этот код, а ты уверен, что не выходишь за область выделенной памяти?
а это код Тролей :)

Цитата(Stanislaus @ 3.9.2008, 22:10) *
val = driver()->formatValue(f); // тут ненадолго задумывается....
query = query.replace(i, 1, driver()->formatValue(f)); // и тут вылетает ексепшн...
мабуть драйвер таки не доделаный, надо у тролей в трекере поискать
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Tonal
  опции профиля:
сообщение 4.9.2008, 11:28
Сообщение #10


Активный участник
***

Группа: Участник
Сообщений: 452
Регистрация: 6.12.2007
Из: Новосибирск
Пользователь №: 34

Спасибо сказали: 69 раз(а)




Репутация:   17  


Если верить этому коду, то Qt вместо параметров явным образом подставляет значения перед отправкой SQL-я на сервер.
А на длину SQL-я могут быть довольно сильные ограничения (Firebird/Interbase < 32к).

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

Сообщение отредактировал Tonal - 4.9.2008, 11:29
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


7 чел. читают эту тему (гостей: 7, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 23.11.2024, 6:47