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