MythTV  master
dbutil.cpp
Go to the documentation of this file.
1 #include <climits>
2 #include <cstdio>
3 #include <cstdlib>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7 
8 #include <QDir>
9 #include <QFile>
10 #include <QRegExp>
11 #include <QDateTime>
12 #include <QSqlError>
13 #include <QSqlRecord>
14 
15 #include "dbutil.h"
16 #include "mythcorecontext.h"
17 #include "storagegroup.h"
18 #include "mythmiscutil.h"
19 #include "mythdate.h"
20 #include "mythdb.h"
21 #include "mythdirs.h"
22 #include "mythlogging.h"
23 #include "mythsystemlegacy.h"
24 #include "exitcodes.h"
25 
26 #define LOC QString("DBUtil: ")
27 
28 const int DBUtil::kUnknownVersionNumber = INT_MIN;
29 
34  : m_versionMajor(-1), m_versionMinor(-1),
35  m_versionPoint(-1)
36 {
37 }
38 
44 {
45  if (m_versionString.isEmpty())
47  return m_versionString;
48 }
49 
62 int DBUtil::CompareDBMSVersion(int major, int minor, int point)
63 {
64  if (m_versionMajor < 0)
65  if (!ParseDBMSVersion())
66  return kUnknownVersionNumber;
67 
68  int result = 0;
70  int compareto[3] = {major, minor, point};
71  for (int i = 0; i < 3 && !result; i++)
72  {
73  if ((version[i] > -1) || (compareto[i] != 0))
74  result = version[i] - compareto[i];
75  }
76 
77  return result;
78 }
79 
84 {
85  const QStringList tables = GetTables();
86  const int size = tables.size();
87  // Usually there will be a single table called schemalock, but check for
88  // no tables, also, just in case.
89  return (((size == 1) && (tables.at(0).endsWith(".`schemalock`"))) ||
90  (size == 0));
91 }
92 
98 {
99  QString backupStartTimeStr =
100  gCoreContext->GetSetting("BackupDBLastRunStart");
101  QString backupEndTimeStr = gCoreContext->GetSetting("BackupDBLastRunEnd");
102 
103  if (backupStartTimeStr.isEmpty())
104  {
105  LOG(VB_DATABASE, LOG_ERR, "DBUtil::BackupInProgress(): No start time "
106  "found, database backup is not in progress.");
107  return false;
108  }
109 
110  backupStartTimeStr.replace(" ", "T");
111 
112  QDateTime backupStartTime = MythDate::fromString(backupStartTimeStr);
113 
114  // No end time set
115  if (backupEndTimeStr.isEmpty())
116  {
117  // If DB Backup started less then 10 minutes ago, assume still running
118  if (backupStartTime.secsTo(MythDate::current()) < 600)
119  {
120  LOG(VB_DATABASE, LOG_INFO,
121  QString("DBUtil::BackupInProgress(): Found "
122  "database backup start time of %1 which was %2 seconds "
123  "ago, therefore it appears the backup is still running.")
124  .arg(backupStartTimeStr)
125  .arg(backupStartTime.secsTo(MythDate::current())));
126  return true;
127  }
128  LOG(VB_DATABASE, LOG_ERR, QString("DBUtil::BackupInProgress(): "
129  "Database backup started at %1, but no end time was found. "
130  "The backup started %2 seconds ago and should have "
131  "finished by now therefore it appears it is not running .")
132  .arg(backupStartTimeStr)
133  .arg(backupStartTime.secsTo(MythDate::current())));
134  return false;
135  }
136 
137  backupEndTimeStr.replace(" ", "T");
138 
139  QDateTime backupEndTime = MythDate::fromString(backupEndTimeStr);
140 
141  if (backupEndTime >= backupStartTime)
142  {
143  LOG(VB_DATABASE, LOG_ERR,
144  QString("DBUtil::BackupInProgress(): Found "
145  "database backup end time of %1 later than start time "
146  "of %2, therefore backup is not running.")
147  .arg(backupEndTimeStr).arg(backupStartTimeStr));
148  return false;
149  }
150  if (backupStartTime.secsTo(MythDate::current()) > 600)
151  {
152  LOG(VB_DATABASE, LOG_ERR,
153  QString("DBUtil::BackupInProgress(): "
154  "Database backup started at %1, but has not ended yet. "
155  "The backup started %2 seconds ago and should have "
156  "finished by now therefore it appears it is not running")
157  .arg(backupStartTimeStr)
158  .arg(backupStartTime.secsTo(MythDate::current())));
159  return false;
160  }
161 
162  // start > end and started less than 10 minutes ago
163  LOG(VB_DATABASE, LOG_INFO, QString("DBUtil::BackupInProgress(): "
164  "Database backup started at %1, and is still running.")
165  .arg(backupStartTimeStr));
166  return true;
167 }
168 
194 MythDBBackupStatus DBUtil::BackupDB(QString &filename, bool disableRotation)
195 {
196  filename = QString();
197 
198 #ifdef _WIN32
199  LOG(VB_GENERAL, LOG_CRIT, "Database backups disabled on Windows.");
200  return kDB_Backup_Disabled;
201 #else
202 
203  if (gCoreContext->GetBoolSetting("DisableAutomaticBackup", false))
204  {
205  LOG(VB_GENERAL, LOG_CRIT,
206  "Database backups disabled. Skipping backup.");
207  return kDB_Backup_Disabled;
208  }
209 
210  if (IsNewDatabase())
211  {
212  LOG(VB_GENERAL, LOG_CRIT, "New database detected. Skipping backup.");
213  return kDB_Backup_Empty_DB;
214  }
215 
216  QString backupScript = GetShareDir() + "mythconverg_backup.pl";
217  backupScript = gCoreContext->GetSetting("DatabaseBackupScript",
218  backupScript);
219 
220  if (!QFile::exists(backupScript))
221  {
222  LOG(VB_GENERAL, LOG_CRIT, QString("Database backup script does "
223  "not exist: %1").arg(backupScript));
224  backupScript.clear();
225  }
226 
227  bool result = false;
228  MSqlQuery query(MSqlQuery::InitCon());
229 
231  "BackupDBLastRunStart",
233 
234  if (!backupScript.isEmpty())
235  {
236  result = DoBackup(backupScript, filename, disableRotation);
237  if (!result)
238  LOG(VB_GENERAL, LOG_CRIT, "Script-based database backup failed. "
239  "Retrying with internal backup.");
240  }
241 
242  if (!result)
243  result = DoBackup(filename);
244 
246  "BackupDBLastRunEnd",
248 
249  if (query.isConnected())
250  {
251  QString dbTag("BackupDB");
252  query.prepare("DELETE FROM housekeeping WHERE tag = :TAG ;");
253  query.bindValue(":TAG", dbTag);
254  if (!query.exec())
255  MythDB::DBError("DBUtil::BackupDB", query);
256 
257  query.prepare("INSERT INTO housekeeping(tag,lastrun) "
258  "values(:TAG ,now()) ;");
259  query.bindValue(":TAG", dbTag);
260  if (!query.exec())
261  MythDB::DBError("DBUtil::BackupDB", query);
262  }
263 
264  if (result)
265  return kDB_Backup_Completed;
266 
267  return kDB_Backup_Failed;
268 #endif // _WIN32
269 }
270 
282 bool DBUtil::CheckTables(const bool repair, const QString &options)
283 {
284  MSqlQuery query(MSqlQuery::InitCon());
285  if (!query.isConnected())
286  return false;
287 
288  const QStringList all_tables = GetTables(QStringList("MyISAM"));
289 
290  if (all_tables.empty())
291  return true;
292 
293  QString sql = QString("CHECK TABLE %1 %2;").arg(all_tables.join(", "))
294  .arg(options);
295 
296  LOG(VB_GENERAL, LOG_CRIT, "Checking database tables.");
297  if (!query.exec(sql))
298  {
299  MythDB::DBError("DBUtil Checking Tables", query);
300  return false;
301  }
302 
303  QStringList tables = CheckRepairStatus(query);
304  bool result = true;
305  if (!tables.empty())
306  {
307  LOG(VB_GENERAL, LOG_CRIT, QString("Found crashed database table(s): %1")
308  .arg(tables.join(", ")));
309  if (repair)
310  // If RepairTables() repairs the crashed tables, return true
311  result = RepairTables(tables);
312  else
313  result = false;
314  }
315 
316  return result;
317 }
318 
336 bool DBUtil::RepairTables(const QStringList &tables)
337 {
338  MSqlQuery query(MSqlQuery::InitCon());
339  if (!query.isConnected())
340  return false;
341 
342  QString all_tables = tables.join(", ");
343  LOG(VB_GENERAL, LOG_CRIT, QString("Repairing database tables: %1")
344  .arg(all_tables));
345 
346  QString sql = QString("REPAIR TABLE %1;").arg(all_tables);
347  if (!query.exec(sql))
348  {
349  MythDB::DBError("DBUtil Repairing Tables", query);
350  return false;
351  }
352 
353  QStringList bad_tables = CheckRepairStatus(query);
354  bool result = true;
355  if (!bad_tables.empty())
356  {
357  LOG(VB_GENERAL, LOG_CRIT,
358  QString("Unable to repair crashed table(s): %1")
359  .arg(bad_tables.join(", ")));
360  result = false;
361  }
362  return result;
363 }
364 
384 {
385  QStringList tables;
386  QSqlRecord record = query.record();
387  int table_index = record.indexOf("Table");
388  int type_index = record.indexOf("Msg_type");
389  int text_index = record.indexOf("Msg_text");
390  QString table, type, text, previous_table;
391  bool ok = true;
392  while (query.next())
393  {
394  table = query.value(table_index).toString();
395  type = query.value(type_index).toString();
396  text = query.value(text_index).toString();
397  if (table != previous_table)
398  {
399  if (!ok)
400  {
401  tables.append(previous_table);
402  ok = true;
403  }
404  previous_table = table;
405  }
406  // If the final row shows status OK, the table is now good
407  if ("status" == type.toLower() && "ok" == text.toLower())
408  ok = true;
409  else if ("error" == type.toLower() ||
410  ("status" == type.toLower() && "ok" != text.toLower()))
411  ok = false;
412  }
413  // Check the last table in the list
414  if (!ok)
415  tables.append(table);
416  return tables;
417 }
418 
424 QStringList DBUtil::GetTables(const QStringList &engines)
425 {
426  QStringList result;
427 
428  MSqlQuery query(MSqlQuery::InitCon());
429  if (!query.isConnected())
430  return result;
431 
432  QString sql = "SELECT CONCAT('`', TABLE_SCHEMA, "
433  " '`.`', TABLE_NAME, "
434  " '`') AS `TABLE_NAME` "
435  " FROM INFORMATION_SCHEMA.TABLES "
436  " WHERE TABLE_SCHEMA = DATABASE() "
437  " AND TABLE_TYPE = 'BASE TABLE'";
438  if (!engines.empty())
439  sql.append(QString(" AND ENGINE IN ('%1')")
440  .arg(engines.join("', '")));
441  if (!query.exec(sql))
442  {
443  MythDB::DBError("DBUtil Finding Tables", query);
444  return result;
445  }
446 
447  while (query.next())
448  {
449  result.append(query.value(0).toString());
450  }
451 
452  return result;
453 }
454 
467 QString DBUtil::CreateBackupFilename(const QString& prefix, const QString& extension)
468 {
470  return QString("%1-%2%3").arg(prefix).arg(time).arg(extension);
471 }
472 
483 {
484  QString directory;
485  StorageGroup sgroup("DB Backups", gCoreContext->GetHostName());
486  QStringList dirList = sgroup.GetDirList();
487  if (!dirList.empty())
488  {
489  directory = sgroup.FindNextDirMostFree();
490 
491  if (!QDir(directory).exists())
492  {
493  LOG(VB_FILE, LOG_INFO, "GetBackupDirectory() - ignoring " +
494  directory + ", using /tmp");
495  directory.clear();
496  }
497  }
498 
499  if (directory.isNull())
500  // Rather than use kDefaultStorageDir, the default for
501  // FindNextDirMostFree() when no dirs are defined for the StorageGroup,
502  // use /tmp as it's possible that kDefaultStorageDir doesn't exist
503  // and (at least on *nix) less possible that /tmp doesn't exist
504  directory = "/tmp";
505 
506  return directory;
507 }
508 
518  const QString &privateinfo, QString &filename)
519 {
520  bool ok = true;
521  filename = createTempFile("/tmp/mythtv_db_backup_conf_XXXXXX");
522  const QByteArray tmpfile = filename.toLocal8Bit();
523 
524  FILE *fp = fopen(tmpfile.constData(), "w");
525  if (!fp)
526  {
527  LOG(VB_GENERAL, LOG_ERR, LOC +
528  QString("Unable to create temporary "
529  "configuration file for creating DB backup: %1")
530  .arg(tmpfile.constData()));
531  filename = "";
532  ok = false;
533  }
534  else
535  {
536  if (chmod(tmpfile.constData(), S_IRUSR))
537  {
538  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error changing permissions '%1'")
539  .arg(tmpfile.constData()) + ENO);
540  }
541 
542  QByteArray outarr = privateinfo.toLocal8Bit();
543  fprintf(fp, "%s", outarr.constData());
544 
545  if (fclose(fp))
546  {
547  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error closing '%1'")
548  .arg(tmpfile.constData()) + ENO);
549  }
550  }
551 
552  return ok;
553 }
554 
561 bool DBUtil::DoBackup(const QString &backupScript, QString &filename,
562  bool disableRotation)
563 {
565  QString dbSchemaVer = gCoreContext->GetSetting("DBSchemaVer");
566  QString backupDirectory = GetBackupDirectory();
567  QString backupFilename = CreateBackupFilename(dbParams.dbName + "-" +
568  dbSchemaVer, ".sql");
569  QString scriptArgs = gCoreContext->GetSetting("BackupDBScriptArgs");
570  QString rotate = "";
571  if (disableRotation)
572  {
573  if (!(scriptArgs.contains("rotate", Qt::CaseInsensitive)))
574  rotate = "rotate=-1";
575  }
576 
577 
578  QString privateinfo =
579  QString("DBHostName=%1\nDBPort=%2\n"
580  "DBUserName=%3\nDBPassword=%4\n"
581  "DBName=%5\nDBSchemaVer=%6\n"
582  "DBBackupDirectory=%7\nDBBackupFilename=%8\n%9\n")
583  .arg(dbParams.dbHostName).arg(dbParams.dbPort)
584  .arg(dbParams.dbUserName).arg(dbParams.dbPassword)
585  .arg(dbParams.dbName).arg(dbSchemaVer)
586  .arg(backupDirectory).arg(backupFilename).arg(rotate);
587  QString tempDatabaseConfFile;
588  bool hastemp = CreateTemporaryDBConf(privateinfo, tempDatabaseConfFile);
589  if (!hastemp)
590  LOG(VB_GENERAL, LOG_ERR, LOC + "Attempting backup, anyway.");
591 
592  LOG(VB_GENERAL, LOG_ERR, QString("Backing up database with script: '%1'")
593  .arg(backupScript));
594 
595  QString command = backupScript + " " + scriptArgs + " " +
596  tempDatabaseConfFile;
598 
599  if (hastemp)
600  {
601  QByteArray tmpfile = tempDatabaseConfFile.toLocal8Bit();
602  unlink(tmpfile.constData());
603  }
604 
605  if (status != GENERIC_EXIT_OK)
606  {
607  LOG(VB_GENERAL, LOG_ERR, LOC +
608  QString("Error backing up database: %1 (%2)")
609  .arg(command).arg(status));
610  filename = "__FAILED__";
611  return false;
612  }
613 
614  LOG(VB_GENERAL, LOG_CRIT, "Database Backup complete.");
615 
616  QDir dir(backupDirectory, backupFilename + "*");
617  uint numfiles = dir.count();
618  if (numfiles < 1)
619  {
620  // If no file begins with the suggested filename, don't show the backup
621  // filename in the GUI message -- the script probably used some other
622  // filename
623  filename = "";
624  LOG(VB_FILE, LOG_ERR, LOC +
625  QString("No files beginning with the suggested database backup "
626  "filename '%1' were found in '%2'.")
627  .arg(backupFilename).arg(backupDirectory));
628  }
629  else
630  {
631  filename = dir.path() + "/" + dir[0];;
632  if (numfiles > 1)
633  {
634  LOG(VB_FILE, LOG_ERR, LOC +
635  QString("Multiple files beginning with the suggested database "
636  "backup filename '%1' were found in '%2'. "
637  "Assuming the first is the backup.")
638  .arg(backupFilename).arg(backupDirectory));
639  }
640  }
641 
642  if (!filename.isEmpty())
643  {
644  LOG(VB_GENERAL, LOG_CRIT, QString("Backed up database to file: '%1'")
645  .arg(filename));
646  }
647 
648  return true;
649 }
650 
657 bool DBUtil::DoBackup(QString &filename)
658 {
660  QString dbSchemaVer = gCoreContext->GetSetting("DBSchemaVer");
661  QString backupDirectory = GetBackupDirectory();
662 
663  QString command;
664  QString compressCommand("");
665  QString extension = ".sql";
666  if (QFile::exists("/bin/gzip"))
667  compressCommand = "/bin/gzip";
668  else if (QFile::exists("/usr/bin/gzip"))
669  compressCommand = "/usr/bin/gzip";
670  else
671  LOG(VB_GENERAL, LOG_CRIT, "Neither /bin/gzip nor /usr/bin/gzip exist. "
672  "The database backup will be uncompressed.");
673 
674  QString backupFilename = CreateBackupFilename(
675  dbParams.dbName + "-" + dbSchemaVer, extension);
676  QString backupPathname = backupDirectory + "/" + backupFilename;
677 
678  QString privateinfo = QString(
679  "[client]\npassword=%1\n[mysqldump]\npassword=%2\n")
680  .arg(dbParams.dbPassword).arg(dbParams.dbPassword);
681  QString tempExtraConfFile;
682  if (!CreateTemporaryDBConf(privateinfo, tempExtraConfFile))
683  return false;
684 
685  QString portArg = "";
686  if (dbParams.dbPort > 0)
687  portArg = QString(" --port='%1'").arg(dbParams.dbPort);
688  command = QString("mysqldump --defaults-extra-file='%1' --host='%2'%3"
689  " --user='%4' --add-drop-table --add-locks"
690  " --allow-keywords --complete-insert"
691  " --extended-insert --lock-tables --no-create-db --quick"
692  " '%5' > '%6' 2>/dev/null")
693  .arg(tempExtraConfFile).arg(dbParams.dbHostName)
694  .arg(portArg).arg(dbParams.dbUserName)
695  .arg(dbParams.dbName).arg(backupPathname);
696 
697  LOG(VB_FILE, LOG_INFO, QString("Backing up database with command: '%1'")
698  .arg(command));
699  LOG(VB_GENERAL, LOG_CRIT, QString("Backing up database to file: '%1'")
700  .arg(backupPathname));
701 
703 
704  QByteArray tmpfile = tempExtraConfFile.toLocal8Bit();
705  unlink(tmpfile.constData());
706 
707  if (status != GENERIC_EXIT_OK)
708  {
709  LOG(VB_GENERAL, LOG_ERR, LOC +
710  QString("Error backing up database: '%1' (%2)")
711  .arg(command).arg(status));
712  filename = "__FAILED__";
713  return false;
714  }
715 
716  if (compressCommand != "")
717  {
718  LOG(VB_GENERAL, LOG_CRIT, "Compressing database backup file.");
719  compressCommand += " " + backupPathname;
720  status = myth_system(compressCommand, kMSDontBlockInputDevs);
721 
722  if (status != GENERIC_EXIT_OK)
723  {
724  LOG(VB_GENERAL, LOG_CRIT,
725  "Compression failed, backup file will remain uncompressed.");
726  }
727  else
728  {
729  backupPathname += ".gz";
730 
731  LOG(VB_GENERAL, LOG_CRIT, QString("Database Backup filename: '%1'")
732  .arg(backupPathname));
733  }
734  }
735 
736  LOG(VB_GENERAL, LOG_CRIT, "Database Backup complete.");
737 
738  filename = backupPathname;
739  return true;
740 }
741 
747 {
748  // Allow users to override the string provided by the database server in
749  // case the value was changed to an unrecognizable string by whomever
750  // compiled the MySQL server
751  QString dbmsVersion = gCoreContext->GetSetting("DBMSVersionOverride");
752 
753  if (dbmsVersion.isEmpty())
754  {
755  MSqlQuery query(MSqlQuery::InitCon());
756  query.prepare("SELECT VERSION();");
757  if (!query.exec() || !query.next())
758  {
759  LOG(VB_GENERAL, LOG_ERR, LOC +
760  "Unable to determine MySQL version.");
761  MythDB::DBError("DBUtil Querying DBMS version", query);
762  dbmsVersion.clear();
763  }
764  else
765  dbmsVersion = query.value(0).toString();
766  }
767  m_versionString = dbmsVersion;
768 
769  return !m_versionString.isEmpty();
770 }
771 
776 {
777  if (m_versionString.isEmpty())
778  if (!QueryDBMSVersion())
779  return false;
780 
781  bool ok;
782  QString section;
783  int pos = 0, i = 0;
784  int version[3] = {-1, -1, -1};
785  QRegExp digits("(\\d+)");
786 
787  while ((i < 3) && ((pos = digits.indexIn(m_versionString, pos)) > -1))
788  {
789  section = digits.cap(1);
790  pos += digits.matchedLength();
791  version[i] = section.toInt(&ok, 10);
792  if (!ok)
793  version[i] = -1;
794  i++;
795  }
796 
797  m_versionMajor = version[0];
798  m_versionMinor = version[1];
799  m_versionPoint = version[2];
800 
801  return m_versionMajor > -1;
802 }
803 
808 {
809  int count = 0;
810 
811  MSqlQuery query(MSqlQuery::InitCon());
812  if (!query.isConnected())
813  {
814  LOG(VB_GENERAL, LOG_DEBUG, "Not connected to DB");
815  return count;
816  }
817 
818  if (!query.exec("SHOW PROCESSLIST;"))
819  {
820  MythDB::DBError("DBUtil CountClients", query);
821  return count;
822  }
823 
824  QSqlRecord record = query.record();
825  int db_index = record.indexOf("db");
826  QString dbName = gCoreContext->GetDatabaseParams().dbName;
827  QString inUseDB;
828 
829  while (query.next())
830  {
831  inUseDB = query.value(db_index).toString();
832  if (inUseDB == dbName)
833  ++count;
834  }
835 
836  // On average, each myth program has 4 database connections,
837  // but we round up just in case a new program is loading:
838  count = (count + 3)/4;
839 
840  LOG(VB_GENERAL, LOG_DEBUG,
841  QString("DBUtil::CountClients() found %1").arg(count));
842 
843  return count;
844 }
845 
849 bool DBUtil::TryLockSchema(MSqlQuery &query, uint timeout_secs)
850 {
851  query.prepare("SELECT GET_LOCK('schemaLock', :TIMEOUT)");
852  query.bindValue(":TIMEOUT", timeout_secs);
853  return query.exec() && query.first() && query.value(0).toBool();
854 }
855 
857 {
858  query.prepare("SELECT RELEASE_LOCK('schemaLock')");
859  if (!query.exec())
860  {
861  MythDB::DBError("DBUtil UnlockSchema", query);
862  }
863 }
864 
869 {
870  MSqlQuery query(MSqlQuery::InitCon());
871  query.prepare("SELECT CONVERT_TZ(NOW(), 'SYSTEM', 'Etc/UTC')");
872  if (!query.exec() || !query.next())
873  {
874  LOG(VB_GENERAL, LOG_ERR, "MySQL time zone support check failed");
875  return false;
876  }
877 
878  return !query.value(0).isNull();
879 }
880 
881 /* vim: set expandtab tabstop=4 shiftwidth=4: */
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
QStringList GetDirList(void) const
Definition: storagegroup.h:23
QString dbName
database name
Definition: mythdbparams.h:26
static bool RepairTables(const QStringList &tables)
Repairs database tables.
Definition: dbutil.cpp:336
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
DBUtil()
Constructs the DBUtil object.
Definition: dbutil.cpp:33
bool QueryDBMSVersion(void)
Reads and returns the QString version name from the DBMS or returns QString() in the event of an erro...
Definition: dbutil.cpp:746
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
bool ParseDBMSVersion(void)
Parses m_versionString to find the major, minor, and point version.
Definition: dbutil.cpp:775
int CompareDBMSVersion(int major, int minor=0, int point=0)
Compares the version of the active DBMS with the provided version.
Definition: dbutil.cpp:62
Default UTC, "yyyyMMddhhmmss".
Definition: mythdate.h:15
bool isConnected(void)
Only updated once during object creation.
Definition: mythdbcon.h:135
static bool CreateTemporaryDBConf(const QString &privateinfo, QString &filename)
Creates temporary file containing sensitive DB info.
Definition: dbutil.cpp:517
QString GetBackupDirectory()
Determines the appropriate path for the database backup.
Definition: dbutil.cpp:482
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static const int kUnknownVersionNumber
Definition: dbutil.h:54
QString dbPassword
DB password.
Definition: mythdbparams.h:25
int m_versionMajor
Definition: dbutil.h:77
QVariant value(int i) const
Definition: mythdbcon.h:198
static bool IsBackupInProgress(void)
Test to see if a DB backup is in progress.
Definition: dbutil.cpp:97
anonymize the logs
Definition: mythsystem.h:42
static int CountClients(void)
Estimate the number of MythTV programs using the database.
Definition: dbutil.cpp:807
int m_versionPoint
Definition: dbutil.h:79
QString dbUserName
DB user name.
Definition: mythdbparams.h:24
QSqlRecord record(void) const
Definition: mythdbcon.h:205
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QString GetSetting(const QString &key, const QString &defaultval="")
int m_versionMinor
Definition: dbutil.h:78
#define minor(X)
Definition: compat.h:138
QString GetShareDir(void)
Definition: mythdirs.cpp:222
QString m_versionString
Definition: dbutil.h:75
#define LOC
Definition: dbutil.cpp:26
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
uint myth_system(const QString &command, uint flags, uint timeout)
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:99
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
int FILE
Definition: mythburn.py:110
static QStringList CheckRepairStatus(MSqlQuery &query)
Parse the results of a CHECK TABLE or REPAIR TABLE run.
Definition: dbutil.cpp:383
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
Definition: mythdbcon.cpp:792
QString createTempFile(QString name_template, bool dir)
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
Structure containing the basic Database parameters.
Definition: mythdbparams.h:9
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QString dbHostName
database server
Definition: mythdbparams.h:21
QString CreateBackupFilename(const QString &prefix="mythconverg", const QString &extension=".sql")
Creates a filename to use for the filename.
Definition: dbutil.cpp:467
MythDBBackupStatus
Definition: dbutil.h:9
bool GetBoolSetting(const QString &key, bool defaultval=false)
static QStringList GetTables(const QStringList &engines=QStringList())
Retrieves a list of tables from the database.
Definition: dbutil.cpp:424
DatabaseParams GetDatabaseParams(void)
Default UTC, database format.
Definition: mythdate.h:24
static void UnlockSchema(MSqlQuery &)
Definition: dbutil.cpp:856
static bool TryLockSchema(MSqlQuery &, uint timeout_secs)
Try to get a lock on the table schemalock.
Definition: dbutil.cpp:849
QString GetDBMSVersion(void)
Returns the QString version name of the DBMS or QString() in the event of an error.
Definition: dbutil.cpp:43
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
int dbPort
database port
Definition: mythdbparams.h:23
QString GetHostName(void)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
static bool IsNewDatabase(void)
Returns true for a new (empty) database.
Definition: dbutil.cpp:83
MythDBBackupStatus BackupDB(QString &filename, bool disableRotation=false)
Requests a backup of the database.
Definition: dbutil.cpp:194
static bool CheckTimeZoneSupport(void)
Check if MySQL has working timz zone support.
Definition: dbutil.cpp:868
static bool CheckTables(const bool repair=false, const QString &options="QUICK")
Checks database tables.
Definition: dbutil.cpp:282
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:34
bool DoBackup(const QString &backupScript, QString &filename, bool disableRotation=false)
Creates a backup of the database by executing the backupScript.
Definition: dbutil.cpp:561