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");
143 return &(
d->m_dbmanager);
149 QMap<QString, QVariant>::const_iterator it = bindings.begin();
150 if (it == bindings.end())
154 QString str = QString(
"%1").arg(
"",
indent);
155 for (; it != bindings.end(); ++it)
157 QString val = (*it).toString();
163 #
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
164 it->type() == QVariant::String
166 it->typeId() == QMetaType::QString
170 val = (it->toString().isNull()) ?
171 "NULL" : QString(
"\"%1\"").arg(val);
173 const QString curBinding = it.key() +
'=' + val +
',';
174 if ((curColumn >
indent) &&
175 ((curBinding.length() + curColumn) > maxColumn))
178 str += QString(
"%1").arg(
"",
indent);
187 curColumn += curBinding.length();
189 str = str.left(str.length() - 1);
197 QString str = QString(
"DB Error (%1):\n").arg(where);
199 str +=
"Query was:\n";
201 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
204 QVariantList numberedBindings = query.
boundValues();
205 QMap<QString, QVariant> namedBindings;
206 static const QRegularExpression placeholders {
"(:\\w+)" };
207 auto iter = placeholders.globalMatch(str);
208 while (iter.hasNext())
210 auto match = iter.next();
211 namedBindings[match.captured()] = numberedBindings.isEmpty()
213 : numberedBindings.takeFirst();
219 str +=
"Bindings were:\n";
222 str += DBErrorMessage(query.
lastError());
228 LOG(VB_GENERAL, LOG_ERR, GetError(where, query));
234 return "No error type from QSqlError? Strange...";
236 return QString(
"Driver error was [%1/%2]:\n"
238 "Database error was:\n"
241 .arg(err.nativeErrorCode(),
248 return d->m_dbParams.m_dbName;
253 return d->m_dbParams;
258 d->m_dbParams = params;
263 if (
d->m_localhostname != name.toLower())
265 d->m_localhostname = name.toLower();
272 return d->m_localhostname;
277 d->m_ignoreDatabase = bIgnore;
282 return d->m_ignoreDatabase;
287 d->m_suppressDBMessages = bUpgraded;
292 return d->m_suppressDBMessages;
297 (void) SaveSettingOnHost(key,
298 QString::number(newValue),
d->m_localhostname);
303 (void) SaveSettingOnHost(key, newValue,
d->m_localhostname);
307 const QString &newValueRaw,
310 QString loc = QString(
"SaveSettingOnHost('%1') ").arg(key);
313 LOG(VB_GENERAL, LOG_ERR, loc +
"- Illegal null key");
317 QString newValue = (newValueRaw.isNull()) ?
"" : newValueRaw;
319 if (
d->m_ignoreDatabase)
321 if (host.toLower() ==
d->m_localhostname)
324 OverrideSettingForSession(key, newValue);
326 ClearOverrideSettingForSession(key);
331 if (!HaveValidDatabase())
333 if (host.toLower() ==
d->m_localhostname)
334 OverrideSettingForSession(key, newValue);
335 if (!
d->m_suppressDBMessages)
336 LOG(VB_GENERAL, LOG_ERR, loc +
"- No database yet");
341 d->m_delayedSettings.append(setting);
345 bool success =
false;
353 query.
prepare(
"DELETE FROM settings WHERE value = :KEY "
354 "AND hostname = :HOSTNAME ;");
358 query.
prepare(
"DELETE FROM settings WHERE value = :KEY "
359 "AND hostname is NULL;");
381 query.
prepare(
"INSERT INTO settings (value,data,hostname) "
382 "VALUES ( :VALUE, :DATA, :HOSTNAME );");
386 query.
prepare(
"INSERT INTO settings (value,data ) "
387 "VALUES ( :VALUE, :DATA );");
398 if (!(
GetMythDB()->SuppressDBMessages()))
404 LOG(VB_GENERAL, LOG_ERR, loc +
"- database not open");
414 return ClearSettingOnHost(key,
d->m_localhostname);
424 QString key = _key.toLower();
425 QString value = defaultval;
427 d->m_settingsCacheLock.lockForRead();
428 if (
d->m_useSettingsCache)
430 SettingsMap::const_iterator it =
d->m_settingsCache.constFind(key);
431 if (it !=
d->m_settingsCache.constEnd())
434 d->m_settingsCacheLock.unlock();
438 SettingsMap::const_iterator it =
d->m_overriddenSettings.constFind(key);
439 if (it !=
d->m_overriddenSettings.constEnd())
442 d->m_settingsCacheLock.unlock();
445 d->m_settingsCacheLock.unlock();
447 if (
d->m_ignoreDatabase || !HaveValidDatabase())
457 "WHERE value = :KEY AND hostname = :HOSTNAME");
459 query.
bindValue(
":HOSTNAME",
d->m_localhostname);
463 value = query.
value(0).toString();
470 "WHERE value = :KEY AND hostname IS NULL");
475 value = query.
value(0).toString();
483 d->m_settingsCacheLock.lockForWrite();
486 if (
d->m_settingsCache.find(key) ==
d->m_settingsCache.end())
487 d->m_settingsCache[key] = value;
488 d->m_settingsCacheLock.unlock();
496 QMap<QString,bool> done;
497 using KVIt = QMap<QString,QString>::iterator;
498 KVIt kvit = _key_value_pairs.begin();
499 for (; kvit != _key_value_pairs.end(); ++kvit)
500 done[kvit.key().toLower()] =
false;
502 QMap<QString,bool>::iterator dit = done.begin();
503 kvit = _key_value_pairs.begin();
507 d->m_settingsCacheLock.lockForRead();
508 if (
d->m_useSettingsCache)
510 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
512 SettingsMap::const_iterator it =
d->m_settingsCache.constFind(dit.key());
513 if (it !=
d->m_settingsCache.constEnd())
521 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
523 SettingsMap::const_iterator it =
524 d->m_overriddenSettings.constFind(dit.key());
525 if (it !=
d->m_overriddenSettings.constEnd())
532 d->m_settingsCacheLock.unlock();
536 if (((
uint)done.size()) == done_cnt ||
d->m_ignoreDatabase)
541 kvit = _key_value_pairs.begin();
544 QMap<QString,KVIt> keymap;
545 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
550 const QString& key = dit.key();
551 if (!key.contains(
"'"))
553 keylist += QString(
"'%1',").arg(key);
559 *kvit = GetSetting(key, *kvit);
563 if (keylist.isEmpty())
566 keylist = keylist.left(keylist.length() - 1);
571 "SELECT value, data, hostname "
573 "WHERE (hostname = '%1' OR hostname IS NULL) AND "
575 "ORDER BY hostname DESC")
576 .arg(
d->m_localhostname, keylist)))
578 if (!
d->m_suppressDBMessages)
579 DBError(
"GetSettings", query);
585 QString key = query.
value(0).toString().toLower();
586 QMap<QString,KVIt>::const_iterator it = keymap.constFind(key);
587 if (it != keymap.constEnd())
588 **it = query.
value(1).toString();
591 if (
d->m_useSettingsCache)
593 d->m_settingsCacheLock.lockForWrite();
594 for (
auto it = keymap.cbegin(); it != keymap.cend(); ++it)
596 QString key = it.key();
597 QString value = **it;
601 if (
d->m_settingsCache.find(key) ==
d->m_settingsCache.end())
605 d->m_settingsCache[key] = value;
608 d->m_settingsCacheLock.unlock();
617 QString val = QString::number(
static_cast<int>(defaultval));
618 QString retval = GetSetting(key, val);
620 return retval.toInt() > 0;
625 QString val = QString::number(defaultval);
626 QString retval = GetSetting(key, val);
628 return retval.toInt();
633 QString val = QString::number(defaultval);
634 QString retval = GetSetting(key, val);
636 return retval.toDouble();
642 QString retval = GetSetting(key, sentinel);
643 return (retval == sentinel) ?
"" : retval;
649 QString retval = GetSetting(key, sentinel);
650 if (retval == sentinel)
652 return retval.toInt() > 0;
658 QString retval = GetSetting(key, sentinel);
659 return (retval == sentinel) ? 0 : retval.toInt();
665 QString retval = GetSetting(key, sentinel);
666 return (retval == sentinel) ? 0.0 : retval.toDouble();
670 const QString &defaultval)
672 QString key = _key.toLower();
673 QString host = _host.toLower();
674 QString value = defaultval;
675 QString myKey = host +
' ' + key;
677 d->m_settingsCacheLock.lockForRead();
678 if (
d->m_useSettingsCache)
680 SettingsMap::const_iterator it =
d->m_settingsCache.constFind(myKey);
681 if (it !=
d->m_settingsCache.constEnd())
684 d->m_settingsCacheLock.unlock();
688 SettingsMap::const_iterator it =
d->m_overriddenSettings.constFind(myKey);
689 if (it !=
d->m_overriddenSettings.constEnd())
692 d->m_settingsCacheLock.unlock();
695 d->m_settingsCacheLock.unlock();
697 if (
d->m_ignoreDatabase)
703 if (!
d->m_suppressDBMessages)
705 LOG(VB_GENERAL, LOG_ERR,
706 QString(
"Database not open while trying to "
707 "load setting: %1").arg(key));
715 "WHERE value = :VALUE AND hostname = :HOSTNAME");
721 value = query.
value(0).toString();
728 d->m_settingsCacheLock.lockForWrite();
729 if (
d->m_settingsCache.find(myKey) ==
d->m_settingsCache.end())
730 d->m_settingsCache[myKey] = value;
731 d->m_settingsCacheLock.unlock();
740 QString val = QString::number(defaultval);
741 QString retval = GetSettingOnHost(key, host, val);
743 return retval.toInt();
747 const QString &key,
const QString &host,
double defaultval)
749 QString val = QString::number(defaultval);
750 QString retval = GetSettingOnHost(key, host, val);
752 return retval.toDouble();
758 QString retval = GetSettingOnHost(key, host, sentinel);
759 return (retval == sentinel) ?
"" : retval;
765 QString retval = GetSettingOnHost(key, host, sentinel);
766 return (retval == sentinel) ? 0 : retval.toInt();
772 QString retval = GetSettingOnHost(key, host, sentinel);
773 return (retval == sentinel) ? 0.0 : retval.toDouble();
777 int &width,
int &height,
778 double &forced_aspect,
779 double &refresh_rate,
785 QString sRes = QString(
"%1Resolution").arg(
type);
786 QString sRR = QString(
"%1RefreshRate").arg(
type);
787 QString sAspect = QString(
"%1ForceAspect").arg(
type);
788 QString sWidth = QString(
"%1Width").arg(
type);
789 QString sHeight = QString(
"%1Height").arg(
type);
792 sRes = QString(
"%1Resolution%2").arg(
type).arg(index);
793 sRR = QString(
"%1RefreshRate%2").arg(
type).arg(index);
794 sAspect = QString(
"%1ForceAspect%2").arg(
type).arg(index);
795 sWidth = QString(
"%1Width%2").arg(
type).arg(index);
796 sHeight = QString(
"%1Height%2").arg(
type).arg(index);
799 QString res = GetSetting(sRes);
803 QStringList slist = res.split(QString(
"x"));
806 if (2 == slist.size())
808 w = slist[0].toInt(&ok0);
809 h = slist[1].toInt(&ok1);
816 refresh_rate = GetFloatSetting(sRR);
817 forced_aspect = GetFloatSetting(sAspect);
823 int tmpWidth = GetNumSetting(sWidth, width);
827 int tmpHeight = GetNumSetting(sHeight, height);
839 double forced_aspect = 0;
840 double refresh_rate = 0.0;
841 GetResolutionSetting(
t, w, h, forced_aspect, refresh_rate, i);
852 const QString &key,
const QString &value)
854 QString mk = key.toLower();
855 QString mk2 =
d->m_localhostname +
' ' + mk;
857 if (
"dbschemaver" == mk)
859 LOG(VB_GENERAL, LOG_ERR,
860 QString(
"ERROR: Refusing to allow override for '%1'.").arg(key));
867 d->m_settingsCacheLock.lockForWrite();
868 d->m_overriddenSettings[mk] = mv;
869 d->m_settingsCache[mk] = mv;
870 d->m_settingsCache[mk2] = mv;
871 d->m_settingsCacheLock.unlock();
877 QString mk = key.toLower();
878 QString mk2 =
d->m_localhostname +
' ' + mk;
880 d->m_settingsCacheLock.lockForWrite();
882 SettingsMap::iterator oit =
d->m_overriddenSettings.find(mk);
883 if (oit !=
d->m_overriddenSettings.end())
884 d->m_overriddenSettings.erase(oit);
886 SettingsMap::iterator sit =
d->m_settingsCache.find(mk);
887 if (sit !=
d->m_settingsCache.end())
888 d->m_settingsCache.erase(sit);
890 sit =
d->m_settingsCache.find(mk2);
891 if (sit !=
d->m_settingsCache.end())
892 d->m_settingsCache.erase(sit);
894 d->m_settingsCacheLock.unlock();
901 SettingsMap::iterator it = cache.find(myKey);
902 if (it != cache.end())
904 SettingsMap::const_iterator oit = overrides.constFind(myKey);
905 if (oit == overrides.constEnd())
907 LOG(VB_DATABASE, LOG_INFO,
908 QString(
"Clearing Settings Cache for '%1'.").arg(myKey));
913 LOG(VB_DATABASE, LOG_INFO,
914 QString(
"Clearing Cache of overridden '%1' ignored.")
922 d->m_settingsCacheLock.lockForWrite();
926 LOG(VB_DATABASE, LOG_INFO,
"Clearing Settings Cache.");
927 d->m_settingsCache.clear();
930 SettingsMap::const_iterator it =
d->m_overriddenSettings.cbegin();
931 for (; it !=
d->m_overriddenSettings.cend(); ++it)
933 QString mk2 =
d->m_localhostname +
' ' + it.key();
936 d->m_settingsCache[it.key()] = *it;
937 d->m_settingsCache[mk2] = *it;
942 QString myKey = _key.toLower();
943 clear(
d->m_settingsCache,
d->m_overriddenSettings, myKey);
946 QString mkl = myKey.section(QChar(
' '), 1);
948 clear(
d->m_settingsCache,
d->m_overriddenSettings, mkl);
951 d->m_settingsCacheLock.unlock();
957 LOG(VB_DATABASE, LOG_INFO,
"Enabling Settings Cache.");
959 LOG(VB_DATABASE, LOG_INFO,
"Disabling Settings Cache.");
961 d->m_useSettingsCache = activate;
967 if (!HaveValidDatabase())
973 while (!
d->m_delayedSettings.isEmpty())
985 d->m_haveDBConnection = connected;
994 d->m_haveSchema = schema;
1006 return d->m_haveSchema;
1018 return (
d->m_haveDBConnection &&
d->m_haveSchema);