aboutsummaryrefslogtreecommitdiffstats
path: root/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@unit193.net>2021-12-17 07:06:30 -0500
committerLibravatarUnit 193 <unit193@unit193.net>2021-12-17 07:06:30 -0500
commit1fdc150116cad39aae5c5da407c3312b47a59e3a (patch)
tree123c79a4d7ad2d45781ba03ce939f7539fb428d8 /SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h
parentfeda8a7db8d1d7c5439aa8f8feef7cc0dd2b59a0 (diff)
New upstream version 3.3.3+dfsg1.upstream/3.3.3+dfsg1
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h')
-rw-r--r--SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h925
1 files changed, 0 insertions, 925 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h b/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h
deleted file mode 100644
index 51465f9..0000000
--- a/SQLiteStudio3/coreSQLiteStudio/db/abstractdb2.h
+++ /dev/null
@@ -1,925 +0,0 @@
-#ifndef ABSTRACTDB2_H
-#define ABSTRACTDB2_H
-
-#include "db/abstractdb.h"
-#include "parser/lexer.h"
-#include "common/utils_sql.h"
-#include "common/unused.h"
-#include "db/sqlerrorcodes.h"
-#include "db/sqlerrorresults.h"
-#include "log.h"
-#include <sqlite.h>
-#include <QThread>
-#include <QPointer>
-#include <QDebug>
-#include <QMutexLocker>
-#include <QMutex>
-
-/**
- * @brief Complete implementation of SQLite 2 driver for SQLiteStudio.
- *
- * Inherit this when implementing Db for SQLite 2. In most cases you will only need
- * to create one public constructor, which forwards parameters to the AbstractDb constructor.
- * This be sufficient to implement SQLite 2 database plugin.
- * Just link it with proper SQLite library.
- *
- * The template parameter is currently not used for anything specific, so pass any unique type name.
- * The best would be to define empty class/structure just for this purpose.
- * The parameter is there, so this class becomes a template class.
- * We need a template class so we can provide common code base for all SQLite 2 plugins, while the
- * code doesn't introduce dependency to SQLite 2 library, until it's used, which is in SQLite 2 plugins.
- *
- * @see DbQt
- */
-template <class T>
-class AbstractDb2 : public AbstractDb
-{
- public:
- /**
- * @brief Creates SQLite database object.
- * @param name Name for the database.
- * @param path File path of the database.
- * @param connOptions Connection options. See AbstractDb for details.
- *
- * All values from this constructor are just passed to AbstractDb constructor.
- */
- AbstractDb2(const QString& name, const QString& path, const QHash<QString, QVariant>& connOptions);
- ~AbstractDb2();
-
- bool loadExtension(const QString& filePath, const QString& initFunc = QString());
- bool isComplete(const QString& sql) const;
-
- protected:
- bool isOpenInternal();
- void interruptExecution();
- QString getErrorTextInternal();
- int getErrorCodeInternal();
- bool openInternal();
- bool closeInternal();
- bool initAfterCreated();
- void initAfterOpen();
- SqlQueryPtr prepare(const QString& query);
- QString getTypeLabel();
- bool deregisterFunction(const QString& name, int argCount);
- bool registerScalarFunction(const QString& name, int argCount);
- bool registerAggregateFunction(const QString& name, int argCount);
- bool registerCollationInternal(const QString& name);
- bool deregisterCollationInternal(const QString& name);
-
- private:
- class Query : public SqlQuery, public Sqlite2ColumnDataTypeHelper
- {
- public:
- class Row : public SqlResultsRow
- {
- public:
- void init(const QStringList& columns, const QList<QVariant>& resultValues);
- };
-
- Query(AbstractDb2<T>* db, const QString& query);
- ~Query();
-
- QString getErrorText();
- int getErrorCode();
- QStringList getColumnNames();
- int columnCount();
- qint64 rowsAffected();
- QString finalize();
-
- protected:
- SqlResultsRowPtr nextInternal();
- bool hasNextInternal();
- bool execInternal(const QList<QVariant>& args);
- bool execInternal(const QHash<QString, QVariant>& args);
-
- private:
- int prepareStmt(const QString& processedQuery);
- int resetStmt();
- int bindParam(int paramIdx, const QVariant& value);
- int fetchNext();
- int fetchFirst();
- void init(int columnsCount, const char** columns);
- bool checkDbState();
- void copyErrorFromDb();
- void copyErrorToDb();
- void setError(int code, const QString& msg);
-
- static QString replaceNamedParams(const QString& query);
-
- QPointer<AbstractDb2<T>> db;
- sqlite_vm* stmt = nullptr;
- int errorCode = SQLITE_OK;
- QString errorMessage;
- int colCount = -1;
- QStringList colNames;
- QList<QVariant> nextRowValues;
- bool rowAvailable = false;
- };
-
- void cleanUp();
- void resetError();
- QString freeStatement(sqlite_vm* stmt);
-
- static void storeResult(sqlite_func* func, const QVariant& result, bool ok);
- static QList<QVariant> getArgs(int argCount, const char** args);
- static void evaluateScalar(sqlite_func* func, int argCount, const char** args);
- static void evaluateAggregateStep(sqlite_func* func, int argCount, const char** args);
- static void evaluateAggregateFinal(sqlite_func* func);
- static void* getContextMemPtr(sqlite_func* func);
- static QHash<QString,QVariant> getAggregateContext(sqlite_func* func);
- static void setAggregateContext(sqlite_func* func, const QHash<QString,QVariant>& aggregateContext);
- static void releaseAggregateContext(sqlite_func* func);
-
- sqlite* dbHandle = nullptr;
- QString dbErrorMessage;
- int dbErrorCode = SQLITE_OK;
- QList<FunctionUserData*> userDataList;
- QList<Query*> queries;
- QMutex* dbOperMutex = nullptr;
-};
-
-//------------------------------------------------------------------------------------
-// AbstractDb2
-//------------------------------------------------------------------------------------
-
-template <class T>
-AbstractDb2<T>::AbstractDb2(const QString& name, const QString& path, const QHash<QString, QVariant>& connOptions) :
- AbstractDb(name, path, connOptions)
-{
- dbOperMutex = new QMutex(QMutex::Recursive);
-}
-
-template <class T>
-AbstractDb2<T>::~AbstractDb2()
-{
- safe_delete(dbOperMutex);
- if (isOpenInternal())
- closeInternal();
-}
-
-template <class T>
-bool AbstractDb2<T>::loadExtension(const QString& filePath, const QString& initFunc)
-{
- UNUSED(filePath);
- UNUSED(initFunc);
- return false;
-}
-
-template<class T>
-bool AbstractDb2<T>::isComplete(const QString& sql) const
-{
- return sqlite_complete(sql.toUtf8().constData());
-}
-
-template <class T>
-bool AbstractDb2<T>::isOpenInternal()
-{
- return dbHandle != nullptr;
-}
-
-template <class T>
-SqlQueryPtr AbstractDb2<T>::prepare(const QString& query)
-{
- return SqlQueryPtr(new Query(this, query));
-}
-
-template <class T>
-void AbstractDb2<T>::interruptExecution()
-{
- if (!isOpenInternal())
- return;
-
- QMutexLocker mutexLocker(dbOperMutex);
- sqlite_interrupt(dbHandle);
-}
-
-template <class T>
-QString AbstractDb2<T>::getErrorTextInternal()
-{
- return dbErrorMessage;
-}
-
-template <class T>
-int AbstractDb2<T>::getErrorCodeInternal()
-{
- return dbErrorCode;
-}
-
-template <class T>
-bool AbstractDb2<T>::openInternal()
-{
- resetError();
- sqlite* handle = nullptr;
- char* errMsg = nullptr;
- QMutexLocker mutexLocker(dbOperMutex);
- handle = sqlite_open(path.toUtf8().constData(), 0, &errMsg);
- if (!handle)
- {
- dbErrorCode = SQLITE_ERROR;
-
- if (errMsg)
- {
- dbErrorMessage = QObject::tr("Could not open database: %1").arg(QString::fromUtf8(errMsg));
- sqlite_freemem(errMsg);
- }
- return false;
- }
- dbHandle = handle;
- return true;
-}
-
-template <class T>
-bool AbstractDb2<T>::closeInternal()
-{
- resetError();
- if (!dbHandle)
- return false;
-
- cleanUp();
-
- QMutexLocker mutexLocker(dbOperMutex);
- sqlite_close(dbHandle);
- dbHandle = nullptr;
- return true;
-}
-
-template <class T>
-bool AbstractDb2<T>::initAfterCreated()
-{
- version = 2;
- return AbstractDb::initAfterCreated();
-}
-
-template <class T>
-void AbstractDb2<T>::initAfterOpen()
-{
-}
-
-template <class T>
-QString AbstractDb2<T>::getTypeLabel()
-{
- return T::label;
-}
-
-template <class T>
-bool AbstractDb2<T>::deregisterFunction(const QString& name, int argCount)
-{
- if (!dbHandle)
- return false;
-
- QMutexLocker mutexLocker(dbOperMutex);
- sqlite_create_function(dbHandle, name.toLatin1().data(), argCount, nullptr, nullptr);
- sqlite_create_aggregate(dbHandle, name.toLatin1().data(), argCount, nullptr, nullptr, nullptr);
-
- FunctionUserData* userData = nullptr;
- QMutableListIterator<FunctionUserData*> it(userDataList);
- while (it.hasNext())
- {
- userData = it.next();
- if (userData->name == name && userData->argCount == argCount)
- {
- it.remove();
- delete userData;
- }
- }
-
- return true;
-}
-
-template <class T>
-bool AbstractDb2<T>::registerScalarFunction(const QString& name, int argCount)
-{
- if (!dbHandle)
- return false;
-
- FunctionUserData* userData = new FunctionUserData;
- userData->db = this;
- userData->name = name;
- userData->argCount = argCount;
- userDataList << userData;
-
- QMutexLocker mutexLocker(dbOperMutex);
- int res = sqlite_create_function(dbHandle, name.toUtf8().constData(), argCount,
- &AbstractDb2<T>::evaluateScalar, userData);
-
- return res == SQLITE_OK;
-}
-
-template <class T>
-bool AbstractDb2<T>::registerAggregateFunction(const QString& name, int argCount)
-{
- if (!dbHandle)
- return false;
-
- FunctionUserData* userData = new FunctionUserData;
- userData->db = this;
- userData->name = name;
- userData->argCount = argCount;
- userDataList << userData;
-
- QMutexLocker mutexLocker(dbOperMutex);
- int res = sqlite_create_aggregate(dbHandle, name.toUtf8().constData(), argCount,
- &AbstractDb2<T>::evaluateAggregateStep,
- &AbstractDb2<T>::evaluateAggregateFinal,
- userData);
-
- return res == SQLITE_OK;
-}
-
-template <class T>
-bool AbstractDb2<T>::registerCollationInternal(const QString& name)
-{
- // Not supported in SQLite 2
- UNUSED(name);
- return false;
-}
-
-template <class T>
-bool AbstractDb2<T>::deregisterCollationInternal(const QString& name)
-{
- // Not supported in SQLite 2
- UNUSED(name);
- return false;
-}
-
-template <class T>
-void AbstractDb2<T>::cleanUp()
-{
- for (Query* q : queries)
- q->finalize();
-}
-
-template <class T>
-void AbstractDb2<T>::resetError()
-{
- dbErrorCode = 0;
- dbErrorMessage = QString::null;
-}
-
-template <class T>
-void AbstractDb2<T>::storeResult(sqlite_func* func, const QVariant& result, bool ok)
-{
- if (!ok)
- {
- QByteArray ba = result.toString().toUtf8();
- sqlite_set_result_error(func, ba.constData(), ba.size());
- return;
- }
-
- // Code below is a modified code from Qt (its SQLite plugin).
- if (result.isNull())
- {
- sqlite_set_result_string(func, nullptr, -1);
- return;
- }
-
- switch (result.type())
- {
- case QVariant::ByteArray:
- {
- QByteArray ba = result.toByteArray();
- sqlite_set_result_string(func, ba.constData(), ba.size());
- break;
- }
- case QVariant::Int:
- case QVariant::Bool:
- case QVariant::UInt:
- case QVariant::LongLong:
- {
- sqlite_set_result_int(func, result.toLongLong());
- break;
- }
- case QVariant::Double:
- {
- sqlite_set_result_double(func, result.toDouble());
- break;
- }
- case QVariant::List:
- {
- QList<QVariant> list = result.toList();
- QStringList strList;
- for (const QVariant& v : list)
- strList << v.toString();
-
- QByteArray ba = strList.join(" ").toUtf8();
- sqlite_set_result_string(func, ba.constData(), ba.size());
- break;
- }
- case QVariant::StringList:
- {
- QByteArray ba = result.toStringList().join(" ").toUtf8();
- sqlite_set_result_string(func, ba.constData(), ba.size());
- break;
- }
- default:
- {
- // SQLITE_TRANSIENT makes sure that sqlite buffers the data
- QByteArray ba = result.toString().toUtf8();
- sqlite_set_result_string(func, ba.constData(), ba.size());
- break;
- }
- }
-}
-
-template <class T>
-QList<QVariant> AbstractDb2<T>::getArgs(int argCount, const char** args)
-{
- QList<QVariant> results;
-
- for (int i = 0; i < argCount; i++)
- {
- if (!args[i])
- {
- results << QVariant();
- continue;
- }
-
- results << QString::fromUtf8(args[i]);
- }
- return results;
-}
-
-template <class T>
-void AbstractDb2<T>::evaluateScalar(sqlite_func* func, int argCount, const char** args)
-{
- QList<QVariant> argList = getArgs(argCount, args);
- bool ok = true;
- QVariant result = AbstractDb::evaluateScalar(sqlite_user_data(func), argList, ok);
- storeResult(func, result, ok);
-}
-
-template <class T>
-void AbstractDb2<T>::evaluateAggregateStep(sqlite_func* func, int argCount, const char** args)
-{
- void* dataPtr = sqlite_user_data(func);
- QList<QVariant> argList = getArgs(argCount, args);
- QHash<QString,QVariant> aggregateContext = getAggregateContext(func);
-
- AbstractDb::evaluateAggregateStep(dataPtr, aggregateContext, argList);
-
- setAggregateContext(func, aggregateContext);
-}
-
-template <class T>
-void AbstractDb2<T>::evaluateAggregateFinal(sqlite_func* func)
-{
- void* dataPtr = sqlite_user_data(func);
- QHash<QString,QVariant> aggregateContext = getAggregateContext(func);
-
- bool ok = true;
- QVariant result = AbstractDb::evaluateAggregateFinal(dataPtr, aggregateContext, ok);
-
- storeResult(func, result, ok);
- releaseAggregateContext(func);
-}
-
-template <class T>
-void*AbstractDb2<T>::getContextMemPtr(sqlite_func* func)
-{
- return sqlite_aggregate_context(func, sizeof(QHash<QString,QVariant>**));
-}
-
-template <class T>
-QHash<QString, QVariant> AbstractDb2<T>::getAggregateContext(sqlite_func* func)
-{
- return AbstractDb::getAggregateContext(getContextMemPtr(func));
-}
-
-template <class T>
-void AbstractDb2<T>::setAggregateContext(sqlite_func* func, const QHash<QString, QVariant>& aggregateContext)
-{
- AbstractDb::setAggregateContext(getContextMemPtr(func), aggregateContext);
-}
-
-template <class T>
-void AbstractDb2<T>::releaseAggregateContext(sqlite_func* func)
-{
- AbstractDb::releaseAggregateContext(getContextMemPtr(func));
-}
-
-//------------------------------------------------------------------------------------
-// Query
-//------------------------------------------------------------------------------------
-
-template <class T>
-AbstractDb2<T>::Query::Query(AbstractDb2<T>* db, const QString& query) :
- db(db)
-{
- this->query = query;
- db->queries << this;
-}
-
-template <class T>
-AbstractDb2<T>::Query::~Query()
-{
- if (db.isNull())
- return;
-
- finalize();
- db->queries.removeOne(this);
-}
-
-template <class T>
-void AbstractDb2<T>::Query::copyErrorFromDb()
-{
- if (db->dbErrorCode != 0)
- {
- errorCode = db->dbErrorCode;
- errorMessage = db->dbErrorMessage;
- return;
- }
-}
-
-template <class T>
-void AbstractDb2<T>::Query::copyErrorToDb()
-{
- db->dbErrorCode = errorCode;
- db->dbErrorMessage = errorMessage;
-}
-
-template <class T>
-void AbstractDb2<T>::Query::setError(int code, const QString& msg)
-{
- if (errorCode != SQLITE_OK)
- return; // don't overwrite first error
-
- errorCode = code;
- errorMessage = msg;
- copyErrorToDb();
-}
-
-template <class T>
-int AbstractDb2<T>::Query::prepareStmt(const QString& processedQuery)
-{
- char* errMsg = nullptr;
- const char* tail;
- QByteArray queryBytes = processedQuery.toUtf8();
- QMutexLocker mutexLocker(db->dbOperMutex);
- int res = sqlite_compile(db->dbHandle, queryBytes.constData(), &tail, &stmt, &errMsg);
- if (res != SQLITE_OK)
- {
- finalize();
- if (errMsg)
- {
- setError(res, QString::fromUtf8((errMsg)));
- sqlite_freemem(errMsg);
- }
- return res;
- }
-
- if (tail && !QString::fromUtf8(tail).trimmed().isEmpty())
- qWarning() << "Executed query left with tailing contents:" << tail << ", while executing query:" << query;
-
- return SQLITE_OK;
-}
-
-template <class T>
-int AbstractDb2<T>::Query::resetStmt()
-{
- errorCode = 0;
- errorMessage = QString::null;
- affected = 0;
- colCount = -1;
- rowAvailable = false;
- nextRowValues.clear();
-
- char* errMsg = nullptr;
- QMutexLocker mutexLocker(db->dbOperMutex);
- int res = sqlite_reset(stmt, &errMsg);
- if (res != SQLITE_OK)
- {
- stmt = nullptr;
- if (errMsg)
- {
- setError(res, QString::fromUtf8((errMsg)));
- sqlite_freemem(errMsg);
- }
- return res;
- }
- return SQLITE_OK;
-}
-
-template <class T>
-bool AbstractDb2<T>::Query::execInternal(const QList<QVariant>& args)
-{
- if (!checkDbState())
- return false;
-
- QMutexLocker mutexLocker(db->dbOperMutex);
-
- logSql(db.data(), query, args, flags);
-
- int res;
- if (stmt)
- res = resetStmt();
- else
- res = prepareStmt(query);
-
- if (res != SQLITE_OK)
- return false;
-
- int maxParamIdx = args.size();
- if (!flags.testFlag(Db::Flag::SKIP_PARAM_COUNTING))
- {
- QueryWithParamCount queryWithParams = getQueryWithParamCount(query, Dialect::Sqlite2);
- maxParamIdx = qMin(maxParamIdx, queryWithParams.second);
- }
-
- for (int paramIdx = 1; paramIdx <= maxParamIdx; paramIdx++)
- {
- res = bindParam(paramIdx, args[paramIdx-1]);
- if (res != SQLITE_OK)
- return false;
- }
-
- bool ok = (fetchFirst() == SQLITE_OK);
- if (ok && !flags.testFlag(Db::Flag::SKIP_DROP_DETECTION))
- db->checkForDroppedObject(query);
-
- return ok;
-}
-
-template <class T>
-bool AbstractDb2<T>::Query::execInternal(const QHash<QString, QVariant>& args)
-{
- if (!checkDbState())
- return false;
-
- QMutexLocker mutexLocker(db->dbOperMutex);
-
- logSql(db.data(), query, args, flags);
-
- QueryWithParamNames queryWithParams = getQueryWithParamNames(query, Dialect::Sqlite2);
- QString singleStr = replaceNamedParams(queryWithParams.first);
-
- int res;
- if (stmt)
- res = resetStmt();
- else
- res = prepareStmt(singleStr);
-
- if (res != SQLITE_OK)
- return false;
-
- int paramIdx = 1;
- for (const QString& paramName : queryWithParams.second)
- {
- if (!args.contains(paramName))
- {
- setError(SqlErrorCode::OTHER_EXECUTION_ERROR, "Error while preparing statement: could not bind parameter " + paramName);
- return false;
- }
-
- res = bindParam(paramIdx++, args[paramName]);
- if (res != SQLITE_OK)
- return false;
- }
-
- bool ok = (fetchFirst() == SQLITE_OK);
- if (ok && !flags.testFlag(Db::Flag::SKIP_DROP_DETECTION))
- db->checkForDroppedObject(query);
-
- return ok;
-}
-
-template <class T>
-QString AbstractDb2<T>::Query::replaceNamedParams(const QString& query)
-{
- TokenList tokens = Lexer::tokenize(query, Dialect::Sqlite2);
- for (TokenPtr token : tokens)
- {
- if (token->type == Token::BIND_PARAM)
- token->value = "?";
- }
- return tokens.detokenize();
-}
-
-template <class T>
-int AbstractDb2<T>::Query::bindParam(int paramIdx, const QVariant& value)
-{
- if (value.isNull())
- return sqlite_bind(stmt, paramIdx, nullptr, 0, 0);
-
- switch (value.type())
- {
- case QVariant::ByteArray:
- {
- // NOTE: SQLite 2 has a bug that makes it impossible to write BLOB with nulls inside. First occurrance of the null
- // makes the whole value to be saved as truncated to that position. Nothing I can do about it.
- QByteArray ba = value.toByteArray();
- return sqlite_bind(stmt, paramIdx, ba.constData(), ba.size(), true);
- }
- default:
- {
- QByteArray ba = value.toString().toUtf8();
- ba.append('\0');
- return sqlite_bind(stmt, paramIdx, ba.constData(), ba.size(), true);
- }
- }
-
- qWarning() << "sqlite_bind() MISUSE";
- return SQLITE_MISUSE; // not going to happen
-}
-template <class T>
-QString AbstractDb2<T>::Query::getErrorText()
-{
- return errorMessage;
-}
-
-template <class T>
-int AbstractDb2<T>::Query::getErrorCode()
-{
- return errorCode;
-}
-
-template <class T>
-QStringList AbstractDb2<T>::Query::getColumnNames()
-{
- return colNames;
-}
-
-template <class T>
-int AbstractDb2<T>::Query::columnCount()
-{
- return colCount;
-}
-
-template <class T>
-qint64 AbstractDb2<T>::Query::rowsAffected()
-{
- return affected;
-}
-
-template <class T>
-SqlResultsRowPtr AbstractDb2<T>::Query::nextInternal()
-{
- if (!rowAvailable || db.isNull())
- return SqlResultsRowPtr();
-
- ReadWriteLocker locker(&(db->dbOperLock), query, Dialect::Sqlite2, flags.testFlag(Db::Flag::NO_LOCK));
-
- Row* row = new Row;
- row->init(colNames, nextRowValues);
-
- int res = fetchNext();
- if (res != SQLITE_OK)
- {
- delete row;
- return SqlResultsRowPtr();
- }
- return SqlResultsRowPtr(row);
-}
-
-template <class T>
-bool AbstractDb2<T>::Query::hasNextInternal()
-{
- return rowAvailable && stmt;
-}
-
-template <class T>
-int AbstractDb2<T>::Query::fetchFirst()
-{
- QMutexLocker mutexLocker(db->dbOperMutex);
- rowAvailable = true;
- int res = fetchNext();
- affected = 0;
- if (res == SQLITE_OK)
- {
- affected = sqlite_changes(db->dbHandle);
- insertRowId["ROWID"] = sqlite_last_insert_rowid(db->dbHandle);
- }
- return res;
-}
-
-template <class T>
-bool AbstractDb2<T>::Query::checkDbState()
-{
- if (db.isNull() || !db->dbHandle)
- {
- setError(SqlErrorCode::DB_NOT_DEFINED, "SqlQuery is no longer valid.");
- return false;
- }
-
- return true;
-}
-
-template <class T>
-QString AbstractDb2<T>::Query::finalize()
-{
- QString msg;
- if (stmt)
- {
- char* errMsg = nullptr;
- QMutexLocker mutexLocker(db->dbOperMutex);
- sqlite_finalize(stmt, &errMsg);
- stmt = nullptr;
- if (errMsg)
- {
- msg = QString::fromUtf8(errMsg);
- sqlite_freemem(errMsg);
- }
- }
- return msg;
-}
-
-template <class T>
-int AbstractDb2<T>::Query::fetchNext()
-{
- if (!checkDbState())
- rowAvailable = false;
-
- if (!rowAvailable || !stmt)
- {
- setError(SQLITE_MISUSE, QObject::tr("Result set expired or no row available."));
- return SQLITE_MISUSE;
- }
-
- rowAvailable = false;
-
- const char** values;
- const char** columns;
- int columnsCount;
-
- int res;
- int secondsSpent = 0;
- QMutexLocker mutexLocker(db->dbOperMutex);
- while ((res = sqlite_step(stmt, &columnsCount, &values, &columns)) == SQLITE_BUSY && secondsSpent < db->getTimeout())
- {
- QThread::sleep(1);
- if (db->getTimeout() >= 0)
- secondsSpent++;
- }
-
- switch (res)
- {
- case SQLITE_ROW:
- rowAvailable = true;
- break;
- case SQLITE_DONE:
- // Empty pointer as no more results are available.
- break;
- default:
- setError(res, finalize());
- return SQLITE_ERROR;
- }
-
- // First row, initialize members
- if (colCount == -1)
- init(columnsCount, columns);
-
- // Then read the next row data
- nextRowValues.clear();
- if (rowAvailable)
- {
- for (int i = 0; i < colCount; i++)
- {
- if (isBinaryColumn(i))
- nextRowValues << QByteArray(values[i]);
- else
- nextRowValues << QString::fromUtf8(values[i]);
- }
- }
-
- return SQLITE_OK;
-}
-
-template <class T>
-void AbstractDb2<T>::Query::init(int columnsCount, const char** columns)
-{
- colCount = columnsCount;
-
- TokenList columnDescription;
- for (int i = 0; i < colCount; i++)
- {
- columnDescription = Lexer::tokenize(QString::fromUtf8(columns[i]), Dialect::Sqlite2).filterWhiteSpaces();
- if (columnDescription.size() > 0)
- {
- // If the column is prefixed with dbname and table name, then we remove them.
- for (int j = 0; j < 2 &&columnDescription.size() > 1 && columnDescription[1]->type == Token::OPERATOR && columnDescription[1]->value == "."; j++)
- {
- columnDescription.removeFirst();
- columnDescription.removeFirst();
- }
-
- colNames << stripObjName(columnDescription.first()->value, Dialect::Sqlite2);
- }
- else
- colNames << "";
- }
-}
-
-//------------------------------------------------------------------------------------
-// Row
-//------------------------------------------------------------------------------------
-
-template <class T>
-void AbstractDb2<T>::Query::Row::init(const QStringList& columns, const QList<QVariant>& resultValues)
-{
- for (int i = 0; i < columns.size(); i++)
- {
- values << resultValues[i];
- valuesMap[columns[i]] = resultValues[i];
- }
-}
-
-#endif // ABSTRACTDB2_H