File indexing completed on 2024-05-12 04:58:28

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2014-2018 David Rosca <nowrep@gmail.com>
0004 *
0005 * This program is free software: you can redistribute it and/or modify
0006 * it under the terms of the GNU General Public License as published by
0007 * the Free Software Foundation, either version 3 of the License, or
0008 * (at your option) any later version.
0009 *
0010 * This program is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 * GNU General Public License for more details.
0014 *
0015 * You should have received a copy of the GNU General Public License
0016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017 * ============================================================ */
0018 #include "sqldatabase.h"
0019 
0020 #include <QApplication>
0021 #include <QThreadStorage>
0022 #include <QFutureWatcher>
0023 #include <QtConcurrent/QtConcurrentRun>
0024 
0025 QThreadStorage<QSqlDatabase> s_databases;
0026 
0027 Q_GLOBAL_STATIC(SqlDatabase, qz_sql_database)
0028 
0029 // SqlQueryJob
0030 SqlQueryJob::SqlQueryJob(QObject *parent)
0031     : QObject(parent)
0032 {
0033 }
0034 
0035 SqlQueryJob::SqlQueryJob(const QString &query, QObject *parent)
0036     : QObject(parent)
0037 {
0038     setQuery(query);
0039 }
0040 
0041 void SqlQueryJob::setQuery(const QString &query)
0042 {
0043     m_query = query;
0044 }
0045 
0046 void SqlQueryJob::addBindValue(const QVariant &value)
0047 {
0048     m_boundValues.append(value);
0049 }
0050 
0051 QSqlError SqlQueryJob::error() const
0052 {
0053     return m_error;
0054 }
0055 
0056 QVariant SqlQueryJob::lastInsertId() const
0057 {
0058     return m_lastInsertId;
0059 }
0060 
0061 QVector<QSqlRecord> SqlQueryJob::records() const
0062 {
0063     return m_records;
0064 }
0065 
0066 void SqlQueryJob::start()
0067 {
0068     struct Result {
0069         QSqlError error;
0070         QVariant lastInsertId;
0071         QVector<QSqlRecord> records;
0072     };
0073 
0074     const QString query = m_query;
0075     m_query.clear();
0076     const QVector<QVariant> boundValues = m_boundValues;
0077     m_boundValues.clear();
0078 
0079     auto watcher = new QFutureWatcher<Result>(this);
0080     connect(watcher, &QFutureWatcher<Result>::finished, this, [=]() {
0081         deleteLater();
0082         const auto result = watcher->result();
0083         m_error = result.error;
0084         m_lastInsertId = result.lastInsertId;
0085         m_records = result.records;
0086         Q_EMIT finished(this);
0087     });
0088 
0089     watcher->setFuture(QtConcurrent::run([=]() {
0090         QSqlQuery q(SqlDatabase::instance()->database());
0091         q.prepare(query);
0092         for (const QVariant &value : boundValues) {
0093             q.addBindValue(value);
0094         }
0095         q.exec();
0096         Result res;
0097         res.error = q.lastError();
0098         res.lastInsertId = q.lastInsertId();
0099         while (q.next()) {
0100             res.records.append(q.record());
0101         }
0102         return res;
0103     }));
0104 }
0105 
0106 // SqlDatabase
0107 SqlDatabase::SqlDatabase(QObject* parent)
0108     : QObject(parent)
0109 {
0110 }
0111 
0112 SqlDatabase::~SqlDatabase()
0113 = default;
0114 
0115 QSqlDatabase SqlDatabase::database()
0116 {
0117     if (QThread::currentThread() == qApp->thread()) {
0118         return QSqlDatabase::database();
0119     }
0120 
0121     if (!s_databases.hasLocalData()) {
0122         const QString threadStr = QStringLiteral("Falkon/%1").arg((quintptr) QThread::currentThread());
0123         QSqlDatabase::removeDatabase(threadStr);
0124         QSqlDatabase db = QSqlDatabase::addDatabase(QSL("QSQLITE"), threadStr);
0125         db.setDatabaseName(m_databaseName);
0126         db.setConnectOptions(m_connectOptions);
0127         db.open();
0128         s_databases.setLocalData(db);
0129     }
0130 
0131     return s_databases.localData();
0132 }
0133 
0134 void SqlDatabase::setDatabase(const QSqlDatabase &database)
0135 {
0136     m_databaseName = database.databaseName();
0137     m_connectOptions = database.connectOptions();
0138 }
0139 
0140 // instance
0141 SqlDatabase* SqlDatabase::instance()
0142 {
0143     return qz_sql_database();
0144 }