5 #include <QReadWriteLock>
12 #include <QRegularExpression>
13 #include <QStandardPaths>
16 #include "mythconfig.h"
67 params.m_dbHostPing =
false;
70 QStandardPaths::writableLocation(QStandardPaths::TempLocation) +
72 QString(
"mythtv_%1.%2.sqlite3")
73 .arg(testname).arg(
MythRandom(),8,16,QLatin1Char(
'0'));
75 params.m_dbName =
":memory:";
77 params.m_dbType =
"QSQLITE";
78 db->SetDatabaseParams(params);
129 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;
266 if (
force || (params !=
d->m_dbParams))
283 if (addr.setAddress(dbHostName))
285 addr.setScopeId(QString());
286 dbHostName = addr.toString();
301 success = config.Save();
304 d->m_dbParams = params;
307 GetDBManager()->CloseDatabases();
315 if (
d->m_localhostname != name.toLower())
317 d->m_localhostname = name.toLower();
324 return d->m_localhostname;
329 d->m_ignoreDatabase = bIgnore;
334 return d->m_ignoreDatabase;
339 d->m_suppressDBMessages = bUpgraded;
344 return d->m_suppressDBMessages;
349 (void) SaveSettingOnHost(key,
350 QString::number(newValue),
d->m_localhostname);
355 (void) SaveSettingOnHost(key, newValue,
d->m_localhostname);
359 const QString &newValueRaw,
362 QString loc = QString(
"SaveSettingOnHost('%1') ").arg(key);
365 LOG(VB_GENERAL, LOG_ERR, loc +
"- Illegal null key");
369 QString newValue = (newValueRaw.isNull()) ?
"" : newValueRaw;
371 if (
d->m_ignoreDatabase)
373 if (host.toLower() ==
d->m_localhostname)
376 OverrideSettingForSession(key, newValue);
378 ClearOverrideSettingForSession(key);
383 if (!HaveValidDatabase())
385 if (host.toLower() ==
d->m_localhostname)
386 OverrideSettingForSession(key, newValue);
387 if (!
d->m_suppressDBMessages)
388 LOG(VB_GENERAL, LOG_ERR, loc +
"- No database yet");
393 d->m_delayedSettings.append(setting);
397 bool success =
false;
405 query.
prepare(
"DELETE FROM settings WHERE value = :KEY "
406 "AND hostname = :HOSTNAME ;");
410 query.
prepare(
"DELETE FROM settings WHERE value = :KEY "
411 "AND hostname is NULL;");
433 query.
prepare(
"INSERT INTO settings (value,data,hostname) "
434 "VALUES ( :VALUE, :DATA, :HOSTNAME );");
438 query.
prepare(
"INSERT INTO settings (value,data ) "
439 "VALUES ( :VALUE, :DATA );");
450 if (!(
GetMythDB()->SuppressDBMessages()))
456 LOG(VB_GENERAL, LOG_ERR, loc +
"- database not open");
466 return ClearSettingOnHost(key,
d->m_localhostname);
476 QString key = _key.toLower();
477 QString value = defaultval;
479 d->m_settingsCacheLock.lockForRead();
480 if (
d->m_useSettingsCache)
482 SettingsMap::const_iterator it =
d->m_settingsCache.constFind(key);
483 if (it !=
d->m_settingsCache.constEnd())
486 d->m_settingsCacheLock.unlock();
490 SettingsMap::const_iterator it =
d->m_overriddenSettings.constFind(key);
491 if (it !=
d->m_overriddenSettings.constEnd())
494 d->m_settingsCacheLock.unlock();
497 d->m_settingsCacheLock.unlock();
499 if (
d->m_ignoreDatabase || !HaveValidDatabase())
509 "WHERE value = :KEY AND hostname = :HOSTNAME");
511 query.
bindValue(
":HOSTNAME",
d->m_localhostname);
515 value = query.
value(0).toString();
522 "WHERE value = :KEY AND hostname IS NULL");
527 value = query.
value(0).toString();
535 d->m_settingsCacheLock.lockForWrite();
538 if (
d->m_settingsCache.find(key) ==
d->m_settingsCache.end())
539 d->m_settingsCache[key] = value;
540 d->m_settingsCacheLock.unlock();
548 QMap<QString,bool> done;
549 using KVIt = QMap<QString,QString>::iterator;
550 KVIt kvit = _key_value_pairs.begin();
551 for (; kvit != _key_value_pairs.end(); ++kvit)
552 done[kvit.key().toLower()] =
false;
554 QMap<QString,bool>::iterator dit = done.begin();
555 kvit = _key_value_pairs.begin();
559 d->m_settingsCacheLock.lockForRead();
560 if (
d->m_useSettingsCache)
562 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
564 SettingsMap::const_iterator it =
d->m_settingsCache.constFind(dit.key());
565 if (it !=
d->m_settingsCache.constEnd())
573 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
575 SettingsMap::const_iterator it =
576 d->m_overriddenSettings.constFind(dit.key());
577 if (it !=
d->m_overriddenSettings.constEnd())
584 d->m_settingsCacheLock.unlock();
588 if (((
uint)done.size()) == done_cnt ||
d->m_ignoreDatabase)
593 kvit = _key_value_pairs.begin();
596 QMap<QString,KVIt> keymap;
597 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
602 const QString& key = dit.key();
603 if (!key.contains(
"'"))
605 keylist += QString(
"'%1',").arg(key);
611 *kvit = GetSetting(key, *kvit);
615 if (keylist.isEmpty())
618 keylist = keylist.left(keylist.length() - 1);
623 "SELECT value, data, hostname "
625 "WHERE (hostname = '%1' OR hostname IS NULL) AND "
627 "ORDER BY hostname DESC")
628 .arg(
d->m_localhostname, keylist)))
630 if (!
d->m_suppressDBMessages)
631 DBError(
"GetSettings", query);
637 QString key = query.
value(0).toString().toLower();
638 QMap<QString,KVIt>::const_iterator it = keymap.constFind(key);
639 if (it != keymap.constEnd())
640 **it = query.
value(1).toString();
643 if (
d->m_useSettingsCache)
645 d->m_settingsCacheLock.lockForWrite();
646 for (
auto it = keymap.cbegin(); it != keymap.cend(); ++it)
648 QString key = it.key();
649 QString value = **it;
653 if (
d->m_settingsCache.find(key) ==
d->m_settingsCache.end())
657 d->m_settingsCache[key] = value;
660 d->m_settingsCacheLock.unlock();
669 QString val = QString::number(
static_cast<int>(defaultval));
670 QString retval = GetSetting(key, val);
672 return retval.toInt() > 0;
677 QString val = QString::number(defaultval);
678 QString retval = GetSetting(key, val);
680 return retval.toInt();
685 QString val = QString::number(defaultval);
686 QString retval = GetSetting(key, val);
688 return retval.toDouble();
694 QString retval = GetSetting(key, sentinel);
695 return (retval == sentinel) ?
"" : retval;
701 QString retval = GetSetting(key, sentinel);
702 if (retval == sentinel)
704 return retval.toInt() > 0;
710 QString retval = GetSetting(key, sentinel);
711 return (retval == sentinel) ? 0 : retval.toInt();
717 QString retval = GetSetting(key, sentinel);
718 return (retval == sentinel) ? 0.0 : retval.toDouble();
722 const QString &defaultval)
724 QString key = _key.toLower();
725 QString host = _host.toLower();
726 QString value = defaultval;
727 QString myKey = host +
' ' + key;
729 d->m_settingsCacheLock.lockForRead();
730 if (
d->m_useSettingsCache)
732 SettingsMap::const_iterator it =
d->m_settingsCache.constFind(myKey);
733 if (it !=
d->m_settingsCache.constEnd())
736 d->m_settingsCacheLock.unlock();
740 SettingsMap::const_iterator it =
d->m_overriddenSettings.constFind(myKey);
741 if (it !=
d->m_overriddenSettings.constEnd())
744 d->m_settingsCacheLock.unlock();
747 d->m_settingsCacheLock.unlock();
749 if (
d->m_ignoreDatabase)
755 if (!
d->m_suppressDBMessages)
757 LOG(VB_GENERAL, LOG_ERR,
758 QString(
"Database not open while trying to "
759 "load setting: %1").arg(key));
767 "WHERE value = :VALUE AND hostname = :HOSTNAME");
773 value = query.
value(0).toString();
780 d->m_settingsCacheLock.lockForWrite();
781 if (
d->m_settingsCache.find(myKey) ==
d->m_settingsCache.end())
782 d->m_settingsCache[myKey] = value;
783 d->m_settingsCacheLock.unlock();
792 QString val = QString::number(defaultval);
793 QString retval = GetSettingOnHost(key, host, val);
795 return retval.toInt();
799 const QString &key,
const QString &host,
double defaultval)
801 QString val = QString::number(defaultval);
802 QString retval = GetSettingOnHost(key, host, val);
804 return retval.toDouble();
810 QString retval = GetSettingOnHost(key, host, sentinel);
811 return (retval == sentinel) ?
"" : retval;
817 QString retval = GetSettingOnHost(key, host, sentinel);
818 return (retval == sentinel) ? 0 : retval.toInt();
824 QString retval = GetSettingOnHost(key, host, sentinel);
825 return (retval == sentinel) ? 0.0 : retval.toDouble();
829 int &width,
int &height,
830 double &forced_aspect,
831 double &refresh_rate,
837 QString sRes = QString(
"%1Resolution").arg(
type);
838 QString sRR = QString(
"%1RefreshRate").arg(
type);
839 QString sAspect = QString(
"%1ForceAspect").arg(
type);
840 QString sWidth = QString(
"%1Width").arg(
type);
841 QString sHeight = QString(
"%1Height").arg(
type);
844 sRes = QString(
"%1Resolution%2").arg(
type).arg(index);
845 sRR = QString(
"%1RefreshRate%2").arg(
type).arg(index);
846 sAspect = QString(
"%1ForceAspect%2").arg(
type).arg(index);
847 sWidth = QString(
"%1Width%2").arg(
type).arg(index);
848 sHeight = QString(
"%1Height%2").arg(
type).arg(index);
851 QString res = GetSetting(sRes);
855 QStringList slist = res.split(QString(
"x"));
858 if (2 == slist.size())
860 w = slist[0].toInt(&ok0);
861 h = slist[1].toInt(&ok1);
868 refresh_rate = GetFloatSetting(sRR);
869 forced_aspect = GetFloatSetting(sAspect);
875 int tmpWidth = GetNumSetting(sWidth, width);
879 int tmpHeight = GetNumSetting(sHeight, height);
891 double forced_aspect = 0;
892 double refresh_rate = 0.0;
893 GetResolutionSetting(
t, w, h, forced_aspect, refresh_rate, i);
904 const QString &key,
const QString &value)
906 QString mk = key.toLower();
907 QString mk2 =
d->m_localhostname +
' ' + mk;
909 if (
"dbschemaver" == mk)
911 LOG(VB_GENERAL, LOG_ERR,
912 QString(
"ERROR: Refusing to allow override for '%1'.").arg(key));
919 d->m_settingsCacheLock.lockForWrite();
920 d->m_overriddenSettings[mk] = mv;
921 d->m_settingsCache[mk] = mv;
922 d->m_settingsCache[mk2] = mv;
923 d->m_settingsCacheLock.unlock();
929 QString mk = key.toLower();
930 QString mk2 =
d->m_localhostname +
' ' + mk;
932 d->m_settingsCacheLock.lockForWrite();
934 SettingsMap::iterator oit =
d->m_overriddenSettings.find(mk);
935 if (oit !=
d->m_overriddenSettings.end())
936 d->m_overriddenSettings.erase(oit);
938 SettingsMap::iterator sit =
d->m_settingsCache.find(mk);
939 if (sit !=
d->m_settingsCache.end())
940 d->m_settingsCache.erase(sit);
942 sit =
d->m_settingsCache.find(mk2);
943 if (sit !=
d->m_settingsCache.end())
944 d->m_settingsCache.erase(sit);
946 d->m_settingsCacheLock.unlock();
953 SettingsMap::iterator it = cache.find(myKey);
954 if (it != cache.end())
956 SettingsMap::const_iterator oit = overrides.constFind(myKey);
957 if (oit == overrides.constEnd())
959 LOG(VB_DATABASE, LOG_INFO,
960 QString(
"Clearing Settings Cache for '%1'.").arg(myKey));
965 LOG(VB_DATABASE, LOG_INFO,
966 QString(
"Clearing Cache of overridden '%1' ignored.")
974 d->m_settingsCacheLock.lockForWrite();
978 LOG(VB_DATABASE, LOG_INFO,
"Clearing Settings Cache.");
979 d->m_settingsCache.clear();
982 SettingsMap::const_iterator it =
d->m_overriddenSettings.cbegin();
983 for (; it !=
d->m_overriddenSettings.cend(); ++it)
985 QString mk2 =
d->m_localhostname +
' ' + it.key();
988 d->m_settingsCache[it.key()] = *it;
989 d->m_settingsCache[mk2] = *it;
994 QString myKey = _key.toLower();
995 clear(
d->m_settingsCache,
d->m_overriddenSettings, myKey);
998 QString mkl = myKey.section(QChar(
' '), 1);
1000 clear(
d->m_settingsCache,
d->m_overriddenSettings, mkl);
1003 d->m_settingsCacheLock.unlock();
1009 LOG(VB_DATABASE, LOG_INFO,
"Enabling Settings Cache.");
1011 LOG(VB_DATABASE, LOG_INFO,
"Disabling Settings Cache.");
1013 d->m_useSettingsCache = activate;
1019 if (!HaveValidDatabase())
1025 while (!
d->m_delayedSettings.isEmpty())
1037 d->m_haveDBConnection = connected;
1046 d->m_haveSchema = schema;
1058 return d->m_haveSchema;
1070 return (
d->m_haveDBConnection &&
d->m_haveSchema);