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