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 <QRegularExpression>
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 
35 {
36  if (m_versionString.isEmpty())
38  return m_versionString;
39 }
40 
53 int DBUtil::CompareDBMSVersion(int major, int minor, int point)
54 {
55  if (m_versionMajor < 0)
56  if (!ParseDBMSVersion())
57  return kUnknownVersionNumber;
58 
59  int result = 0;
61  std::array<int,3> compareto {major, minor, point};
62  for (int i = 0; i < 3 && !result; i++)
63  {
64  if ((version[i] > -1) || (compareto[i] != 0))
65  result = version[i] - compareto[i];
66  }
67 
68  return result;
69 }
70 
75 {
76  const QStringList tables = GetTables();
77  const int size = tables.size();
78  // Usually there will be a single table called schemalock, but check for
79  // no tables, also, just in case.
80  return (((size == 1) && (tables.at(0).endsWith(".`schemalock`"))) ||
81  (size == 0));
82 }
83 
89 {
90  QString backupStartTimeStr =
91  gCoreContext->GetSetting("BackupDBLastRunStart");
92  QString backupEndTimeStr = gCoreContext->GetSetting("BackupDBLastRunEnd");
93 
94  if (backupStartTimeStr.isEmpty())
95  {
96  LOG(VB_DATABASE, LOG_ERR, "DBUtil::BackupInProgress(): No start time "
97  "found, database backup is not in progress.");
98  return false;
99  }
100 
101  backupStartTimeStr.replace(" ", "T");
102 
103  QDateTime backupStartTime = MythDate::fromString(backupStartTimeStr);
104  auto backupElapsed = MythDate::secsInPast(backupStartTime);
105 
106  // No end time set
107  if (backupEndTimeStr.isEmpty())
108  {
109  // If DB Backup started less then 10 minutes ago, assume still running
110  if (backupElapsed < 10min)
111  {
112  LOG(VB_DATABASE, LOG_INFO,
113  QString("DBUtil::BackupInProgress(): Found "
114  "database backup start time of %1 which was %2 seconds "
115  "ago, therefore it appears the backup is still running.")
116  .arg(backupStartTimeStr)
117  .arg(backupElapsed.count()));
118  return true;
119  }
120  LOG(VB_DATABASE, LOG_ERR, QString("DBUtil::BackupInProgress(): "
121  "Database backup started at %1, but no end time was found. "
122  "The backup started %2 seconds ago and should have "
123  "finished by now therefore it appears it is not running .")
124  .arg(backupStartTimeStr)
125  .arg(backupElapsed.count()));
126  return false;
127  }
128 
129  backupEndTimeStr.replace(" ", "T");
130 
131  QDateTime backupEndTime = MythDate::fromString(backupEndTimeStr);
132 
133  if (backupEndTime >= backupStartTime)
134  {
135  LOG(VB_DATABASE, LOG_ERR,
136  QString("DBUtil::BackupInProgress(): Found "
137  "database backup end time of %1 later than start time "
138  "of %2, therefore backup is not running.")
139  .arg(backupEndTimeStr, backupStartTimeStr));
140  return false;
141  }
142  if (backupElapsed > 10min)
143  {
144  LOG(VB_DATABASE, LOG_ERR,
145  QString("DBUtil::BackupInProgress(): "
146  "Database backup started at %1, but has not ended yet. "
147  "The backup started %2 seconds ago and should have "
148  "finished by now therefore it appears it is not running")
149  .arg(backupStartTimeStr)
150  .arg(backupElapsed.count()));
151  return false;
152  }
153 
154  // start > end and started less than 10 minutes ago
155  LOG(VB_DATABASE, LOG_INFO, QString("DBUtil::BackupInProgress(): "
156  "Database backup started at %1, and is still running.")
157  .arg(backupStartTimeStr));
158  return true;
159 }
160 
187  [[maybe_unused]] bool disableRotation)
188 {
189  filename = QString();
190 
191 #ifdef _WIN32
192  LOG(VB_GENERAL, LOG_CRIT, "Database backups disabled on Windows.");
193  return kDB_Backup_Disabled;
194 #else
195 
196  if (gCoreContext->GetBoolSetting("DisableAutomaticBackup", false))
197  {
198  LOG(VB_GENERAL, LOG_CRIT,
199  "Database backups disabled. Skipping backup.");
200  return kDB_Backup_Disabled;
201  }
202 
203  if (IsNewDatabase())
204  {
205  LOG(VB_GENERAL, LOG_CRIT, "New database detected. Skipping backup.");
206  return kDB_Backup_Empty_DB;
207  }
208 
209  QString backupScript = GetShareDir() + "mythconverg_backup.pl";
210  backupScript = gCoreContext->GetSetting("DatabaseBackupScript",
211  backupScript);
212 
213  if (!QFile::exists(backupScript))
214  {
215  LOG(VB_GENERAL, LOG_CRIT, QString("Database backup script does "
216  "not exist: %1").arg(backupScript));
217  backupScript.clear();
218  }
219 
220  bool result = false;
221  MSqlQuery query(MSqlQuery::InitCon());
222 
224  "BackupDBLastRunStart",
226 
227  if (!backupScript.isEmpty())
228  {
229  result = DoBackup(backupScript, filename, disableRotation);
230  if (!result)
231  LOG(VB_GENERAL, LOG_CRIT, "Script-based database backup failed. "
232  "Retrying with internal backup.");
233  }
234 
235  if (!result)
236  result = DoBackup(filename);
237 
239  "BackupDBLastRunEnd",
241 
242  if (query.isConnected())
243  {
244  QString dbTag("BackupDB");
245  query.prepare("DELETE FROM housekeeping WHERE tag = :TAG ;");
246  query.bindValue(":TAG", dbTag);
247  if (!query.exec())
248  MythDB::DBError("DBUtil::BackupDB", query);
249 
250  query.prepare("INSERT INTO housekeeping(tag,lastrun) "
251  "values(:TAG ,now()) ;");
252  query.bindValue(":TAG", dbTag);
253  if (!query.exec())
254  MythDB::DBError("DBUtil::BackupDB", query);
255  }
256 
257  if (result)
258  return kDB_Backup_Completed;
259 
260  return kDB_Backup_Failed;
261 #endif // _WIN32
262 }
263 
275 bool DBUtil::CheckTables(const bool repair, const QString &options)
276 {
277  MSqlQuery query(MSqlQuery::InitCon());
278  if (!query.isConnected())
279  return false;
280 
281  const QStringList all_tables = GetTables(QStringList("MyISAM"));
282 
283  if (all_tables.empty())
284  return true;
285 
286  QString sql = QString("CHECK TABLE %1 %2;")
287  .arg(all_tables.join(", "), options);
288 
289  LOG(VB_GENERAL, LOG_CRIT, "Checking database tables.");
290  if (!query.exec(sql))
291  {
292  MythDB::DBError("DBUtil Checking Tables", query);
293  return false;
294  }
295 
296  QStringList tables = CheckRepairStatus(query);
297  bool result = true;
298  if (!tables.empty())
299  {
300  LOG(VB_GENERAL, LOG_CRIT, QString("Found crashed database table(s): %1")
301  .arg(tables.join(", ")));
302  if (repair)
303  {
304  // If RepairTables() repairs the crashed tables, return true
305  result = RepairTables(tables);
306  }
307  else
308  {
309  result = false;
310  }
311  }
312 
313  return result;
314 }
315 
333 bool DBUtil::RepairTables(const QStringList &tables)
334 {
335  MSqlQuery query(MSqlQuery::InitCon());
336  if (!query.isConnected())
337  return false;
338 
339  QString all_tables = tables.join(", ");
340  LOG(VB_GENERAL, LOG_CRIT, QString("Repairing database tables: %1")
341  .arg(all_tables));
342 
343  QString sql = QString("REPAIR TABLE %1;").arg(all_tables);
344  if (!query.exec(sql))
345  {
346  MythDB::DBError("DBUtil Repairing Tables", query);
347  return false;
348  }
349 
350  QStringList bad_tables = CheckRepairStatus(query);
351  bool result = true;
352  if (!bad_tables.empty())
353  {
354  LOG(VB_GENERAL, LOG_CRIT,
355  QString("Unable to repair crashed table(s): %1")
356  .arg(bad_tables.join(", ")));
357  result = false;
358  }
359  return result;
360 }
361 
381 {
382  QStringList tables;
383  QSqlRecord record = query.record();
384  int table_index = record.indexOf("Table");
385  int type_index = record.indexOf("Msg_type");
386  int text_index = record.indexOf("Msg_text");
387  QString table;
388  QString type;
389  QString text;
390  QString 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, time, 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  {
501  // Rather than use kDefaultStorageDir, the default for
502  // FindNextDirMostFree() when no dirs are defined for the StorageGroup,
503  // use /tmp as it's possible that kDefaultStorageDir doesn't exist
504  // and (at least on *nix) less possible that /tmp doesn't exist
505  directory = "/tmp";
506  }
507 
508  return directory;
509 }
510 
520  const QString &privateinfo, QString &filename)
521 {
522  bool ok = true;
523  filename = createTempFile("/tmp/mythtv_db_backup_conf_XXXXXX");
524  const QByteArray tmpfile = filename.toLocal8Bit();
525 
526  FILE *fp = fopen(tmpfile.constData(), "w");
527  if (!fp)
528  {
529  LOG(VB_GENERAL, LOG_ERR, LOC +
530  QString("Unable to create temporary "
531  "configuration file for creating DB backup: %1")
532  .arg(tmpfile.constData()));
533  filename = "";
534  ok = false;
535  }
536  else
537  {
538  if (chmod(tmpfile.constData(), S_IRUSR))
539  {
540  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error changing permissions '%1'")
541  .arg(tmpfile.constData()) + ENO);
542  }
543 
544  QByteArray outarr = privateinfo.toLocal8Bit();
545  fprintf(fp, "%s", outarr.constData());
546 
547  if (fclose(fp))
548  {
549  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error closing '%1'")
550  .arg(tmpfile.constData()) + ENO);
551  }
552  }
553 
554  return ok;
555 }
556 
563 bool DBUtil::DoBackup(const QString &backupScript, QString &filename,
564  bool disableRotation)
565 {
566  DatabaseParams dbParams = GetMythDB()->GetDatabaseParams();
567  QString dbSchemaVer = gCoreContext->GetSetting("DBSchemaVer");
568  QString backupDirectory = GetBackupDirectory();
569  QString backupFilename = CreateBackupFilename(dbParams.m_dbName + "-" +
570  dbSchemaVer, ".sql");
571  QString scriptArgs = gCoreContext->GetSetting("BackupDBScriptArgs");
572  QString rotate = "";
573  if (disableRotation)
574  {
575  if (!(scriptArgs.contains("rotate", Qt::CaseInsensitive)))
576  rotate = "rotate=-1";
577  }
578 
579 
580  QString privateinfo =
581  QString("DBHostName=%1\nDBPort=%2\n"
582  "DBUserName=%3\nDBPassword=%4\n"
583  "DBName=%5\nDBSchemaVer=%6\n"
584  "DBBackupDirectory=%7\nDBBackupFilename=%8\n%9\n")
585  .arg(dbParams.m_dbHostName, QString::number(dbParams.m_dbPort),
586  dbParams.m_dbUserName, dbParams.m_dbPassword,
587  dbParams.m_dbName, dbSchemaVer,
588  backupDirectory, backupFilename,
589  rotate);
590  QString tempDatabaseConfFile;
591  bool hastemp = CreateTemporaryDBConf(privateinfo, tempDatabaseConfFile);
592  if (!hastemp)
593  LOG(VB_GENERAL, LOG_ERR, LOC + "Attempting backup, anyway.");
594 
595  LOG(VB_GENERAL, LOG_ERR, QString("Backing up database with script: '%1'")
596  .arg(backupScript));
597 
598  QString command = backupScript + " " + scriptArgs + " " +
599  tempDatabaseConfFile;
601 
602  if (hastemp)
603  {
604  QByteArray tmpfile = tempDatabaseConfFile.toLocal8Bit();
605  unlink(tmpfile.constData());
606  }
607 
608  if (status != GENERIC_EXIT_OK)
609  {
610  LOG(VB_GENERAL, LOG_ERR, LOC +
611  QString("Error backing up database: %1 (%2)")
612  .arg(command).arg(status));
613  filename = "__FAILED__";
614  return false;
615  }
616 
617  LOG(VB_GENERAL, LOG_CRIT, "Database Backup complete.");
618 
619  QDir dir(backupDirectory, backupFilename + "*");
620  uint numfiles = dir.count();
621  if (numfiles < 1)
622  {
623  // If no file begins with the suggested filename, don't show the backup
624  // filename in the GUI message -- the script probably used some other
625  // filename
626  filename = "";
627  LOG(VB_FILE, LOG_ERR, LOC +
628  QString("No files beginning with the suggested database backup "
629  "filename '%1' were found in '%2'.")
630  .arg(backupFilename, backupDirectory));
631  }
632  else
633  {
634  filename = dir.path() + "/" + dir[0];;
635  if (numfiles > 1)
636  {
637  LOG(VB_FILE, LOG_ERR, LOC +
638  QString("Multiple files beginning with the suggested database "
639  "backup filename '%1' were found in '%2'. "
640  "Assuming the first is the backup.")
641  .arg(backupFilename, backupDirectory));
642  }
643  }
644 
645  if (!filename.isEmpty())
646  {
647  LOG(VB_GENERAL, LOG_CRIT, QString("Backed up database to file: '%1'")
648  .arg(filename));
649  }
650 
651  return true;
652 }
653 
661 {
662  DatabaseParams dbParams = GetMythDB()->GetDatabaseParams();
663  QString dbSchemaVer = gCoreContext->GetSetting("DBSchemaVer");
664  QString backupDirectory = GetBackupDirectory();
665 
666  QString command;
667  QString compressCommand("");
668  QString extension = ".sql";
669  if (QFile::exists("/bin/gzip"))
670  compressCommand = "/bin/gzip";
671  else if (QFile::exists("/usr/bin/gzip"))
672  compressCommand = "/usr/bin/gzip";
673  else
674  LOG(VB_GENERAL, LOG_CRIT, "Neither /bin/gzip nor /usr/bin/gzip exist. "
675  "The database backup will be uncompressed.");
676 
677  QString backupFilename = CreateBackupFilename(
678  dbParams.m_dbName + "-" + dbSchemaVer, extension);
679  QString backupPathname = backupDirectory + "/" + backupFilename;
680 
681  QString privateinfo = QString(
682  "[client]\npassword=%1\n[mysqldump]\npassword=%2\n")
683  .arg(dbParams.m_dbPassword, dbParams.m_dbPassword);
684  QString tempExtraConfFile;
685  if (!CreateTemporaryDBConf(privateinfo, tempExtraConfFile))
686  return false;
687 
688  QString portArg = "";
689  if (dbParams.m_dbPort > 0)
690  portArg = QString(" --port='%1'").arg(dbParams.m_dbPort);
691  command = QString("mysqldump --defaults-extra-file='%1' --host='%2'%3"
692  " --user='%4' --add-drop-table --add-locks"
693  " --allow-keywords --complete-insert"
694  " --extended-insert --lock-tables --no-create-db --quick"
695  " '%5' > '%6' 2>/dev/null")
696  .arg(tempExtraConfFile, dbParams.m_dbHostName,
697  portArg, dbParams.m_dbUserName,
698  dbParams.m_dbName, backupPathname);
699 
700  LOG(VB_FILE, LOG_INFO, QString("Backing up database with command: '%1'")
701  .arg(command));
702  LOG(VB_GENERAL, LOG_CRIT, QString("Backing up database to file: '%1'")
703  .arg(backupPathname));
704 
706 
707  QByteArray tmpfile = tempExtraConfFile.toLocal8Bit();
708  unlink(tmpfile.constData());
709 
710  if (status != GENERIC_EXIT_OK)
711  {
712  LOG(VB_GENERAL, LOG_ERR, LOC +
713  QString("Error backing up database: '%1' (%2)")
714  .arg(command).arg(status));
715  filename = "__FAILED__";
716  return false;
717  }
718 
719  if (compressCommand != "")
720  {
721  LOG(VB_GENERAL, LOG_CRIT, "Compressing database backup file.");
722  compressCommand += " " + backupPathname;
723  status = myth_system(compressCommand, kMSDontBlockInputDevs);
724 
725  if (status != GENERIC_EXIT_OK)
726  {
727  LOG(VB_GENERAL, LOG_CRIT,
728  "Compression failed, backup file will remain uncompressed.");
729  }
730  else
731  {
732  backupPathname += ".gz";
733 
734  LOG(VB_GENERAL, LOG_CRIT, QString("Database Backup filename: '%1'")
735  .arg(backupPathname));
736  }
737  }
738 
739  LOG(VB_GENERAL, LOG_CRIT, "Database Backup complete.");
740 
741  filename = backupPathname;
742  return true;
743 }
744 
750 {
751  // Allow users to override the string provided by the database server in
752  // case the value was changed to an unrecognizable string by whomever
753  // compiled the MySQL server
754  QString dbmsVersion = gCoreContext->GetSetting("DBMSVersionOverride");
755 
756  if (dbmsVersion.isEmpty())
757  {
758  MSqlQuery query(MSqlQuery::InitCon());
759  query.prepare("SELECT VERSION();");
760  if (!query.exec() || !query.next())
761  {
762  LOG(VB_GENERAL, LOG_ERR, LOC +
763  "Unable to determine MySQL version.");
764  MythDB::DBError("DBUtil Querying DBMS version", query);
765  dbmsVersion.clear();
766  }
767  else
768  {
769  dbmsVersion = query.value(0).toString();
770  }
771  }
772  m_versionString = dbmsVersion;
773 
774  return !m_versionString.isEmpty();
775 }
776 
781 {
782  if (m_versionString.isEmpty())
783  if (!QueryDBMSVersion())
784  return false;
785 
786  static const QRegularExpression parseVersion
787  { R"(^(\d+)(?:\.(\d+)(?:\.(\d+))?)?)" };
788  auto match = parseVersion.match(m_versionString);
789  if (!match.hasMatch())
790  return false;
791 
792  // If any of these wasn't matched, the captured string will be
793  // empty and toInt will parse it as a zero.
794  m_versionMajor = match.capturedView(1).toInt(nullptr);
795  m_versionMinor = match.capturedView(2).toInt(nullptr);
796  m_versionPoint = match.capturedView(3).toInt(nullptr);
797 
798  return m_versionMajor > -1;
799 }
800 
805 {
806  int count = 0;
807 
808  MSqlQuery query(MSqlQuery::InitCon());
809  if (!query.isConnected())
810  {
811  LOG(VB_GENERAL, LOG_DEBUG, "Not connected to DB");
812  return count;
813  }
814 
815  if (!query.exec("SHOW PROCESSLIST;"))
816  {
817  MythDB::DBError("DBUtil CountClients", query);
818  return count;
819  }
820 
821  QSqlRecord record = query.record();
822  int db_index = record.indexOf("db");
823  QString dbName = GetMythDB()->GetDatabaseName();
824  QString inUseDB;
825 
826  while (query.next())
827  {
828  inUseDB = query.value(db_index).toString();
829  if (inUseDB == dbName)
830  ++count;
831  }
832 
833  // On average, each myth program has 4 database connections,
834  // but we round up just in case a new program is loading:
835  count = (count + 3)/4;
836 
837  LOG(VB_GENERAL, LOG_DEBUG,
838  QString("DBUtil::CountClients() found %1").arg(count));
839 
840  return count;
841 }
842 
846 bool DBUtil::TryLockSchema(MSqlQuery &query, uint timeout_secs)
847 {
848  query.prepare("SELECT GET_LOCK('schemaLock', :TIMEOUT)");
849  query.bindValue(":TIMEOUT", timeout_secs);
850  return query.exec() && query.first() && query.value(0).toBool();
851 }
852 
854 {
855  query.prepare("SELECT RELEASE_LOCK('schemaLock')");
856  if (!query.exec())
857  {
858  MythDB::DBError("DBUtil UnlockSchema", query);
859  }
860 }
861 
866 {
867  MSqlQuery query(MSqlQuery::InitCon());
868  query.prepare("SELECT CONVERT_TZ(NOW(), 'SYSTEM', 'Etc/UTC')");
869  if (!query.exec() || !query.next())
870  {
871  LOG(VB_GENERAL, LOG_ERR, "MySQL time zone support check failed");
872  return false;
873  }
874 
875  return !query.value(0).isNull();
876 }
877 
889 bool DBUtil::CheckTableColumnExists(const QString &tableName, const QString &columnName)
890 {
891  MSqlQuery query(MSqlQuery::InitCon());
892  if (!query.isConnected())
893  return false;
894 
895  QString sql = QString("SELECT COUNT(*) FROM information_schema.columns "
896  "WHERE table_schema = DATABASE() AND "
897  "table_name = '%1' AND column_name = '%2';")
898  .arg(tableName, columnName);
899  LOG(VB_GENERAL, LOG_DEBUG,
900  QString("DBUtil::CheckTableColumnExists() SQL: %1").arg(sql));
901 
902  if (!query.exec(sql))
903  {
904  MythDB::DBError("DBUtil Check Table Column Exists", query);
905  return false;
906  }
907 
908  bool result = false;
909  if (query.next())
910  {
911  result = (query.value(0).toInt() > 0);
912  }
913  else
914  {
915  LOG(VB_GENERAL, LOG_ERR,
916  QString("DBUtil::CheckTableColumnExists() - Empty result set"));
917  }
918 
919  LOG(VB_GENERAL, LOG_DEBUG,
920  QString("DBUtil::CheckTableColumnExists('%1', '%2') result: %3").arg(tableName,
921  columnName, QVariant(result).toString()));
922 
923  return result;
924 }
925 
926 /* vim: set expandtab tabstop=4 shiftwidth=4: */
kDB_Backup_Disabled
@ kDB_Backup_Disabled
Definition: dbutil.h:15
DBUtil::QueryDBMSVersion
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:749
MythDBBackupStatus
MythDBBackupStatus
Definition: dbutil.h:9
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
LOC
#define LOC
Definition: dbutil.cpp:26
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:93
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
DatabaseParams::m_dbHostName
QString m_dbHostName
database server
Definition: mythdbparams.h:22
DBUtil::CheckTableColumnExists
static bool CheckTableColumnExists(const QString &tableName, const QString &columnName)
Checks for the presence of a column in a table in the current database.
Definition: dbutil.cpp:889
dbutil.h
kMSDontBlockInputDevs
@ kMSDontBlockInputDevs
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:36
kMSAnonLog
@ kMSAnonLog
anonymize the logs
Definition: mythsystem.h:44
mythdb.h
DatabaseParams
Structure containing the basic Database parameters.
Definition: mythdbparams.h:10
MSqlQuery::record
QSqlRecord record(void) const
Definition: mythdbcon.h:216
DBUtil::CreateBackupFilename
static QString CreateBackupFilename(const QString &prefix="mythconverg", const QString &extension=".sql")
Creates a filename to use for the filename.
Definition: dbutil.cpp:467
DBUtil::IsBackupInProgress
static bool IsBackupInProgress(void)
Test to see if a DB backup is in progress.
Definition: dbutil.cpp:88
xbmcvfs.exists
bool exists(str path)
Definition: xbmcvfs.py:51
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
DBUtil::CheckTables
static bool CheckTables(bool repair=false, const QString &options="QUICK")
Checks database tables.
Definition: dbutil.cpp:275
GetMythDB
MythDB * GetMythDB(void)
Definition: mythdb.cpp:50
mythdirs.h
myth_system
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
Definition: mythsystemlegacy.cpp:506
hardwareprofile.distros.mythtv_data.data_mythtv.prefix
string prefix
Definition: data_mythtv.py:40
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
mythburn.FILE
int FILE
Definition: mythburn.py:139
DBUtil::ParseDBMSVersion
bool ParseDBMSVersion(void)
Parses m_versionString to find the major, minor, and point version.
Definition: dbutil.cpp:780
mythsystemlegacy.h
DBUtil::m_versionMinor
int m_versionMinor
Definition: dbutil.h:82
DBUtil::GetDBMSVersion
QString GetDBMSVersion(void)
Returns the QString version name of the DBMS or QString() in the event of an error.
Definition: dbutil.cpp:34
DBUtil::m_versionString
QString m_versionString
Definition: dbutil.h:79
DatabaseParams::m_dbPort
int m_dbPort
database port
Definition: mythdbparams.h:24
mythdate.h
minor
#define minor(X)
Definition: compat.h:78
mythlogging.h
DBUtil::CheckRepairStatus
static QStringList CheckRepairStatus(MSqlQuery &query)
Parse the results of a CHECK TABLE or REPAIR TABLE run.
Definition: dbutil.cpp:380
DBUtil::CreateTemporaryDBConf
static bool CreateTemporaryDBConf(const QString &privateinfo, QString &filename)
Creates temporary file containing sensitive DB info.
Definition: dbutil.cpp:519
MythDate::kFilename
@ kFilename
Default UTC, "yyyyMMddhhmmss".
Definition: mythdate.h:18
MSqlQuery::first
bool first(void)
Wrap QSqlQuery::first() so we can display the query results.
Definition: mythdbcon.cpp:822
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:225
kDB_Backup_Empty_DB
@ kDB_Backup_Empty_DB
Definition: dbutil.h:14
GetShareDir
QString GetShareDir(void)
Definition: mythdirs.cpp:254
createTempFile
QString createTempFile(QString name_template, bool dir)
Definition: mythmiscutil.cpp:323
DBUtil::BackupDB
static MythDBBackupStatus BackupDB(QString &filename, bool disableRotation=false)
Requests a backup of the database.
Definition: dbutil.cpp:186
DBUtil::CheckTimeZoneSupport
static bool CheckTimeZoneSupport(void)
Check if MySQL has working timz zone support.
Definition: dbutil.cpp:865
storagegroup.h
DBUtil::CountClients
static int CountClients(void)
Estimate the number of MythTV programs using the database.
Definition: dbutil.cpp:804
DBUtil::m_versionPoint
int m_versionPoint
Definition: dbutil.h:83
DBUtil::DoBackup
static bool DoBackup(const QString &backupScript, QString &filename, bool disableRotation=false)
Creates a backup of the database by executing the backupScript.
Definition: dbutil.cpp:563
DatabaseParams::m_dbPassword
QString m_dbPassword
DB password.
Definition: mythdbparams.h:26
DatabaseParams::m_dbName
QString m_dbName
database name
Definition: mythdbparams.h:27
StorageGroup::GetDirList
QStringList GetDirList(void) const
Definition: storagegroup.h:23
MSqlQuery::isConnected
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:137
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
DBUtil::TryLockSchema
static bool TryLockSchema(MSqlQuery &query, uint timeout_secs)
Try to get a lock on the table schemalock.
Definition: dbutil.cpp:846
DBUtil::RepairTables
static bool RepairTables(const QStringList &tables)
Repairs database tables.
Definition: dbutil.cpp:333
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:910
mythmiscutil.h
MythDate::secsInPast
std::chrono::seconds secsInPast(const QDateTime &past)
Definition: mythdate.cpp:212
mythcorecontext.h
StorageGroup::FindNextDirMostFree
QString FindNextDirMostFree(void)
Definition: storagegroup.cpp:666
DBUtil::GetBackupDirectory
static QString GetBackupDirectory()
Determines the appropriate path for the database backup.
Definition: dbutil.cpp:482
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
DatabaseParams::m_dbUserName
QString m_dbUserName
DB user name.
Definition: mythdbparams.h:25
DBUtil::kUnknownVersionNumber
static const int kUnknownVersionNumber
Definition: dbutil.h:58
kDB_Backup_Completed
@ kDB_Backup_Completed
Definition: dbutil.h:13
DBUtil::m_versionMajor
int m_versionMajor
Definition: dbutil.h:81
DBUtil::IsNewDatabase
static bool IsNewDatabase(void)
Returns true for a new (empty) database.
Definition: dbutil.cpp:74
StorageGroup
Definition: storagegroup.h:11
MythDate::kDatabase
@ kDatabase
Default UTC, database format.
Definition: mythdate.h:27
DBUtil::UnlockSchema
static void UnlockSchema(MSqlQuery &query)
Definition: dbutil.cpp:853
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:842
exitcodes.h
DBUtil::GetTables
static QStringList GetTables(const QStringList &engines=QStringList())
Retrieves a list of tables from the database.
Definition: dbutil.cpp:424
build_compdb.filename
filename
Definition: build_compdb.py:21
kDB_Backup_Failed
@ kDB_Backup_Failed
Definition: dbutil.h:12
nv_python_libs.bbciplayer.bbciplayer_api.version
string version
Definition: bbciplayer_api.py:77
build_compdb.options
options
Definition: build_compdb.py:11
MythCoreContext::SaveSettingOnHost
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
Definition: mythcorecontext.cpp:895
uint
unsigned int uint
Definition: freesurround.h:24
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:902
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
DBUtil::CompareDBMSVersion
int CompareDBMSVersion(int major, int minor=0, int point=0)
Compares the version of the active DBMS with the provided version.
Definition: dbutil.cpp:53