-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathQueryWorker.cpp
More file actions
101 lines (88 loc) · 2.87 KB
/
Copy pathQueryWorker.cpp
File metadata and controls
101 lines (88 loc) · 2.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "QueryWorker.h"
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QUuid>
namespace {
// Register the cross-thread signal payload type once, the first time a
// worker is constructed. Needed because QVector<QStringList> isn't one
// of Qt's built-in meta types, and queued connections (which is what a
// cross-thread signal/slot always uses) require every argument type to
// be registered with the meta-object system.
void registerResultRowsMetaType()
{
static const int registered = qRegisterMetaType<ResultRows>("ResultRows");
Q_UNUSED(registered);
}
} // namespace
QueryWorker::QueryWorker(QString dbPath, QObject* parent)
: QObject(parent)
, m_dbPath(std::move(dbPath))
// Each QSqlDatabase connection is identified by a global name; a
// per-worker UUID keeps this from colliding with the GUI thread's
// own connection (or with any other worker's, if one is ever
// created while an old one is still shutting down).
, m_connectionName("query_worker_" + QUuid::createUuid().toString(QUuid::WithoutBraces))
{
registerResultRowsMetaType();
}
QueryWorker::~QueryWorker()
{
if (m_connected) {
// The QSqlDatabase handle must be released before removeDatabase()
// is called, or Qt will warn about it still being in use - the
// extra scope makes sure db goes out of scope first.
{
QSqlDatabase db = QSqlDatabase::database(m_connectionName);
db.close();
}
QSqlDatabase::removeDatabase(m_connectionName);
}
}
bool QueryWorker::ensureConnected()
{
if (m_connected) {
return true;
}
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", m_connectionName);
db.setDatabaseName(m_dbPath);
if (!db.open()) {
emit failed(db.lastError().text());
return false;
}
m_connected = true;
return true;
}
void QueryWorker::execute(const QString& sql)
{
if (!ensureConnected()) {
return;
}
QSqlQuery query(QSqlDatabase::database(m_connectionName));
if (!query.exec(sql)) {
emit failed(query.lastError().text());
return;
}
// Copy everything out of QSqlQuery into plain strings before
// crossing back to the GUI thread - the query object itself is
// bound to this thread's connection and must not be touched from
// MainWindow.
const QSqlRecord record = query.record();
const int columnCount = record.count();
QStringList headers;
headers.reserve(columnCount);
for (int c = 0; c < columnCount; ++c) {
headers << record.fieldName(c);
}
ResultRows rows;
while (query.next()) {
QStringList row;
row.reserve(columnCount);
for (int c = 0; c < columnCount; ++c) {
row << query.value(c).toString();
}
rows.push_back(row);
}
emit succeeded(headers, rows);
}