QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
QGCSqlHelper.cc
Go to the documentation of this file.
1#include "QGCSqlHelper.h"
2
3#include <QtCore/QLatin1Char>
4#include <QtCore/QStringLiteral>
5#include <QtSql/QSqlQuery>
6
7namespace QGCSqlHelper {
8
9QString escapeLikePattern(const QString& text)
10{
11 QString escaped = text;
12 escaped.replace(QLatin1Char('\\'), QStringLiteral("\\\\"));
13 escaped.replace(QLatin1Char('%'), QStringLiteral("\\%"));
14 escaped.replace(QLatin1Char('_'), QStringLiteral("\\_"));
15 return escaped;
16}
17
18QString placeholders(int n)
19{
20 if (n <= 0) {
21 return {};
22 }
23 QString out;
24 out.reserve((n * 2) - 1);
25 out += QLatin1Char('?');
26 for (int i = 1; i < n; ++i) {
27 out += QLatin1Char(',');
28 out += QLatin1Char('?');
29 }
30 return out;
31}
32
33void applySqlitePragmas(QSqlDatabase& db)
34{
35 QSqlQuery q(db);
36 q.exec(QStringLiteral("PRAGMA journal_mode=WAL"));
37 q.exec(QStringLiteral("PRAGMA synchronous=NORMAL"));
38 q.exec(QStringLiteral("PRAGMA foreign_keys=ON"));
39}
40
41std::optional<int> userVersion(QSqlDatabase& db)
42{
43 QSqlQuery q(db);
44 if (!q.exec(QStringLiteral("PRAGMA user_version")) || !q.next()) {
45 return std::nullopt;
46 }
47 return q.value(0).toInt();
48}
49
50bool setUserVersion(QSqlDatabase& db, int v)
51{
52 QSqlQuery q(db);
53 return q.exec(QStringLiteral("PRAGMA user_version = %1").arg(v));
54}
55
56// ── ScopedConnection ───────────────────────────────────────────────────
57
58std::atomic<int> ScopedConnection::s_connId{0};
59
60ScopedConnection::ScopedConnection(const QString& dbPath, bool readOnly, const QString& prefix)
61{
62 if (dbPath.isEmpty()) {
63 return;
64 }
65
66 _connName = QStringLiteral("%1_%2").arg(prefix).arg(s_connId.fetch_add(1));
67
68 QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), _connName);
69 db.setDatabaseName(dbPath);
70 if (readOnly) {
71 db.setConnectOptions(QStringLiteral("QSQLITE_OPEN_READONLY"));
72 }
73
74 if (db.open()) {
76 _valid = true;
77 }
78}
79
81{
82 if (!_connName.isEmpty()) {
83 {
84 QSqlDatabase db = QSqlDatabase::database(_connName, false);
85 if (db.isOpen()) {
86 db.close();
87 }
88 }
89 QSqlDatabase::removeDatabase(_connName);
90 }
91}
92
93QSqlDatabase ScopedConnection::database() const
94{
95 return QSqlDatabase::database(_connName, false);
96}
97
98// ── Transaction ────────────────────────────────────────────────────────
99
100// QSqlDatabase is a shallow handle; pass by value so the caller's connection
101// remains valid for the transaction's lifetime regardless of caller scope.
102Transaction::Transaction(QSqlDatabase db) // NOLINT(performance-unnecessary-value-param)
103 : _db(db)
104 , _active(_db.transaction())
105{
106}
107
109{
110 if (_active && !_committed) {
111 _db.rollback();
112 }
113}
114
116{
117 if (!_active) {
118 return false;
119 }
120 _committed = _db.commit();
121 return _committed;
122}
123
124} // namespace QGCSqlHelper
QSqlDatabase database() const
ScopedConnection(const QString &dbPath, bool readOnly=false, const QString &prefix=QStringLiteral("QGCSql"))
Transaction(QSqlDatabase db)
Lightweight SQL utilities shared across QGC components.
bool setUserVersion(QSqlDatabase &db, int v)
QString escapeLikePattern(const QString &text)
void applySqlitePragmas(QSqlDatabase &db)
QString placeholders(int n)
std::optional< int > userVersion(QSqlDatabase &db)