Pregunta

I have a class which needs to execute batch inserts repeatedly. QSqlQuery instance is a member of that class. At first I tried this code:

TOMCache::TOMCache(QObject *parent): QObject(parent) {    
    m_setWithGeoQuery.prepare("INSERT OR REPLACE INTO cache_storage(key, value, lat, lng, expiration) VALUES(?, ?, ?, ?, ?)");
}

void TOMCache::flushBuffer() {
    QSqlQuery &query = m_setWithGeoQuery;
    query.addBindValue(m_buffer.at(0));
    query.addBindValue(m_buffer.at(1));
    query.addBindValue(m_buffer.at(2));
    query.addBindValue(m_buffer.at(3));
    query.addBindValue(m_buffer.at(4));
    if(!query.execBatch())
        qWarning() << "-- execBatch() failed: " << query.lastError().text();
    m_buffer.clear();
    m_buffer << QVariantList() << QVariantList() << QVariantList() << QVariantList() << QVariantList();
}

That didn't work. The created SQLite file had 65536 Bytes, but there was only 1 row in the table cache_storage (flushBuffer() was called many times). It looks like the first call of execBatch() executed successfully and next calls silently failed (they kept returning true). I realized that the following code works:

void TOMCache::flushBuffer() {

    QSqlQuery query;
    query.prepare("INSERT OR REPLACE INTO cache_storage(key, value, lat, lng, expiration) VALUES(?, ?, ?, ?, ?)");
    query.addBindValue(m_buffer.at(0));
    query.addBindValue(m_buffer.at(1));
    query.addBindValue(m_buffer.at(2));
    query.addBindValue(m_buffer.at(3));
    query.addBindValue(m_buffer.at(4));
    if(!query.execBatch())
        qWarning() << "-- execBatch() failed: " << query.lastError().text();
    m_buffer.clear();
    m_buffer << QVariantList() << QVariantList() << QVariantList() << QVariantList() << QVariantList();
}

I have a couple of questions:

  1. Does QSqlQuery need to be created and destroyed for each call of execBatch()?

  2. If so, why do the subsequent calls of execBatch() pretend to execute successfully?

  3. What about the big file size in the first case? (There are only 2 tables, the other one is empty)

I should mention that this is part of an application running on BlackBerry 10 OS. In order to avoid creating and destroying QSqlQuery each time, I also tried to call query.clear() at the end of flushBuffer() but that seems to have removed also the prepared SQL from QSqlQuery instance (next call of execBatch() failed).

EDIT: I tried to avoid parsing the SQL each time, so I tried to keep m_setWithGeoQuery unmodified and just make a copy of it in flushBuffer():

    QSqlQuery query(m_setWithGeoQuery);
    query.addBindValue(m_buffer.at(0));
    ...

Surprisingly, it doesn't work. It behaves the same as the first snippet.

¿Fue útil?

Solución

This is a bug in Qt : https://bugreports.qt.io/browse/QTBUG-43874. It happens only if both the two conditions are met:

  • calling several times execBatch on the same query
  • The values are bound using QSqlQuery::addBindValue

As a consequence, you can workaround this bug by calling QSqlQuery::bindValue, so the following code should work

TOMCache::TOMCache(QObject *parent): QObject(parent) {    
    m_setWithGeoQuery.prepare("INSERT OR REPLACE INTO cache_storage(key, value, lat, lng, expiration) VALUES(?, ?, ?, ?, ?)");
}

void TOMCache::flushBuffer() {
    QSqlQuery &query = m_setWithGeoQuery;
    query.bindValue(0, m_buffer.at(0));
    query.bindValue(1, m_buffer.at(1));
    query.bindValue(2, m_buffer.at(2));
    query.bindValue(3, m_buffer.at(3));
    query.bindValue(4, m_buffer.at(4));
    if(!query.execBatch())
        qWarning() << "-- execBatch() failed: " << query.lastError().text();
    m_buffer.clear();
    m_buffer << QVariantList() << QVariantList() << QVariantList() <<     QVariantList() << QVariantList();
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top