4 #include <QReadWriteLock> 75 bool ignoreDatabase {
false};
76 bool suppressDBMessages {
true};
79 volatile bool useSettingsCache {
false};
88 bool haveDBConnection {
false};
89 bool haveSchema {
false};
96 m_localhostname.clear();
102 LOG(VB_DATABASE, LOG_INFO,
"Destroying MythDBPrivate");
117 return &(
d->m_dbmanager);
123 QMap<QString, QVariant>::const_iterator it = bindings.begin();
124 if (it == bindings.end())
128 QString str = QString(
"%1").arg(
"",
indent);
129 for (; it != bindings.end(); ++it)
131 QString val = (*it).toString();
136 else if (it->type() == QVariant::String)
138 val = (it->toString().isNull()) ?
139 "NULL" : QString(
"\"%1\"").arg(val);
141 const QString curBinding = it.key() +
'=' + val +
',';
142 if ((curColumn >
indent) &&
143 ((curBinding.length() + curColumn) > maxColumn))
146 str += QString(
"%1").arg(
"",
indent);
155 curColumn += curBinding.length();
157 str = str.left(str.length() - 1);
165 QString str = QString(
"DB Error (%1):\n").arg(where);
167 str +=
"Query was:\n";
172 str +=
"Bindings were:\n";
175 str += DBErrorMessage(query.
lastError());
181 LOG(VB_GENERAL, LOG_ERR, GetError(where, query));
187 return "No error type from QSqlError? Strange...";
189 return QString(
"Driver error was [%1/%2]:\n" 191 "Database error was:\n" 194 .arg(err.nativeErrorCode())
195 .arg(err.driverText())
196 .arg(err.databaseText());
201 return d->m_DBparams;
206 d->m_DBparams = params;
211 if (
d->m_localhostname !=
name.toLower())
213 d->m_localhostname =
name.toLower();
220 return d->m_localhostname;
225 d->ignoreDatabase = bIgnore;
230 return d->ignoreDatabase;
235 d->suppressDBMessages = bUpgraded;
240 return d->suppressDBMessages;
245 (void) SaveSettingOnHost(key,
246 QString::number(newValue),
d->m_localhostname);
251 (void) SaveSettingOnHost(key, newValue,
d->m_localhostname);
255 const QString &newValueRaw,
258 QString loc = QString(
"SaveSettingOnHost('%1') ").arg(key);
261 LOG(VB_GENERAL, LOG_ERR, loc +
"- Illegal null key");
265 QString newValue = (newValueRaw.isNull()) ?
"" : newValueRaw;
267 if (
d->ignoreDatabase)
269 if (host.toLower() ==
d->m_localhostname)
272 OverrideSettingForSession(key, newValue);
274 ClearOverrideSettingForSession(key);
279 if (!HaveValidDatabase())
281 if (host.toLower() ==
d->m_localhostname)
282 OverrideSettingForSession(key, newValue);
283 if (!
d->suppressDBMessages)
284 LOG(VB_GENERAL, LOG_ERR, loc +
"- No database yet");
288 setting.
value = newValue;
289 d->delayedSettings.append(setting);
293 bool success =
false;
300 query.
prepare(
"DELETE FROM settings WHERE value = :KEY " 301 "AND hostname = :HOSTNAME ;");
303 query.
prepare(
"DELETE FROM settings WHERE value = :KEY " 304 "AND hostname is NULL;");
324 query.
prepare(
"INSERT INTO settings (value,data,hostname) " 325 "VALUES ( :VALUE, :DATA, :HOSTNAME );");
327 query.
prepare(
"INSERT INTO settings (value,data ) " 328 "VALUES ( :VALUE, :DATA );");
338 if (!(
GetMythDB()->SuppressDBMessages()))
344 LOG(VB_GENERAL, LOG_ERR, loc +
"- database not open");
354 return ClearSettingOnHost(key,
d->m_localhostname);
364 QString key = _key.toLower();
365 QString value = defaultval;
367 d->settingsCacheLock.lockForRead();
368 if (
d->useSettingsCache)
370 SettingsMap::const_iterator it =
d->settingsCache.find(key);
371 if (it !=
d->settingsCache.end())
374 d->settingsCacheLock.unlock();
378 SettingsMap::const_iterator it =
d->overriddenSettings.find(key);
379 if (it !=
d->overriddenSettings.end())
382 d->settingsCacheLock.unlock();
385 d->settingsCacheLock.unlock();
387 if (
d->ignoreDatabase || !HaveValidDatabase())
397 "WHERE value = :KEY AND hostname = :HOSTNAME");
399 query.
bindValue(
":HOSTNAME",
d->m_localhostname);
403 value = query.
value(0).toString();
410 "WHERE value = :KEY AND hostname IS NULL");
415 value = query.
value(0).toString();
423 d->settingsCacheLock.lockForWrite();
426 if (
d->settingsCache.find(key) ==
d->settingsCache.end())
427 d->settingsCache[key] = value;
428 d->settingsCacheLock.unlock();
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;
442 QMap<QString,bool>::iterator dit = done.begin();
443 kvit = _key_value_pairs.begin();
447 d->settingsCacheLock.lockForRead();
448 if (
d->useSettingsCache)
450 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
452 SettingsMap::const_iterator it =
d->settingsCache.find(dit.key());
453 if (it !=
d->settingsCache.end())
461 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
463 SettingsMap::const_iterator it =
464 d->overriddenSettings.find(dit.key());
465 if (it !=
d->overriddenSettings.end())
472 d->settingsCacheLock.unlock();
476 if (((
uint)done.size()) == done_cnt ||
d->ignoreDatabase)
481 kvit = _key_value_pairs.begin();
484 QMap<QString,KVIt> keymap;
485 for (; kvit != _key_value_pairs.end(); ++dit, ++kvit)
490 QString key = dit.key();
491 if (!key.contains(
"'"))
493 keylist += QString(
"'%1',").arg(key);
499 *kvit = GetSetting(key, *kvit);
503 if (keylist.isEmpty())
506 keylist = keylist.left(keylist.length() - 1);
511 "SELECT value, data, hostname " 513 "WHERE (hostname = '%1' OR hostname IS NULL) AND " 515 "ORDER BY hostname DESC")
516 .arg(
d->m_localhostname).arg(keylist)))
518 if (!
d->suppressDBMessages)
519 DBError(
"GetSettings", query);
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();
531 if (
d->useSettingsCache)
533 d->settingsCacheLock.lockForWrite();
534 QMap<QString,KVIt>::const_iterator it = keymap.begin();
535 for (; it != keymap.end(); ++it)
537 QString key = it.key(), value = **it;
541 if (
d->settingsCache.find(key) ==
d->settingsCache.end())
545 d->settingsCache[key] = value;
548 d->settingsCacheLock.unlock();
557 QString val = QString::number(defaultval);
558 QString retval = GetSetting(key, val);
560 return retval.toInt() > 0 ?
true :
false;
565 QString val = QString::number(defaultval);
566 QString retval = GetSetting(key, val);
568 return retval.toInt();
573 QString val = QString::number(defaultval);
574 QString retval = GetSetting(key, val);
576 return retval.toDouble();
582 QString retval = GetSetting(key, sentinel);
583 return (retval == sentinel) ?
"" : retval;
589 QString retval = GetSetting(key, sentinel);
590 if (retval == sentinel)
592 return retval.toInt() > 0 ?
true :
false;
598 QString retval = GetSetting(key, sentinel);
599 return (retval == sentinel) ? 0 : retval.toInt();
605 QString retval = GetSetting(key, sentinel);
606 return (retval == sentinel) ? 0.0 : retval.toDouble();
610 const QString &defaultval)
612 QString key = _key.toLower();
613 QString host = _host.toLower();
614 QString value = defaultval;
615 QString myKey = host +
' ' + key;
617 d->settingsCacheLock.lockForRead();
618 if (
d->useSettingsCache)
620 SettingsMap::const_iterator it =
d->settingsCache.find(myKey);
621 if (it !=
d->settingsCache.end())
624 d->settingsCacheLock.unlock();
628 SettingsMap::const_iterator it =
d->overriddenSettings.find(myKey);
629 if (it !=
d->overriddenSettings.end())
632 d->settingsCacheLock.unlock();
635 d->settingsCacheLock.unlock();
637 if (
d->ignoreDatabase)
643 if (!
d->suppressDBMessages)
644 LOG(VB_GENERAL, LOG_ERR,
645 QString(
"Database not open while trying to " 646 "load setting: %1").arg(key));
653 "WHERE value = :VALUE AND hostname = :HOSTNAME");
659 value = query.
value(0).toString();
666 d->settingsCacheLock.lockForWrite();
667 if (
d->settingsCache.find(myKey) ==
d->settingsCache.end())
668 d->settingsCache[myKey] = value;
669 d->settingsCacheLock.unlock();
678 QString val = QString::number(defaultval);
679 QString retval = GetSettingOnHost(key, host, val);
681 return retval.toInt();
685 const QString &key,
const QString &host,
double defaultval)
687 QString val = QString::number(defaultval);
688 QString retval = GetSettingOnHost(key, host, val);
690 return retval.toDouble();
696 QString retval = GetSettingOnHost(key, host, sentinel);
697 return (retval == sentinel) ?
"" : retval;
703 QString retval = GetSettingOnHost(key, host, sentinel);
704 return (retval == sentinel) ? 0 : retval.toInt();
710 QString retval = GetSettingOnHost(key, host, sentinel);
711 return (retval == sentinel) ? 0.0 : retval.toDouble();
715 int &width,
int &height,
716 double &forced_aspect,
717 double &refresh_rate,
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);
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);
735 QString res = GetSetting(sRes);
739 QStringList slist = res.split(QString(
"x"));
740 int w = width, h = height;
741 if (2 == slist.size())
743 w = slist[0].toInt(&ok0);
744 h = slist[1].toInt(&ok1);
751 refresh_rate = GetFloatSetting(sRR);
752 forced_aspect = GetFloatSetting(sAspect);
758 int tmpWidth = GetNumSetting(sWidth, width);
762 int tmpHeight = GetNumSetting(sHeight, height);
774 double forced_aspect = 0;
775 double refresh_rate = 0.0;
776 GetResolutionSetting(
t, w, h, forced_aspect, refresh_rate, i);
787 const QString &key,
const QString &value)
789 QString mk = key.toLower(), mk2 =
d->m_localhostname +
' ' + mk, mv = value;
790 if (
"dbschemaver" == mk)
792 LOG(VB_GENERAL, LOG_ERR,
793 QString(
"ERROR: Refusing to allow override for '%1'.").arg(key));
800 d->settingsCacheLock.lockForWrite();
801 d->overriddenSettings[mk] = mv;
802 d->settingsCache[mk] = mv;
803 d->settingsCache[mk2] = mv;
804 d->settingsCacheLock.unlock();
810 QString mk = key.toLower();
811 QString mk2 =
d->m_localhostname +
' ' + mk;
813 d->settingsCacheLock.lockForWrite();
815 SettingsMap::iterator oit =
d->overriddenSettings.find(mk);
816 if (oit !=
d->overriddenSettings.end())
817 d->overriddenSettings.erase(oit);
819 SettingsMap::iterator sit =
d->settingsCache.find(mk);
820 if (sit !=
d->settingsCache.end())
821 d->settingsCache.erase(sit);
823 sit =
d->settingsCache.find(mk2);
824 if (sit !=
d->settingsCache.end())
825 d->settingsCache.erase(sit);
827 d->settingsCacheLock.unlock();
834 SettingsMap::iterator it = cache.find(myKey);
835 if (it != cache.end())
837 SettingsMap::const_iterator oit = overrides.find(myKey);
838 if (oit == overrides.end())
840 LOG(VB_DATABASE, LOG_INFO,
841 QString(
"Clearing Settings Cache for '%1'.").arg(myKey));
846 LOG(VB_DATABASE, LOG_INFO,
847 QString(
"Clearing Cache of overridden '%1' ignored.")
855 d->settingsCacheLock.lockForWrite();
859 LOG(VB_DATABASE, LOG_INFO,
"Clearing Settings Cache.");
860 d->settingsCache.clear();
863 SettingsMap::const_iterator it =
d->overriddenSettings.begin();
864 for (; it !=
d->overriddenSettings.end(); ++it)
866 QString mk2 =
d->m_localhostname +
' ' + it.key();
869 d->settingsCache[it.key()] = *it;
870 d->settingsCache[mk2] = *it;
875 QString myKey = _key.toLower();
876 clear(
d->settingsCache,
d->overriddenSettings, myKey);
879 QString mkl = myKey.section(QChar(
' '), 1);
881 clear(
d->settingsCache,
d->overriddenSettings, mkl);
884 d->settingsCacheLock.unlock();
890 LOG(VB_DATABASE, LOG_INFO,
"Enabling Settings Cache.");
892 LOG(VB_DATABASE, LOG_INFO,
"Disabling Settings Cache.");
894 d->useSettingsCache = activate;
900 if (!HaveValidDatabase())
906 while (!
d->delayedSettings.isEmpty())
909 SaveSettingOnHost(setting.
key, setting.
value, setting.
host);
918 d->haveDBConnection = connected;
927 d->haveSchema = schema;
939 return d->haveSchema;
951 return (
d->haveDBConnection &&
d->haveSchema);
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
double GetFloatSettingOnHost(const QString &key, const QString &host, double defaultval)
DatabaseParams GetDatabaseParams(void) const
void bindValue(const QString &placeholder, const QVariant &val)
VERBOSE_PREAMBLE Most true
int GetNumSettingOnHost(const QString &key, const QString &host, int defaultval)
void WriteDelayedSettings(void)
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.
bool isConnected(void)
Only updated once during object creation.
bool HaveValidDatabase(void) const
Returns true if we have successfully connected to the database and that database has tables.
bool ClearSettingOnHost(const QString &key, const QString &host)
QList< SingleSetting > delayedSettings
Settings which should be written to the database as soon as it becomes available.
static QString toCommaList(const QSet< uint > &list)
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...
QHash< QString, QString > SettingsMap
void OverrideSettingForSession(const QString &key, const QString &newValue)
Overrides the given setting for the execution time of the process.
static MythDB * getMythDB()
SettingsMap settingsCache
Permanent settings in the DB and overridden settings.
static const int settings_reserve
int GetNumSetting(const QString &key, int defaultval)
QVariant value(int i) const
const char * kClearSettingValue
void SetDatabaseParams(const DatabaseParams ¶ms)
QSqlError lastError(void) const
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
static const uint16_t * d
void SetHaveDBConnection(bool connected)
Set a flag indicating we have successfully connected to the database.
static QString toCommaList(const QMap< QString, QVariant > &bindings, uint indent=0, uint softMaxColumn=80)
DatabaseParams m_DBparams
Current database host & WOL details.
void ActivateSettingsCache(bool activate=true)
bool GetBoolSetting(const QString &key, bool defaultval)
static QString indent(uint level)
SettingsMap overriddenSettings
Overridden this session only.
void SetSuppressDBMessages(bool bUpgraded)
bool GetSettings(QMap< QString, QString > &_key_value_pairs)
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
void IgnoreDatabase(bool bIgnore)
static void destroyMythDB()
QString GetSetting(const QString &_key, const QString &defaultval)
QMap< QString, QVariant > boundValues(void) const
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Structure containing the basic Database parameters.
#define LOG(_MASK_, _LEVEL_, _STRING_)
DB connection pool, used by MSqlQuery. Do not use directly.
void SetHaveSchema(bool schema)
Set a flag indicating that we have discovered tables and that this therefore not a new empty database...
double GetFloatSetting(const QString &key, double defaultval)
bool IsDatabaseIgnored(void) const
const char * kSentinelValue
QString GetHostName(void) const
bool ClearSetting(const QString &key)
MDBManager * GetDBManager(void)
void ClearSettingsCache(const QString &key=QString())
static QString DBErrorMessage(const QSqlError &err)
QString executedQuery(void) const
void SaveSetting(const QString &key, int newValue)
bool SuppressDBMessages(void) const
QReadWriteLock settingsCacheLock
void SetLocalHostname(const QString &name)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void ClearOverrideSettingForSession(const QString &key)
Clears session Overrides for the given setting.
static void DBError(const QString &where, const MSqlQuery &query)
static QString GetError(const QString &where, const MSqlQuery &query)
QString GetSettingOnHost(const QString &_key, const QString &_host, const QString &defaultval)
static int ClearSettingsCache(const MythUtilCommandLineParser &)
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)