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