MythTV  master
mythdb.cpp
Go to the documentation of this file.
1 #include <vector>
2 
3 #include <QReadWriteLock>
4 #include <QTextStream>
5 #include <QSqlError>
6 #include <QMutex>
7 #include <QFile>
8 #include <QHash>
9 #include <QDir>
10 #include <QRegularExpression>
11 
12 #include "mythdb.h"
13 #include "mythdbcon.h"
14 #include "mythlogging.h"
15 #include "mythdirs.h"
16 #include "mythcorecontext.h"
17 
18 static MythDB *mythdb = nullptr;
19 static QMutex dbLock;
20 
21 // For thread safety reasons this is not a QString
22 const char * const kSentinelValue { "<settings_sentinel_value>" };
23 const char * const kClearSettingValue { "<clear_setting_value>" };
24 
25 MythDB *MythDB::getMythDB(void)
26 {
27  if (mythdb)
28  return mythdb;
29 
30  dbLock.lock();
31  if (!mythdb)
32  mythdb = new MythDB();
33  dbLock.unlock();
34 
35  return mythdb;
36 }
37 
39 {
40  dbLock.lock();
41  delete mythdb;
42  mythdb = nullptr;
43  dbLock.unlock();
44 }
45 
46 MythDB *GetMythDB(void)
47 {
48  return MythDB::getMythDB();
49 }
50 
51 void DestroyMythDB(void)
52 {
54 }
55 
57 {
58  QString m_key;
59  QString m_value;
60  QString m_host;
61 };
62 
63 using SettingsMap = QHash<QString,QString>;
64 
66 {
67  public:
68  MythDBPrivate();
70 
72  QString m_localhostname;
74 
75  bool m_ignoreDatabase {false};
76  bool m_suppressDBMessages {true};
77 
78  QReadWriteLock m_settingsCacheLock;
79  volatile bool m_useSettingsCache {false};
86  QList<SingleSetting> m_delayedSettings;
87 
88  bool m_haveDBConnection {false};
89  bool m_haveSchema {false};
90 };
91 
92 static const int settings_reserve = 61;
93 
95 {
96  m_localhostname.clear();
98 }
99 
101 {
102  LOG(VB_DATABASE, LOG_INFO, "Destroying MythDBPrivate");
103 }
104 
106 {
107  d = new MythDBPrivate();
108 }
109 
111 {
112  delete d;
113 }
114 
116 {
117  return &(d->m_dbmanager);
118 }
119 
120 QString MythDB::toCommaList(const QMap<QString, QVariant> &bindings,
121  uint indent, uint maxColumn)
122 {
123  QMap<QString, QVariant>::const_iterator it = bindings.begin();
124  if (it == bindings.end())
125  return "";
126 
127  uint curColumn = indent;
128  QString str = QString("%1").arg("", indent);
129  for (; it != bindings.end(); ++it)
130  {
131  QString val = (*it).toString();
132  if ((*it).isNull())
133  {
134  val = "NULL";
135  }
136  else if (it->type() == QVariant::String)
137  {
138  val = (it->toString().isNull()) ?
139  "NULL" : QString("\"%1\"").arg(val);
140  }
141  const QString curBinding = it.key() + '=' + val + ',';
142  if ((curColumn > indent) &&
143  ((curBinding.length() + curColumn) > maxColumn))
144  {
145  str += '\n';
146  str += QString("%1").arg("", indent);
147  curColumn = indent;
148  }
149  if (curColumn > indent)
150  {
151  str += ' ';
152  curColumn++;
153  }
154  str += curBinding;
155  curColumn += curBinding.length();
156  }
157  str = str.left(str.length() - 1); // remove trailing comma.
158  str += '\n';
159 
160  return str;
161 }
162 
163 QString MythDB::GetError(const QString &where, const MSqlQuery &query)
164 {
165  QString str = QString("DB Error (%1):\n").arg(where);
166 
167  str += "Query was:\n";
168  str += query.executedQuery() + '\n';
169 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
170  QString tmp = toCommaList(query.boundValues());
171 #else
172  QVariantList numberedBindings = query.boundValues();
173  QMap<QString, QVariant> namedBindings;
174  static const QRegularExpression placeholders { "(:\\w+)" };
175  auto iter = placeholders.globalMatch(str);
176  while (iter.hasNext())
177  {
178  auto match = iter.next();
179  namedBindings[match.captured()] = numberedBindings.isEmpty()
180  ? QString("INVALID")
181  : numberedBindings.takeFirst();
182  }
183  QString tmp = toCommaList(namedBindings);
184 #endif
185  if (!tmp.isEmpty())
186  {
187  str += "Bindings were:\n";
188  str += tmp;
189  }
190  str += DBErrorMessage(query.lastError());
191  return str;
192 }
193 
194 void MythDB::DBError(const QString &where, const MSqlQuery &query)
195 {
196  LOG(VB_GENERAL, LOG_ERR, GetError(where, query));
197 }
198 
199 QString MythDB::DBErrorMessage(const QSqlError& err)
200 {
201  if (!err.type())
202  return "No error type from QSqlError? Strange...";
203 
204  return QString("Driver error was [%1/%2]:\n"
205  "%3\n"
206  "Database error was:\n"
207  "%4\n")
208  .arg(err.type())
209  .arg(err.nativeErrorCode())
210  .arg(err.driverText())
211  .arg(err.databaseText());
212 }
213 
215 {
216  return d->m_dbParams;
217 }
218 
220 {
221  d->m_dbParams = params;
222 }
223 
224 void MythDB::SetLocalHostname(const QString &name)
225 {
226  if (d->m_localhostname != name.toLower())
227  {
228  d->m_localhostname = name.toLower();
230  }
231 }
232 
233 QString MythDB::GetHostName(void) const
234 {
235  return d->m_localhostname;
236 }
237 
238 void MythDB::IgnoreDatabase(bool bIgnore)
239 {
240  d->m_ignoreDatabase = bIgnore;
241 }
242 
244 {
245  return d->m_ignoreDatabase;
246 }
247 
248 void MythDB::SetSuppressDBMessages(bool bUpgraded)
249 {
250  d->m_suppressDBMessages = bUpgraded;
251 }
252 
254 {
255  return d->m_suppressDBMessages;
256 }
257 
258 void MythDB::SaveSetting(const QString &key, int newValue)
259 {
260  (void) SaveSettingOnHost(key,
261  QString::number(newValue), d->m_localhostname);
262 }
263 
264 void MythDB::SaveSetting(const QString &key, const QString &newValue)
265 {
266  (void) SaveSettingOnHost(key, newValue, d->m_localhostname);
267 }
268 
269 bool MythDB::SaveSettingOnHost(const QString &key,
270  const QString &newValueRaw,
271  const QString &host)
272 {
273  QString loc = QString("SaveSettingOnHost('%1') ").arg(key);
274  if (key.isEmpty())
275  {
276  LOG(VB_GENERAL, LOG_ERR, loc + "- Illegal null key");
277  return false;
278  }
279 
280  QString newValue = (newValueRaw.isNull()) ? "" : newValueRaw;
281 
282  if (d->m_ignoreDatabase)
283  {
284  if (host.toLower() == d->m_localhostname)
285  {
286  if (newValue != kClearSettingValue)
287  OverrideSettingForSession(key, newValue);
288  else
289  ClearOverrideSettingForSession(key);
290  }
291  return true;
292  }
293 
294  if (!HaveValidDatabase()) // Bootstrapping without database?
295  {
296  if (host.toLower() == d->m_localhostname)
297  OverrideSettingForSession(key, newValue);
298  if (!d->m_suppressDBMessages)
299  LOG(VB_GENERAL, LOG_ERR, loc + "- No database yet");
300  SingleSetting setting;
301  setting.m_host = host;
302  setting.m_key = key;
303  setting.m_value = newValue;
304  d->m_delayedSettings.append(setting);
305  return false;
306  }
307 
308  bool success = false;
309 
310  MSqlQuery query(MSqlQuery::InitCon());
311  if (query.isConnected())
312  {
313 
314  if (!host.isEmpty())
315  {
316  query.prepare("DELETE FROM settings WHERE value = :KEY "
317  "AND hostname = :HOSTNAME ;");
318  }
319  else
320  {
321  query.prepare("DELETE FROM settings WHERE value = :KEY "
322  "AND hostname is NULL;");
323  }
324 
325  query.bindValue(":KEY", key);
326  if (!host.isEmpty())
327  query.bindValue(":HOSTNAME", host);
328 
329  if (!query.exec())
330  {
331  if (!GetMythDB()->SuppressDBMessages())
332  MythDB::DBError("Clear setting", query);
333  }
334  else
335  {
336  success = true;
337  }
338  }
339 
340  if (success && (newValue != kClearSettingValue))
341  {
342  if (!host.isEmpty())
343  {
344  query.prepare("INSERT INTO settings (value,data,hostname) "
345  "VALUES ( :VALUE, :DATA, :HOSTNAME );");
346  }
347  else
348  {
349  query.prepare("INSERT INTO settings (value,data ) "
350  "VALUES ( :VALUE, :DATA );");
351  }
352 
353  query.bindValue(":VALUE", key);
354  query.bindValue(":DATA", newValue);
355  if (!host.isEmpty())
356  query.bindValue(":HOSTNAME", host);
357 
358  if (!query.exec())
359  {
360  success = false;
361  if (!(GetMythDB()->SuppressDBMessages()))
362  MythDB::DBError(loc + "- query failure: ", query);
363  }
364  }
365  else if (!success)
366  {
367  LOG(VB_GENERAL, LOG_ERR, loc + "- database not open");
368  }
369 
370  ClearSettingsCache(host + ' ' + key);
371 
372  return success;
373 }
374 
375 bool MythDB::ClearSetting(const QString &key)
376 {
377  return ClearSettingOnHost(key, d->m_localhostname);
378 }
379 
380 bool MythDB::ClearSettingOnHost(const QString &key, const QString &host)
381 {
382  return SaveSettingOnHost(key, kClearSettingValue, host);
383 }
384 
385 QString MythDB::GetSetting(const QString &_key, const QString &defaultval)
386 {
387  QString key = _key.toLower();
388  QString value = defaultval;
389 
390  d->m_settingsCacheLock.lockForRead();
391  if (d->m_useSettingsCache)
392  {
393  SettingsMap::const_iterator it = d->m_settingsCache.constFind(key);
394  if (it != d->m_settingsCache.constEnd())
395  {
396  value = *it;
397  d->m_settingsCacheLock.unlock();
398  return value;
399  }
400  }
401  SettingsMap::const_iterator it = d->m_overriddenSettings.constFind(key);
402  if (it != d->m_overriddenSettings.constEnd())
403  {
404  value = *it;
405  d->m_settingsCacheLock.unlock();
406  return value;
407  }
408  d->m_settingsCacheLock.unlock();
409 
410  if (d->m_ignoreDatabase || !HaveValidDatabase())
411  return value;
412 
413  MSqlQuery query(MSqlQuery::InitCon());
414  if (!query.isConnected())
415  return value;
416 
417  query.prepare(
418  "SELECT data "
419  "FROM settings "
420  "WHERE value = :KEY AND hostname = :HOSTNAME");
421  query.bindValue(":KEY", key);
422  query.bindValue(":HOSTNAME", d->m_localhostname);
423 
424  if (query.exec() && query.next())
425  {
426  value = query.value(0).toString();
427  }
428  else
429  {
430  query.prepare(
431  "SELECT data "
432  "FROM settings "
433  "WHERE value = :KEY AND hostname IS NULL");
434  query.bindValue(":KEY", key);
435 
436  if (query.exec() && query.next())
437  {
438  value = query.value(0).toString();
439  }
440  }
441 
442  if (d->m_useSettingsCache && value != kSentinelValue)
443  {
444  key.squeeze();
445  value.squeeze();
446  d->m_settingsCacheLock.lockForWrite();
447  // another thread may have inserted a value into the cache
448  // while we did not have the lock, check first then save
449  if (d->m_settingsCache.find(key) == d->m_settingsCache.end())
450  d->m_settingsCache[key] = value;
451  d->m_settingsCacheLock.unlock();
452  }
453 
454  return value;
455 }
456 
457 bool MythDB::GetSettings(QMap<QString,QString> &_key_value_pairs)
458 {
459  QMap<QString,bool> done;
460  using KVIt = QMap<QString,QString>::iterator;
461  KVIt kvit = _key_value_pairs.begin();
462  for (; kvit != _key_value_pairs.end(); ++kvit)
463  done[kvit.key().toLower()] = false;
464 
465  QMap<QString,bool>::iterator dit = done.begin();
466  kvit = _key_value_pairs.begin();
467 
468  {
469  uint done_cnt = 0;
470  d->m_settingsCacheLock.lockForRead();
471  if (d->m_useSettingsCache)
472  {
473  for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
474  {
475  SettingsMap::const_iterator it = d->m_settingsCache.constFind(dit.key());
476  if (it != d->m_settingsCache.constEnd())
477  {
478  *kvit = *it;
479  *dit = true;
480  done_cnt++;
481  }
482  }
483  }
484  for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
485  {
486  SettingsMap::const_iterator it =
487  d->m_overriddenSettings.constFind(dit.key());
488  if (it != d->m_overriddenSettings.constEnd())
489  {
490  *kvit = *it;
491  *dit = true;
492  done_cnt++;
493  }
494  }
495  d->m_settingsCacheLock.unlock();
496 
497  // Avoid extra work if everything was in the caches and
498  // also don't try to access the DB if m_ignoreDatabase is set
499  if (((uint)done.size()) == done_cnt || d->m_ignoreDatabase)
500  return true;
501  }
502 
503  dit = done.begin();
504  kvit = _key_value_pairs.begin();
505 
506  QString keylist("");
507  QMap<QString,KVIt> keymap;
508  for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
509  {
510  if (*dit)
511  continue;
512 
513  const QString& key = dit.key();
514  if (!key.contains("'"))
515  {
516  keylist += QString("'%1',").arg(key);
517  keymap[key] = kvit;
518  }
519  else
520  { // hopefully no one actually uses quotes for in a settings key.
521  // but in case they do, just get that value inefficiently..
522  *kvit = GetSetting(key, *kvit);
523  }
524  }
525 
526  if (keylist.isEmpty())
527  return true;
528 
529  keylist = keylist.left(keylist.length() - 1);
530 
531  MSqlQuery query(MSqlQuery::InitCon());
532  if (!query.exec(
533  QString(
534  "SELECT value, data, hostname "
535  "FROM settings "
536  "WHERE (hostname = '%1' OR hostname IS NULL) AND "
537  " value IN (%2) "
538  "ORDER BY hostname DESC")
539  .arg(d->m_localhostname).arg(keylist)))
540  {
541  if (!d->m_suppressDBMessages)
542  DBError("GetSettings", query);
543  return false;
544  }
545 
546  while (query.next())
547  {
548  QString key = query.value(0).toString().toLower();
549  QMap<QString,KVIt>::const_iterator it = keymap.constFind(key);
550  if (it != keymap.constEnd())
551  **it = query.value(1).toString();
552  }
553 
554  if (d->m_useSettingsCache)
555  {
556  d->m_settingsCacheLock.lockForWrite();
557  for (auto it = keymap.cbegin(); it != keymap.cend(); ++it)
558  {
559  QString key = it.key();
560  QString value = **it;
561 
562  // another thread may have inserted a value into the cache
563  // while we did not have the lock, check first then save
564  if (d->m_settingsCache.find(key) == d->m_settingsCache.end())
565  {
566  key.squeeze();
567  value.squeeze();
568  d->m_settingsCache[key] = value;
569  }
570  }
571  d->m_settingsCacheLock.unlock();
572  }
573 
574  return true;
575 }
576 
577 
578 bool MythDB::GetBoolSetting(const QString &key, bool defaultval)
579 {
580  QString val = QString::number(static_cast<int>(defaultval));
581  QString retval = GetSetting(key, val);
582 
583  return retval.toInt() > 0;
584 }
585 
586 int MythDB::GetNumSetting(const QString &key, int defaultval)
587 {
588  QString val = QString::number(defaultval);
589  QString retval = GetSetting(key, val);
590 
591  return retval.toInt();
592 }
593 
594 double MythDB::GetFloatSetting(const QString &key, double defaultval)
595 {
596  QString val = QString::number(defaultval);
597  QString retval = GetSetting(key, val);
598 
599  return retval.toDouble();
600 }
601 
602 QString MythDB::GetSetting(const QString &key)
603 {
604  QString sentinel = QString(kSentinelValue);
605  QString retval = GetSetting(key, sentinel);
606  return (retval == sentinel) ? "" : retval;
607 }
608 
609 bool MythDB::GetBoolSetting(const QString &key)
610 {
611  QString sentinel = QString(kSentinelValue);
612  QString retval = GetSetting(key, sentinel);
613  if (retval == sentinel)
614  return false;
615  return retval.toInt() > 0;
616 }
617 
618 int MythDB::GetNumSetting(const QString &key)
619 {
620  QString sentinel = QString(kSentinelValue);
621  QString retval = GetSetting(key, sentinel);
622  return (retval == sentinel) ? 0 : retval.toInt();
623 }
624 
625 double MythDB::GetFloatSetting(const QString &key)
626 {
627  QString sentinel = QString(kSentinelValue);
628  QString retval = GetSetting(key, sentinel);
629  return (retval == sentinel) ? 0.0 : retval.toDouble();
630 }
631 
632 QString MythDB::GetSettingOnHost(const QString &_key, const QString &_host,
633  const QString &defaultval)
634 {
635  QString key = _key.toLower();
636  QString host = _host.toLower();
637  QString value = defaultval;
638  QString myKey = host + ' ' + key;
639 
640  d->m_settingsCacheLock.lockForRead();
641  if (d->m_useSettingsCache)
642  {
643  SettingsMap::const_iterator it = d->m_settingsCache.constFind(myKey);
644  if (it != d->m_settingsCache.constEnd())
645  {
646  value = *it;
647  d->m_settingsCacheLock.unlock();
648  return value;
649  }
650  }
651  SettingsMap::const_iterator it = d->m_overriddenSettings.constFind(myKey);
652  if (it != d->m_overriddenSettings.constEnd())
653  {
654  value = *it;
655  d->m_settingsCacheLock.unlock();
656  return value;
657  }
658  d->m_settingsCacheLock.unlock();
659 
660  if (d->m_ignoreDatabase)
661  return value;
662 
663  MSqlQuery query(MSqlQuery::InitCon());
664  if (!query.isConnected())
665  {
666  if (!d->m_suppressDBMessages)
667  {
668  LOG(VB_GENERAL, LOG_ERR,
669  QString("Database not open while trying to "
670  "load setting: %1").arg(key));
671  }
672  return value;
673  }
674 
675  query.prepare(
676  "SELECT data "
677  "FROM settings "
678  "WHERE value = :VALUE AND hostname = :HOSTNAME");
679  query.bindValue(":VALUE", key);
680  query.bindValue(":HOSTNAME", host);
681 
682  if (query.exec() && query.next())
683  {
684  value = query.value(0).toString();
685  }
686 
687  if (d->m_useSettingsCache && value != kSentinelValue)
688  {
689  myKey.squeeze();
690  value.squeeze();
691  d->m_settingsCacheLock.lockForWrite();
692  if (d->m_settingsCache.find(myKey) == d->m_settingsCache.end())
693  d->m_settingsCache[myKey] = value;
694  d->m_settingsCacheLock.unlock();
695  }
696 
697  return value;
698 }
699 
700 int MythDB::GetNumSettingOnHost(const QString &key, const QString &host,
701  int defaultval)
702 {
703  QString val = QString::number(defaultval);
704  QString retval = GetSettingOnHost(key, host, val);
705 
706  return retval.toInt();
707 }
708 
710  const QString &key, const QString &host, double defaultval)
711 {
712  QString val = QString::number(defaultval);
713  QString retval = GetSettingOnHost(key, host, val);
714 
715  return retval.toDouble();
716 }
717 
718 QString MythDB::GetSettingOnHost(const QString &key, const QString &host)
719 {
720  QString sentinel = QString(kSentinelValue);
721  QString retval = GetSettingOnHost(key, host, sentinel);
722  return (retval == sentinel) ? "" : retval;
723 }
724 
725 int MythDB::GetNumSettingOnHost(const QString &key, const QString &host)
726 {
727  QString sentinel = QString(kSentinelValue);
728  QString retval = GetSettingOnHost(key, host, sentinel);
729  return (retval == sentinel) ? 0 : retval.toInt();
730 }
731 
732 double MythDB::GetFloatSettingOnHost(const QString &key, const QString &host)
733 {
734  QString sentinel = QString(kSentinelValue);
735  QString retval = GetSettingOnHost(key, host, sentinel);
736  return (retval == sentinel) ? 0.0 : retval.toDouble();
737 }
738 
739 void MythDB::GetResolutionSetting(const QString &type,
740  int &width, int &height,
741  double &forced_aspect,
742  double &refresh_rate,
743  int index)
744 {
745  bool ok = false;
746  bool ok0 = false;
747  bool ok1 = false;
748  QString sRes = QString("%1Resolution").arg(type);
749  QString sRR = QString("%1RefreshRate").arg(type);
750  QString sAspect = QString("%1ForceAspect").arg(type);
751  QString sWidth = QString("%1Width").arg(type);
752  QString sHeight = QString("%1Height").arg(type);
753  if (index >= 0)
754  {
755  sRes = QString("%1Resolution%2").arg(type).arg(index);
756  sRR = QString("%1RefreshRate%2").arg(type).arg(index);
757  sAspect = QString("%1ForceAspect%2").arg(type).arg(index);
758  sWidth = QString("%1Width%2").arg(type).arg(index);
759  sHeight = QString("%1Height%2").arg(type).arg(index);
760  }
761 
762  QString res = GetSetting(sRes);
763 
764  if (!res.isEmpty())
765  {
766  QStringList slist = res.split(QString("x"));
767  int w = width;
768  int h = height;
769  if (2 == slist.size())
770  {
771  w = slist[0].toInt(&ok0);
772  h = slist[1].toInt(&ok1);
773  }
774  ok = ok0 && ok1;
775  if (ok)
776  {
777  width = w;
778  height = h;
779  refresh_rate = GetFloatSetting(sRR);
780  forced_aspect = GetFloatSetting(sAspect);
781  }
782  }
783 
784  if (!ok)
785  {
786  int tmpWidth = GetNumSetting(sWidth, width);
787  if (tmpWidth)
788  width = tmpWidth;
789 
790  int tmpHeight = GetNumSetting(sHeight, height);
791  if (tmpHeight)
792  height = tmpHeight;
793 
794  refresh_rate = 0.0;
795  forced_aspect = 0.0;
796  //SetSetting(sRes, QString("%1x%2").arg(width).arg(height));
797  }
798 }
799 
800 void MythDB::GetResolutionSetting(const QString &t, int &w, int &h, int i)
801 {
802  double forced_aspect = 0;
803  double refresh_rate = 0.0;
804  GetResolutionSetting(t, w, h, forced_aspect, refresh_rate, i);
805 }
806 
807 
815  const QString &key, const QString &value)
816 {
817  QString mk = key.toLower();
818  QString mk2 = d->m_localhostname + ' ' + mk;
819  QString mv = value;
820  if ("dbschemaver" == mk)
821  {
822  LOG(VB_GENERAL, LOG_ERR,
823  QString("ERROR: Refusing to allow override for '%1'.").arg(key));
824  return;
825  }
826  mk.squeeze();
827  mk2.squeeze();
828  mv.squeeze();
829 
830  d->m_settingsCacheLock.lockForWrite();
831  d->m_overriddenSettings[mk] = mv;
832  d->m_settingsCache[mk] = mv;
833  d->m_settingsCache[mk2] = mv;
834  d->m_settingsCacheLock.unlock();
835 }
836 
839 {
840  QString mk = key.toLower();
841  QString mk2 = d->m_localhostname + ' ' + mk;
842 
843  d->m_settingsCacheLock.lockForWrite();
844 
845  SettingsMap::iterator oit = d->m_overriddenSettings.find(mk);
846  if (oit != d->m_overriddenSettings.end())
847  d->m_overriddenSettings.erase(oit);
848 
849  SettingsMap::iterator sit = d->m_settingsCache.find(mk);
850  if (sit != d->m_settingsCache.end())
851  d->m_settingsCache.erase(sit);
852 
853  sit = d->m_settingsCache.find(mk2);
854  if (sit != d->m_settingsCache.end())
855  d->m_settingsCache.erase(sit);
856 
857  d->m_settingsCacheLock.unlock();
858 }
859 
860 static void clear(
861  SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
862 {
863  // Do the actual clearing..
864  SettingsMap::iterator it = cache.find(myKey);
865  if (it != cache.end())
866  {
867  SettingsMap::const_iterator oit = overrides.constFind(myKey);
868  if (oit == overrides.constEnd())
869  {
870  LOG(VB_DATABASE, LOG_INFO,
871  QString("Clearing Settings Cache for '%1'.").arg(myKey));
872  cache.erase(it);
873  }
874  else
875  {
876  LOG(VB_DATABASE, LOG_INFO,
877  QString("Clearing Cache of overridden '%1' ignored.")
878  .arg(myKey));
879  }
880  }
881 }
882 
883 void MythDB::ClearSettingsCache(const QString &_key)
884 {
885  d->m_settingsCacheLock.lockForWrite();
886 
887  if (_key.isEmpty())
888  {
889  LOG(VB_DATABASE, LOG_INFO, "Clearing Settings Cache.");
890  d->m_settingsCache.clear();
891  d->m_settingsCache.reserve(settings_reserve);
892 
893  SettingsMap::const_iterator it = d->m_overriddenSettings.cbegin();
894  for (; it != d->m_overriddenSettings.cend(); ++it)
895  {
896  QString mk2 = d->m_localhostname + ' ' + it.key();
897  mk2.squeeze();
898 
899  d->m_settingsCache[it.key()] = *it;
900  d->m_settingsCache[mk2] = *it;
901  }
902  }
903  else
904  {
905  QString myKey = _key.toLower();
906  clear(d->m_settingsCache, d->m_overriddenSettings, myKey);
907 
908  // To be safe always clear any local[ized] version too
909  QString mkl = myKey.section(QChar(' '), 1);
910  if (!mkl.isEmpty())
911  clear(d->m_settingsCache, d->m_overriddenSettings, mkl);
912  }
913 
914  d->m_settingsCacheLock.unlock();
915 }
916 
917 void MythDB::ActivateSettingsCache(bool activate)
918 {
919  if (activate)
920  LOG(VB_DATABASE, LOG_INFO, "Enabling Settings Cache.");
921  else
922  LOG(VB_DATABASE, LOG_INFO, "Disabling Settings Cache.");
923 
924  d->m_useSettingsCache = activate;
926 }
927 
929 {
930  if (!HaveValidDatabase())
931  return;
932 
933  if (!gCoreContext->IsUIThread())
934  return;
935 
936  while (!d->m_delayedSettings.isEmpty())
937  {
938  SingleSetting setting = d->m_delayedSettings.takeFirst();
939  SaveSettingOnHost(setting.m_key, setting.m_value, setting.m_host);
940  }
941 }
942 
946 void MythDB::SetHaveDBConnection(bool connected)
947 {
948  d->m_haveDBConnection = connected;
949 }
950 
955 void MythDB::SetHaveSchema(bool schema)
956 {
957  d->m_haveSchema = schema;
958 }
959 
967 bool MythDB::HaveSchema(void) const
968 {
969  return d->m_haveSchema;
970 }
971 
980 {
981  return (d->m_haveDBConnection && d->m_haveSchema);
982 }
MythDB::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval)
Definition: mythdb.cpp:578
MythDBPrivate::m_haveSchema
bool m_haveSchema
Definition: mythdb.cpp:89
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:807
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:124
DestroyMythDB
void DestroyMythDB(void)
Definition: mythdb.cpp:51
MythDB::WriteDelayedSettings
void WriteDelayedSettings(void)
Definition: mythdb.cpp:928
dbLock
static QMutex dbLock
Definition: mythdb.cpp:19
MythDB::HaveSchema
bool HaveSchema(void) const
Get a flag indicating that we have discovered tables and that this therefore not a new empty database...
Definition: mythdb.cpp:967
MythDB::IsDatabaseIgnored
bool IsDatabaseIgnored(void) const
Definition: mythdb.cpp:243
MythDB::IgnoreDatabase
void IgnoreDatabase(bool bIgnore)
Definition: mythdb.cpp:238
MythDB::~MythDB
~MythDB()
Definition: mythdb.cpp:110
MythDB::GetSettingOnHost
QString GetSettingOnHost(const QString &_key, const QString &_host, const QString &defaultval)
Definition: mythdb.cpp:632
mythdb.h
MythDB::DBErrorMessage
static QString DBErrorMessage(const QSqlError &err)
Definition: mythdb.cpp:199
MythDB::ClearSettingOnHost
bool ClearSettingOnHost(const QString &key, const QString &host)
Definition: mythdb.cpp:380
kClearSettingValue
const char *const kClearSettingValue
Definition: mythdb.cpp:23
DatabaseParams
Structure containing the basic Database parameters.
Definition: mythdbparams.h:10
MythDB::ActivateSettingsCache
void ActivateSettingsCache(bool activate=true)
Definition: mythdb.cpp:917
MDBManager
DB connection pool, used by MSqlQuery. Do not use directly.
Definition: mythdbcon.h:52
MythDBPrivate::m_settingsCache
SettingsMap m_settingsCache
Permanent settings in the DB and overridden settings.
Definition: mythdb.cpp:81
SingleSetting
Definition: mythdb.cpp:56
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:197
mythdbcon.h
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:604
MythCoreContext::IsUIThread
bool IsUIThread(void)
Definition: mythcorecontext.cpp:1361
MythDBPrivate::m_localhostname
QString m_localhostname
Definition: mythdb.cpp:72
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythDBPrivate::m_dbParams
DatabaseParams m_dbParams
Current database host & WOL details.
Definition: mythdb.cpp:71
GetMythDB
MythDB * GetMythDB(void)
Definition: mythdb.cpp:46
mythdirs.h
MythDB::GetFloatSettingOnHost
double GetFloatSettingOnHost(const QString &key, const QString &host, double defaultval)
Definition: mythdb.cpp:709
MythDBPrivate::m_useSettingsCache
volatile bool m_useSettingsCache
Definition: mythdb.cpp:79
MythDBPrivate::m_dbmanager
MDBManager m_dbmanager
Definition: mythdb.cpp:73
MythDBPrivate
Definition: mythdb.cpp:65
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
MythDB::GetFloatSetting
double GetFloatSetting(const QString &key, double defaultval)
Definition: mythdb.cpp:594
MythDBPrivate::m_suppressDBMessages
bool m_suppressDBMessages
Definition: mythdb.cpp:76
MythDB::ClearSettingsCache
void ClearSettingsCache(const QString &key=QString())
Definition: mythdb.cpp:883
MythDB::destroyMythDB
static void destroyMythDB()
Definition: mythdb.cpp:38
MythDBPrivate::m_settingsCacheLock
QReadWriteLock m_settingsCacheLock
Definition: mythdb.cpp:78
MythDB::SaveSettingOnHost
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
Definition: mythdb.cpp:269
SingleSetting::m_host
QString m_host
Definition: mythdb.cpp:60
MythDB::GetDatabaseParams
DatabaseParams GetDatabaseParams(void) const
Definition: mythdb.cpp:214
MythDB::ClearSetting
bool ClearSetting(const QString &key)
Definition: mythdb.cpp:375
mythlogging.h
MythDBPrivate::m_overriddenSettings
SettingsMap m_overriddenSettings
Overridden this session only.
Definition: mythdb.cpp:83
MythDBPrivate::MythDBPrivate
MythDBPrivate()
Definition: mythdb.cpp:94
mythdb
static MythDB * mythdb
Definition: mythdb.cpp:18
MythDB::GetNumSetting
int GetNumSetting(const QString &key, int defaultval)
Definition: mythdb.cpp:586
MythDB::GetError
static QString GetError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:163
hardwareprofile.i18n.t
t
Definition: i18n.py:36
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:536
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:194
MythDB::SuppressDBMessages
bool SuppressDBMessages(void) const
Definition: mythdb.cpp:253
MythDBPrivate::m_ignoreDatabase
bool m_ignoreDatabase
Definition: mythdb.cpp:75
MythDB::GetNumSettingOnHost
int GetNumSettingOnHost(const QString &key, const QString &host, int defaultval)
Definition: mythdb.cpp:700
MSqlQuery::boundValues
QVariantList boundValues(void) const
Definition: mythdbcon.h:204
SingleSetting::m_value
QString m_value
Definition: mythdb.cpp:59
clear
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:860
kSentinelValue
const char *const kSentinelValue
Definition: mythdb.cpp:22
SingleSetting::m_key
QString m_key
Definition: mythdb.cpp:58
MythDBPrivate::~MythDBPrivate
~MythDBPrivate()
Definition: mythdb.cpp:100
MSqlQuery::isConnected
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:134
uint
unsigned int uint
Definition: compat.h:140
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
SettingsMap
QHash< QString, QString > SettingsMap
Definition: mythdb.cpp:63
MythDB::getMythDB
static MythDB * getMythDB()
Definition: mythdb.cpp:25
MythDB::SetHaveSchema
void SetHaveSchema(bool schema)
Set a flag indicating that we have discovered tables and that this therefore not a new empty database...
Definition: mythdb.cpp:955
MSqlQuery::lastError
QSqlError lastError(void) const
Definition: mythdbcon.h:206
MythDB::SetLocalHostname
void SetLocalHostname(const QString &name)
Definition: mythdb.cpp:224
MythDB::GetResolutionSetting
void GetResolutionSetting(const QString &type, int &width, int &height, double &forced_aspect, double &refresh_rate, int index=-1)
MythDB::GetHostName
QString GetHostName(void) const
Definition: mythdb.cpp:233
MythDB::MythDB
MythDB()
Definition: mythdb.cpp:105
MythDBPrivate::m_delayedSettings
QList< SingleSetting > m_delayedSettings
Settings which should be written to the database as soon as it becomes available.
Definition: mythdb.cpp:86
mythcorecontext.h
MSqlQuery::executedQuery
QString executedQuery(void) const
Definition: mythdbcon.h:198
toCommaList
static QString toCommaList(const QSet< uint > &list)
Definition: tv_play.cpp:6640
MythDB::GetSetting
QString GetSetting(const QString &_key, const QString &defaultval)
Definition: mythdb.cpp:385
MythDB::SetDatabaseParams
void SetDatabaseParams(const DatabaseParams &params)
Definition: mythdb.cpp:219
MythDB::SetSuppressDBMessages
void SetSuppressDBMessages(bool bUpgraded)
Definition: mythdb.cpp:248
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
MythDBPrivate::m_haveDBConnection
bool m_haveDBConnection
Definition: mythdb.cpp:88
MythDB::GetSettings
bool GetSettings(QMap< QString, QString > &_key_value_pairs)
Definition: mythdb.cpp:457
ClearSettingsCache
static int ClearSettingsCache(const MythUtilCommandLineParser &)
Definition: backendutils.cpp:39
MythDB::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythdb.cpp:258
MythDB::SetHaveDBConnection
void SetHaveDBConnection(bool connected)
Set a flag indicating we have successfully connected to the database.
Definition: mythdb.cpp:946
MythDB::HaveValidDatabase
bool HaveValidDatabase(void) const
Returns true if we have successfully connected to the database and that database has tables.
Definition: mythdb.cpp:979
settings_reserve
static const int settings_reserve
Definition: mythdb.cpp:92
MythDB::OverrideSettingForSession
void OverrideSettingForSession(const QString &key, const QString &newValue)
Overrides the given setting for the execution time of the process.
Definition: mythdb.cpp:814
d
static const iso6937table * d
Definition: iso6937tables.cpp:1025
indent
static QString indent(uint level)
Definition: mythsettings.cpp:17
MythDB::GetDBManager
MDBManager * GetDBManager(void)
Definition: mythdb.cpp:115
MythDB::ClearOverrideSettingForSession
void ClearOverrideSettingForSession(const QString &key)
Clears session Overrides for the given setting.
Definition: mythdb.cpp:838
MythDB::toCommaList
static QString toCommaList(const QMap< QString, QVariant > &bindings, uint indent=0, uint softMaxColumn=80)
Definition: mythdb.cpp:120
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:832