5 #include <QReadWriteLock>
12 #include <QRegularExpression>
13 #include <QStandardPaths>
15 #include "mythconfig.h"
66 params.m_dbHostPing =
false;
69 QStandardPaths::writableLocation(QStandardPaths::TempLocation) +
71 QString(
"mythtv_%1.%2.sqlite3")
72 .arg(testname).arg(
MythRandom(),8,16,QLatin1Char(
'0'));
74 params.m_dbName =
":memory:";
76 params.m_dbType =
"QSQLITE";
77 db->SetDatabaseParams(params);
128 LOG(VB_DATABASE, LOG_INFO,
"Destroying MythDBPrivate");
142 return &(
d->m_dbmanager);
148 QMap<QString, QVariant>::const_iterator it = bindings.begin();
149 if (it == bindings.end())
153 QString str = QString(
"%1").arg(
"",
indent);
154 for (; it != bindings.end(); ++it)
156 QString val = (*it).toString();
162 #
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
163 it->type() == QVariant::String
165 it->typeId() == QMetaType::QString
169 val = (it->toString().isNull()) ?
170 "NULL" : QString(
"\"%1\"").arg(val);
172 const QString curBinding = it.key() +
'=' + val +
',';
173 if ((curColumn >
indent) &&
174 ((curBinding.length() + curColumn) > maxColumn))
177 str += QString(
"%1").arg(
"",
indent);
186 curColumn += curBinding.length();
188 str = str.left(str.length() - 1);
196 QString str = QString(
"DB Error (%1):\n").arg(where);
198 str +=
"Query was:\n";
200 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
203 QVariantList numberedBindings = query.
boundValues();
204 QMap<QString, QVariant> namedBindings;
205 static const QRegularExpression placeholders {
"(:\\w+)" };
206 auto iter = placeholders.globalMatch(str);
207 while (iter.hasNext())
209 auto match = iter.next();
210 namedBindings[match.captured()] = numberedBindings.isEmpty()
212 : numberedBindings.takeFirst();
218 str +=
"Bindings were:\n";
221 str += DBErrorMessage(query.
lastError());
227 LOG(VB_GENERAL, LOG_ERR, GetError(where, query));
233 return "No error type from QSqlError? Strange...";
235 return QString(
"Driver error was [%1/%2]:\n"
237 "Database error was:\n"
240 .arg(err.nativeErrorCode(),
247 return d->m_dbParams.m_dbName;
252 return d->m_dbParams;
257 d->m_dbParams = params;
262 if (
d->m_localhostname != name.toLower())
264 d->m_localhostname = name.toLower();
271 return d->m_localhostname;
276 d->m_ignoreDatabase = bIgnore;
281 return d->m_ignoreDatabase;
286 d->m_suppressDBMessages = bUpgraded;
291 return d->m_suppressDBMessages;
296 (void) SaveSettingOnHost(key,
297 QString::number(newValue),
d->m_localhostname);
302 (void) SaveSettingOnHost(key, newValue,
d->m_localhostname);
306 const QString &newValueRaw,
309 QString loc = QString(
"SaveSettingOnHost('%1') ").arg(key);
312 LOG(VB_GENERAL, LOG_ERR, loc +
"- Illegal null key");
316 QString newValue = (newValueRaw.isNull()) ?
"" : newValueRaw;
318 if (
d->m_ignoreDatabase)
320 if (host.toLower() ==
d->m_localhostname)
323 OverrideSettingForSession(key, newValue);
325 ClearOverrideSettingForSession(key);
330 if (!HaveValidDatabase())
332 if (host.toLower() ==
d->m_localhostname)
333 OverrideSettingForSession(key, newValue);
334 if (!
d->m_suppressDBMessages)
335 LOG(VB_GENERAL, LOG_ERR, loc +
"- No database yet");
340 d->m_delayedSettings.append(setting);
344 bool success =
false;
352 query.
prepare(
"DELETE FROM settings WHERE value = :KEY "
353 "AND hostname = :HOSTNAME ;");
357 query.
prepare(
"DELETE FROM settings WHERE value = :KEY "
358 "AND hostname is NULL;");
380 query.
prepare(
"INSERT INTO settings (value,data,hostname) "
381 "VALUES ( :VALUE, :DATA, :HOSTNAME );");
385 query.
prepare(
"INSERT INTO settings (value,data ) "
386 "VALUES ( :VALUE, :DATA );");
397 if (!(
GetMythDB()->SuppressDBMessages()))
403 LOG(VB_GENERAL, LOG_ERR, loc +
"- database not open");
413 return ClearSettingOnHost(key,
d->m_localhostname);
423 QString key = _key.toLower();
424 QString value = defaultval;
426 d->m_settingsCacheLock.lockForRead();
427 if (
d->m_useSettingsCache)
429 SettingsMap::const_iterator it =
d->m_settingsCache.constFind(key);
430 if (it !=
d->m_settingsCache.constEnd())
433 d->m_settingsCacheLock.unlock();
437 SettingsMap::const_iterator it =
d->m_overriddenSettings.constFind(key);
438 if (it !=
d->m_overriddenSettings.constEnd())
441 d->m_settingsCacheLock.unlock();
444 d->m_settingsCacheLock.unlock();
446 if (
d->m_ignoreDatabase || !HaveValidDatabase())
456 "WHERE value = :KEY AND hostname = :HOSTNAME");
458 query.
bindValue(
":HOSTNAME",
d->m_localhostname);
462 value = query.
value(0).toString();
469 "WHERE value = :KEY AND hostname IS NULL");
474 value = query.
value(0).toString();
482 d->m_settingsCacheLock.lockForWrite();
485 if (
d->m_settingsCache.find(key) ==
d->m_settingsCache.end())
486 d->m_settingsCache[key] = value;
487 d->m_settingsCacheLock.unlock();
495 QMap<QString,bool> done;
496 using KVIt = QMap<QString,QString>::iterator;
497 KVIt kvit = _key_value_pairs.begin();
498 for (; kvit != _key_value_pairs.end(); ++kvit)
499 done[kvit.key().toLower()] =
false;
501 QMap<QString,bool>::iterator dit = done.begin();
502 kvit = _key_value_pairs.begin();
506 d->m_settingsCacheLock.lockForRead();
507 if (
d->m_useSettingsCache)
509 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
511 SettingsMap::const_iterator it =
d->m_settingsCache.constFind(dit.key());
512 if (it !=
d->m_settingsCache.constEnd())
520 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
522 SettingsMap::const_iterator it =
523 d->m_overriddenSettings.constFind(dit.key());
524 if (it !=
d->m_overriddenSettings.constEnd())
531 d->m_settingsCacheLock.unlock();
535 if (((
uint)done.size()) == done_cnt ||
d->m_ignoreDatabase)
540 kvit = _key_value_pairs.begin();
543 QMap<QString,KVIt> keymap;
544 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
549 const QString& key = dit.key();
550 if (!key.contains(
"'"))
552 keylist += QString(
"'%1',").arg(key);
558 *kvit = GetSetting(key, *kvit);
562 if (keylist.isEmpty())
565 keylist = keylist.left(keylist.length() - 1);
570 "SELECT value, data, hostname "
572 "WHERE (hostname = '%1' OR hostname IS NULL) AND "
574 "ORDER BY hostname DESC")
575 .arg(
d->m_localhostname, keylist)))
577 if (!
d->m_suppressDBMessages)
578 DBError(
"GetSettings", query);
584 QString key = query.
value(0).toString().toLower();
585 QMap<QString,KVIt>::const_iterator it = keymap.constFind(key);
586 if (it != keymap.constEnd())
587 **it = query.
value(1).toString();
590 if (
d->m_useSettingsCache)
592 d->m_settingsCacheLock.lockForWrite();
593 for (
auto it = keymap.cbegin(); it != keymap.cend(); ++it)
595 QString key = it.key();
596 QString value = **it;
600 if (
d->m_settingsCache.find(key) ==
d->m_settingsCache.end())
604 d->m_settingsCache[key] = value;
607 d->m_settingsCacheLock.unlock();
616 QString val = QString::number(
static_cast<int>(defaultval));
617 QString retval = GetSetting(key, val);
619 return retval.toInt() > 0;
624 QString val = QString::number(defaultval);
625 QString retval = GetSetting(key, val);
627 return retval.toInt();
632 QString val = QString::number(defaultval);
633 QString retval = GetSetting(key, val);
635 return retval.toDouble();
641 QString retval = GetSetting(key, sentinel);
642 return (retval == sentinel) ?
"" : retval;
648 QString retval = GetSetting(key, sentinel);
649 if (retval == sentinel)
651 return retval.toInt() > 0;
657 QString retval = GetSetting(key, sentinel);
658 return (retval == sentinel) ? 0 : retval.toInt();
664 QString retval = GetSetting(key, sentinel);
665 return (retval == sentinel) ? 0.0 : retval.toDouble();
669 const QString &defaultval)
671 QString key = _key.toLower();
672 QString host = _host.toLower();
673 QString value = defaultval;
674 QString myKey = host +
' ' + key;
676 d->m_settingsCacheLock.lockForRead();
677 if (
d->m_useSettingsCache)
679 SettingsMap::const_iterator it =
d->m_settingsCache.constFind(myKey);
680 if (it !=
d->m_settingsCache.constEnd())
683 d->m_settingsCacheLock.unlock();
687 SettingsMap::const_iterator it =
d->m_overriddenSettings.constFind(myKey);
688 if (it !=
d->m_overriddenSettings.constEnd())
691 d->m_settingsCacheLock.unlock();
694 d->m_settingsCacheLock.unlock();
696 if (
d->m_ignoreDatabase)
702 if (!
d->m_suppressDBMessages)
704 LOG(VB_GENERAL, LOG_ERR,
705 QString(
"Database not open while trying to "
706 "load setting: %1").arg(key));
714 "WHERE value = :VALUE AND hostname = :HOSTNAME");
720 value = query.
value(0).toString();
727 d->m_settingsCacheLock.lockForWrite();
728 if (
d->m_settingsCache.find(myKey) ==
d->m_settingsCache.end())
729 d->m_settingsCache[myKey] = value;
730 d->m_settingsCacheLock.unlock();
739 QString val = QString::number(defaultval);
740 QString retval = GetSettingOnHost(key, host, val);
742 return retval.toInt();
746 const QString &key,
const QString &host,
double defaultval)
748 QString val = QString::number(defaultval);
749 QString retval = GetSettingOnHost(key, host, val);
751 return retval.toDouble();
757 QString retval = GetSettingOnHost(key, host, sentinel);
758 return (retval == sentinel) ?
"" : retval;
764 QString retval = GetSettingOnHost(key, host, sentinel);
765 return (retval == sentinel) ? 0 : retval.toInt();
771 QString retval = GetSettingOnHost(key, host, sentinel);
772 return (retval == sentinel) ? 0.0 : retval.toDouble();
776 int &width,
int &height,
777 double &forced_aspect,
778 double &refresh_rate,
784 QString sRes = QString(
"%1Resolution").arg(
type);
785 QString sRR = QString(
"%1RefreshRate").arg(
type);
786 QString sAspect = QString(
"%1ForceAspect").arg(
type);
787 QString sWidth = QString(
"%1Width").arg(
type);
788 QString sHeight = QString(
"%1Height").arg(
type);
791 sRes = QString(
"%1Resolution%2").arg(
type).arg(index);
792 sRR = QString(
"%1RefreshRate%2").arg(
type).arg(index);
793 sAspect = QString(
"%1ForceAspect%2").arg(
type).arg(index);
794 sWidth = QString(
"%1Width%2").arg(
type).arg(index);
795 sHeight = QString(
"%1Height%2").arg(
type).arg(index);
798 QString res = GetSetting(sRes);
802 QStringList slist = res.split(QString(
"x"));
805 if (2 == slist.size())
807 w = slist[0].toInt(&ok0);
808 h = slist[1].toInt(&ok1);
815 refresh_rate = GetFloatSetting(sRR);
816 forced_aspect = GetFloatSetting(sAspect);
822 int tmpWidth = GetNumSetting(sWidth, width);
826 int tmpHeight = GetNumSetting(sHeight, height);
838 double forced_aspect = 0;
839 double refresh_rate = 0.0;
840 GetResolutionSetting(
t, w, h, forced_aspect, refresh_rate, i);
851 const QString &key,
const QString &value)
853 QString mk = key.toLower();
854 QString mk2 =
d->m_localhostname +
' ' + mk;
856 if (
"dbschemaver" == mk)
858 LOG(VB_GENERAL, LOG_ERR,
859 QString(
"ERROR: Refusing to allow override for '%1'.").arg(key));
866 d->m_settingsCacheLock.lockForWrite();
867 d->m_overriddenSettings[mk] = mv;
868 d->m_settingsCache[mk] = mv;
869 d->m_settingsCache[mk2] = mv;
870 d->m_settingsCacheLock.unlock();
876 QString mk = key.toLower();
877 QString mk2 =
d->m_localhostname +
' ' + mk;
879 d->m_settingsCacheLock.lockForWrite();
881 SettingsMap::iterator oit =
d->m_overriddenSettings.find(mk);
882 if (oit !=
d->m_overriddenSettings.end())
883 d->m_overriddenSettings.erase(oit);
885 SettingsMap::iterator sit =
d->m_settingsCache.find(mk);
886 if (sit !=
d->m_settingsCache.end())
887 d->m_settingsCache.erase(sit);
889 sit =
d->m_settingsCache.find(mk2);
890 if (sit !=
d->m_settingsCache.end())
891 d->m_settingsCache.erase(sit);
893 d->m_settingsCacheLock.unlock();
900 SettingsMap::iterator it = cache.find(myKey);
901 if (it != cache.end())
903 SettingsMap::const_iterator oit = overrides.constFind(myKey);
904 if (oit == overrides.constEnd())
906 LOG(VB_DATABASE, LOG_INFO,
907 QString(
"Clearing Settings Cache for '%1'.").arg(myKey));
912 LOG(VB_DATABASE, LOG_INFO,
913 QString(
"Clearing Cache of overridden '%1' ignored.")
921 d->m_settingsCacheLock.lockForWrite();
925 LOG(VB_DATABASE, LOG_INFO,
"Clearing Settings Cache.");
926 d->m_settingsCache.clear();
929 SettingsMap::const_iterator it =
d->m_overriddenSettings.cbegin();
930 for (; it !=
d->m_overriddenSettings.cend(); ++it)
932 QString mk2 =
d->m_localhostname +
' ' + it.key();
935 d->m_settingsCache[it.key()] = *it;
936 d->m_settingsCache[mk2] = *it;
941 QString myKey = _key.toLower();
942 clear(
d->m_settingsCache,
d->m_overriddenSettings, myKey);
945 QString mkl = myKey.section(QChar(
' '), 1);
947 clear(
d->m_settingsCache,
d->m_overriddenSettings, mkl);
950 d->m_settingsCacheLock.unlock();
956 LOG(VB_DATABASE, LOG_INFO,
"Enabling Settings Cache.");
958 LOG(VB_DATABASE, LOG_INFO,
"Disabling Settings Cache.");
960 d->m_useSettingsCache = activate;
966 if (!HaveValidDatabase())
972 while (!
d->m_delayedSettings.isEmpty())
984 d->m_haveDBConnection = connected;
993 d->m_haveSchema = schema;
1005 return d->m_haveSchema;
1017 return (
d->m_haveDBConnection &&
d->m_haveSchema);