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