Torc  0.1
torcdb.cpp
Go to the documentation of this file.
1 /* Class TorcDB
2 *
3 * This file is part of the Torc project.
4 *
5 * Copyright (C) Mark Kendall 2012-18
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 * USA.
21 */
22 
23 // Qt
24 #include <QtSql>
25 #include <QThread>
26 #include <QHash>
27 
28 // Torc
29 #include "torclogging.h"
30 #include "torcdb.h"
31 
51 TorcDB::TorcDB(const QString &DatabaseName, const QString &DatabaseType)
52  : m_databaseValid(false),
53  m_databaseName(DatabaseName),
54  m_databaseType(DatabaseType),
55  m_lock(QMutex::Recursive),
56  m_connectionMap()
57 {
58 }
59 
61 {
62  QMutexLocker locker(&m_lock);
63  m_databaseValid = false;
65 }
66 
70 bool TorcDB::IsValid(void)
71 {
72  QMutexLocker locker(&m_lock);
73  return m_databaseValid;
74 }
75 
80 {
81  QMutexLocker locker(&m_lock);
82 
84 
85  if (m_connectionMap.isEmpty())
86  return;
87 
88  LOG(VB_GENERAL, LOG_WARNING, QStringLiteral("%1 open connections.").arg(m_connectionMap.size()));
89 
90  QHashIterator<QThread*,QString> it(m_connectionMap);
91  while (it.hasNext())
92  {
93  it.next();
94  QString name = it.value();
95  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Removing connection '%1'").arg(name));
96  QSqlDatabase::removeDatabase(name);
97  }
98  m_connectionMap.clear();
99 }
100 
105 {
106  QThread* thread = QThread::currentThread();
107  QMutexLocker locker(&m_lock);
108  if (m_connectionMap.contains(thread))
109  {
110  QString name = m_connectionMap.value(thread);
111  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("Removing connection '%1'").arg(name));
112  QSqlDatabase::removeDatabase(name);
113  m_connectionMap.remove(thread);
114  }
115 }
116 
126 {
127  QThread* thread = QThread::currentThread();
128 
129  {
130  QMutexLocker locker(&m_lock);
131  if (m_connectionMap.contains(thread))
132  return m_connectionMap.value(thread);
133  }
134 
135  if (thread->objectName().isEmpty())
136  {
137  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Database access is only available from TorcQThread"));
138  return QString();
139  }
140 
141  QString name = QStringLiteral("%1-%2").arg(thread->objectName(), QString::number((unsigned long long)thread));
142  QSqlDatabase newdb = QSqlDatabase::addDatabase(m_databaseType, name);
143 
144  if (m_databaseType == QStringLiteral("QSQLITE"))
145  newdb.setConnectOptions(QStringLiteral("QSQLITE_BUSY_TIMEOUT=1"));
146  newdb.setDatabaseName(m_databaseName);
147 
148  {
149  QMutexLocker locker(&m_lock);
150  m_connectionMap.insert(thread, name);
151  LOG(VB_GENERAL, LOG_INFO, QStringLiteral("New connection '%1'").arg(name));
152  }
153 
154  return name;
155 }
156 
162 bool TorcDB::DebugError(QSqlQuery *Query)
163 {
164  if (!Query)
165  return true;
166 
167  QSqlError error = Query->lastError();
168 
169  if (error.type() == QSqlError::NoError)
170  return false;
171 
172  if (!error.databaseText().isEmpty())
173  {
174  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Database Error: %1")
175  .arg(error.databaseText()));
176  return true;
177  }
178 
179  if (!error.driverText().isEmpty())
180  {
181  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Driver Error: %1")
182  .arg(error.driverText()));
183  }
184 
185  return true;
186 }
187 
193 bool TorcDB::DebugError(QSqlDatabase *Database)
194 {
195  if (!Database)
196  return true;
197 
198  QSqlError error = Database->lastError();
199 
200  if (error.type() == QSqlError::NoError)
201  return false;
202 
203  if (!error.databaseText().isEmpty())
204  {
205  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Database Error: %1")
206  .arg(error.databaseText()));
207  return true;
208  }
209 
210  if (!error.driverText().isEmpty())
211  {
212  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Driver Error: %1")
213  .arg(error.driverText()));
214  }
215 
216  return true;
217 }
218 
229 void TorcDB::LoadSettings(QMap<QString, QString> &Settings)
230 {
231  QMutexLocker locker(&m_lock);
232  QSqlDatabase db = QSqlDatabase::database(GetThreadConnection());
233  DebugError(&db);
234  if (!db.isValid() || !db.isOpen())
235  return;
236 
237  QSqlQuery query(QStringLiteral("SELECT name, value from settings;"), db);
238  DebugError(&query);
239 
240  while (query.next())
241  {
242  LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral("'%1' : '%2'").arg(query.value(0).toString(), query.value(1).toString()));
243  Settings.insert(query.value(0).toString(), query.value(1).toString());
244  }
245 }
246 
250 void TorcDB::SetSetting(const QString &Name, const QString &Value)
251 {
252  QMutexLocker locker(&m_lock);
253  if (Name.isEmpty())
254  return;
255 
256  QSqlDatabase db = QSqlDatabase::database(GetThreadConnection());
257  DebugError(&db);
258  if (!db.isValid() || !db.isOpen())
259  {
260  LOG(VB_GENERAL, LOG_ERR, QStringLiteral("Failed to open database connection."));
261  return;
262  }
263 
264  QSqlQuery query(db);
265  query.prepare(QStringLiteral("DELETE FROM settings where name=:NAME;"));
266  query.bindValue(QStringLiteral(":NAME"), Name);
267  query.exec();
268  DebugError(&query);
269 
270  query.prepare(QStringLiteral("INSERT INTO settings (name, value) VALUES (:NAME, :VALUE);"));
271  query.bindValue(QStringLiteral(":NAME"), Name);
272  query.bindValue(QStringLiteral(":VALUE"), Value);
273  query.exec();
274  DebugError(&query);
275 }
TorcDB(const QString &DatabaseName, const QString &DatabaseType)
Definition: torcdb.cpp:51
bool IsValid(void)
Returns true if the datbase has been opened/created.
Definition: torcdb.cpp:70
void CloseThreadConnection(void)
Close the database connection for the current thread.
Definition: torcdb.cpp:104
QString GetThreadConnection(void)
Retrieve a database connection for the current thread.
Definition: torcdb.cpp:125
QMutex m_lock
Definition: torcdb.h:34
QString m_databaseType
Definition: torcdb.h:33
QHash< QThread *, QString > m_connectionMap
Definition: torcdb.h:35
bool m_databaseValid
Definition: torcdb.h:31
QString m_databaseName
Definition: torcdb.h:32
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: torclogging.h:20
virtual ~TorcDB()
Definition: torcdb.cpp:60
void CloseConnections(void)
Close all cached database connections.
Definition: torcdb.cpp:79
void SetSetting(const QString &Name, const QString &Value)
Set the setting Name to the value Value.
Definition: torcdb.cpp:250
void LoadSettings(QMap< QString, QString > &Settings)
Retrieve all persistent settings stored in the database.
Definition: torcdb.cpp:229
static bool DebugError(QSqlQuery *Query)
Log database errors following a failed query.
Definition: torcdb.cpp:162