mirror of
https://invent.kde.org/network/falkon.git
synced 2024-12-20 10:46:35 +01:00
[SqlDatabase] New class allowing to exec Sql queries in separate thread
It uses its own QSqlDatabase connection, which is supported according to docs.
This commit is contained in:
parent
16ff847a8b
commit
167ae2af50
@ -32,6 +32,7 @@
|
||||
#include "rssmanager.h"
|
||||
#include "proxystyle.h"
|
||||
#include "pluginproxy.h"
|
||||
#include "sqldatabase.h"
|
||||
#include "iconprovider.h"
|
||||
#include "browserwindow.h"
|
||||
#include "cookiemanager.h"
|
||||
@ -271,6 +272,7 @@ MainApplication::~MainApplication()
|
||||
delete m_bookmarks;
|
||||
delete m_cookieJar;
|
||||
|
||||
SqlDatabase::destroy();
|
||||
IconProvider::instance()->saveIconsToDatabase();
|
||||
}
|
||||
|
||||
|
@ -250,7 +250,7 @@ void ProfileManager::connectDatabase()
|
||||
|
||||
// Reconnect
|
||||
if (m_databaseConnected) {
|
||||
QSqlDatabase::removeDatabase(QLatin1String("qt_sql_default_connection"));
|
||||
QSqlDatabase::removeDatabase(QSqlDatabase::database().connectionName());
|
||||
}
|
||||
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"));
|
||||
|
@ -260,7 +260,8 @@ SOURCES += \
|
||||
history/historymenu.cpp \
|
||||
app/datapaths.cpp \
|
||||
app/profilemanager.cpp \
|
||||
app/mainmenu.cpp
|
||||
app/mainmenu.cpp \
|
||||
tools/sqldatabase.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
@ -461,7 +462,8 @@ HEADERS += \
|
||||
history/historymenu.h \
|
||||
app/datapaths.h \
|
||||
app/profilemanager.h \
|
||||
app/mainmenu.h
|
||||
app/mainmenu.h \
|
||||
tools/sqldatabase.h
|
||||
|
||||
FORMS += \
|
||||
preferences/autofillmanager.ui \
|
||||
|
187
src/lib/tools/sqldatabase.cpp
Normal file
187
src/lib/tools/sqldatabase.cpp
Normal file
@ -0,0 +1,187 @@
|
||||
/* ============================================================
|
||||
* QupZilla - WebKit based browser
|
||||
* Copyright (C) 2014 David Rosca <nowrep@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */
|
||||
#include "sqldatabase.h"
|
||||
|
||||
#include <QMetaMethod>
|
||||
|
||||
#define CONNECTION_NAME QSL("QupZilla::DatabaseWorker")
|
||||
|
||||
SqlDatabase* SqlDatabase::s_instance = 0;
|
||||
|
||||
// SqlDatabase
|
||||
SqlDatabase::SqlDatabase(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
qRegisterMetaType<QSqlQuery>("QSqlQuery");
|
||||
|
||||
m_worker = new DatabaseWorker;
|
||||
m_thread = new DatabaseWorkerThread(m_worker);
|
||||
m_worker->moveToThread(m_thread);
|
||||
m_thread->start();
|
||||
|
||||
connect(m_thread, SIGNAL(started()), m_worker, SLOT(threadStarted()));
|
||||
}
|
||||
|
||||
SqlDatabase::~SqlDatabase()
|
||||
{
|
||||
m_thread->exit();
|
||||
m_thread->wait();
|
||||
|
||||
delete m_thread;
|
||||
delete m_worker;
|
||||
}
|
||||
|
||||
void SqlDatabase::execAsync(const QSqlQuery &query, QObject* receiver, const char* slot)
|
||||
{
|
||||
m_worker->execQueryAsync(query, receiver, slot);
|
||||
}
|
||||
|
||||
void SqlDatabase::transactionAsync(const QList<QSqlQuery> &queries)
|
||||
{
|
||||
m_worker->transactionAsync(queries);
|
||||
}
|
||||
|
||||
SqlDatabase* SqlDatabase::instance()
|
||||
{
|
||||
if (!s_instance) {
|
||||
s_instance = new SqlDatabase;
|
||||
}
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
void SqlDatabase::destroy()
|
||||
{
|
||||
delete s_instance;
|
||||
s_instance = 0;
|
||||
}
|
||||
|
||||
// DatabaseWorker
|
||||
DatabaseWorker::DatabaseWorker()
|
||||
: QObject()
|
||||
, m_started(false)
|
||||
{
|
||||
}
|
||||
|
||||
void DatabaseWorker::execQueryAsync(const QSqlQuery &query, QObject* receiver, const char* slot)
|
||||
{
|
||||
QueryData data;
|
||||
data.queries.append(query);
|
||||
data.receiver = receiver;
|
||||
data.slot = slot;
|
||||
|
||||
m_queries.enqueue(data);
|
||||
|
||||
if (m_started) {
|
||||
QMetaObject::invokeMethod(this, "execPendingQueries", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseWorker::transactionAsync(const QList<QSqlQuery> &queries)
|
||||
{
|
||||
QueryData data;
|
||||
data.queries = queries;
|
||||
data.receiver = 0;
|
||||
data.slot = 0;
|
||||
|
||||
m_queries.enqueue(data);
|
||||
|
||||
if (m_started) {
|
||||
QMetaObject::invokeMethod(this, "execPendingQueries", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
bool DatabaseWorker::hasPendingQueries() const
|
||||
{
|
||||
return !m_queries.isEmpty();
|
||||
}
|
||||
|
||||
void DatabaseWorker::threadStarted()
|
||||
{
|
||||
m_started = true;
|
||||
|
||||
QSqlDatabase::cloneDatabase(QSqlDatabase::database(), CONNECTION_NAME);
|
||||
m_db = QSqlDatabase::database(CONNECTION_NAME);
|
||||
|
||||
// Execute queries that got queued before starting thread
|
||||
if (hasPendingQueries()) {
|
||||
QMetaObject::invokeMethod(this, "execPendingQueries", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
static QSqlQuery copyQueryToDatabase(const QSqlQuery &query, const QSqlDatabase &db)
|
||||
{
|
||||
QSqlQuery out(db);
|
||||
out.prepare(query.lastQuery());
|
||||
|
||||
const QList<QVariant> boundValues = query.boundValues().values();
|
||||
|
||||
foreach (const QVariant &variant, boundValues) {
|
||||
out.addBindValue(variant);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void DatabaseWorker::execPendingQueries()
|
||||
{
|
||||
while (hasPendingQueries()) {
|
||||
QueryData data = m_queries.dequeue();
|
||||
|
||||
Q_ASSERT(!data.queries.isEmpty());
|
||||
|
||||
// Transaction
|
||||
if (data.queries.size() > 1) {
|
||||
m_db.transaction();
|
||||
foreach (const QSqlQuery &q, data.queries) {
|
||||
QSqlQuery query = copyQueryToDatabase(q, m_db);
|
||||
query.exec();
|
||||
}
|
||||
m_db.commit();
|
||||
}
|
||||
// Single query
|
||||
else {
|
||||
QSqlQuery query = copyQueryToDatabase(data.queries.takeFirst(), m_db);
|
||||
query.exec();
|
||||
|
||||
// Invoke connected slot
|
||||
if (data.receiver) {
|
||||
// SLOT() macro is prepending a "1" to the slot signature
|
||||
int index = data.receiver->metaObject()->indexOfMethod(QMetaObject::normalizedSignature(data.slot + 1));
|
||||
Q_ASSERT(index >= 0);
|
||||
QMetaMethod method = data.receiver->metaObject()->method(index);
|
||||
method.invoke(data.receiver, Qt::QueuedConnection, Q_ARG(QSqlQuery, query));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DatabaseWorkerThread
|
||||
DatabaseWorkerThread::DatabaseWorkerThread(DatabaseWorker* worker)
|
||||
: QThread()
|
||||
, m_worker(worker)
|
||||
{
|
||||
}
|
||||
|
||||
void DatabaseWorkerThread::run()
|
||||
{
|
||||
exec();
|
||||
|
||||
if (m_worker->hasPendingQueries()) {
|
||||
m_worker->execPendingQueries();
|
||||
}
|
||||
}
|
101
src/lib/tools/sqldatabase.h
Normal file
101
src/lib/tools/sqldatabase.h
Normal file
@ -0,0 +1,101 @@
|
||||
/* ============================================================
|
||||
* QupZilla - WebKit based browser
|
||||
* Copyright (C) 2014 David Rosca <nowrep@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */
|
||||
#ifndef SQLDATABASE_H
|
||||
#define SQLDATABASE_H
|
||||
|
||||
#include <QQueue>
|
||||
#include <QThread>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
#include "qzcommon.h"
|
||||
|
||||
class QThread;
|
||||
class QSqlQuery;
|
||||
|
||||
class DatabaseWorker;
|
||||
class DatabaseWorkerThread;
|
||||
|
||||
// Queries are executed in FIFO order
|
||||
class QUPZILLA_EXPORT SqlDatabase : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SqlDatabase(QObject* parent = 0);
|
||||
~SqlDatabase();
|
||||
|
||||
// Executes query async and send result if receiver is not null.
|
||||
// Slot must have "name(QSqlQuery)" signature
|
||||
void execAsync(const QSqlQuery &query, QObject* receiver = 0, const char* slot = 0);
|
||||
|
||||
// Executes transaction async without sending result
|
||||
void transactionAsync(const QList<QSqlQuery> &queries);
|
||||
|
||||
// May be called only after creating QSqlDatabase connection in main thread
|
||||
static SqlDatabase* instance();
|
||||
// Must be called before closing main thread QSqlDatabase connection
|
||||
static void destroy();
|
||||
|
||||
private:
|
||||
DatabaseWorker* m_worker;
|
||||
DatabaseWorkerThread* m_thread;
|
||||
|
||||
static SqlDatabase* s_instance;
|
||||
};
|
||||
|
||||
class DatabaseWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DatabaseWorker();
|
||||
|
||||
void execQueryAsync(const QSqlQuery &query, QObject* receiver = 0, const char* slot = 0);
|
||||
void transactionAsync(const QList<QSqlQuery> &queries);
|
||||
|
||||
bool hasPendingQueries() const;
|
||||
|
||||
public slots:
|
||||
void threadStarted();
|
||||
void execPendingQueries();
|
||||
|
||||
private:
|
||||
struct QueryData {
|
||||
QList<QSqlQuery> queries;
|
||||
QObject* receiver;
|
||||
const char* slot;
|
||||
};
|
||||
|
||||
QQueue<QueryData> m_queries;
|
||||
QSqlDatabase m_db;
|
||||
bool m_started;
|
||||
};
|
||||
|
||||
class DatabaseWorkerThread : public QThread
|
||||
{
|
||||
public:
|
||||
explicit DatabaseWorkerThread(DatabaseWorker* worker);
|
||||
|
||||
private:
|
||||
void run();
|
||||
|
||||
DatabaseWorker* m_worker;
|
||||
};
|
||||
|
||||
#endif // SQLDATABASE_H
|
Loading…
Reference in New Issue
Block a user