00001 #include <climits>
00002 #include <stdlib.h>
00003 #include <stdio.h>
00004 #include <sys/types.h>
00005 #include <sys/stat.h>
00006 #include <unistd.h>
00007
00008 #include <QDir>
00009 #include <QFile>
00010 #include <QRegExp>
00011 #include <QDateTime>
00012 #include <QSqlError>
00013 #include <QSqlRecord>
00014
00015 #include "dbutil.h"
00016 #include "mythcorecontext.h"
00017 #include "storagegroup.h"
00018 #include "mythmiscutil.h"
00019 #include "mythdb.h"
00020 #include "mythdirs.h"
00021 #include "mythlogging.h"
00022 #include "mythsystem.h"
00023 #include "exitcodes.h"
00024
00025 #define LOC QString("DBUtil: ")
00026
00027 const int DBUtil::kUnknownVersionNumber = INT_MIN;
00028
00032 DBUtil::DBUtil(void)
00033 : m_versionString(QString::null), m_versionMajor(-1), m_versionMinor(-1),
00034 m_versionPoint(-1)
00035 {
00036 }
00037
00042 QString DBUtil::GetDBMSVersion(void)
00043 {
00044 if (m_versionString.isEmpty())
00045 QueryDBMSVersion();
00046 return m_versionString;
00047 }
00048
00061 int DBUtil::CompareDBMSVersion(int major, int minor, int point)
00062 {
00063 if (m_versionMajor < 0)
00064 if (!ParseDBMSVersion())
00065 return kUnknownVersionNumber;
00066
00067 int result = 0;
00068 int version[3] = {m_versionMajor, m_versionMinor, m_versionPoint};
00069 int compareto[3] = {major, minor, point};
00070 for (int i = 0; i < 3 && !result; i++)
00071 {
00072 if ((version[i] > -1) || (compareto[i] != 0))
00073 result = version[i] - compareto[i];
00074 }
00075
00076 return result;
00077 }
00078
00082 bool DBUtil::IsNewDatabase(void)
00083 {
00084 const QStringList tables = GetTables();
00085 const int size = tables.size();
00086
00087
00088 return (((size == 1) && (tables.at(0).endsWith(".`schemalock`"))) ||
00089 (size == 0));
00090 }
00091
00096 bool DBUtil::IsBackupInProgress(void)
00097 {
00098 QString backupStartTimeStr =
00099 gCoreContext->GetSetting("BackupDBLastRunStart");
00100 QString backupEndTimeStr = gCoreContext->GetSetting("BackupDBLastRunEnd");
00101
00102 if (backupStartTimeStr.isEmpty())
00103 {
00104 LOG(VB_DATABASE, LOG_ERR, "DBUtil::BackupInProgress(): No start time "
00105 "found, database backup is not in progress.");
00106 return false;
00107 }
00108
00109 backupStartTimeStr.replace(" ", "T");
00110
00111 QDateTime backupStartTime =
00112 QDateTime::fromString(backupStartTimeStr, Qt::ISODate);
00113
00114
00115 if (backupEndTimeStr.isEmpty())
00116 {
00117
00118 if (backupStartTime.secsTo(QDateTime::currentDateTime()) < 600)
00119 {
00120 LOG(VB_DATABASE, LOG_INFO,
00121 QString("DBUtil::BackupInProgress(): Found "
00122 "database backup start time of %1 which was %2 seconds "
00123 "ago, therefore it appears the backup is still running.")
00124 .arg(backupStartTimeStr)
00125 .arg(backupStartTime.secsTo(QDateTime::currentDateTime())));
00126 return true;
00127 }
00128 else
00129 {
00130 LOG(VB_DATABASE, LOG_ERR, QString("DBUtil::BackupInProgress(): "
00131 "Database backup started at %1, but no end time was found. "
00132 "The backup started %2 seconds ago and should have "
00133 "finished by now therefore it appears it is not running .")
00134 .arg(backupStartTimeStr)
00135 .arg(backupStartTime.secsTo(QDateTime::currentDateTime())));
00136 return false;
00137 }
00138 }
00139 else
00140 {
00141 backupEndTimeStr.replace(" ", "T");
00142
00143 QDateTime backupEndTime =
00144 QDateTime::fromString(backupEndTimeStr, Qt::ISODate);
00145
00146 if (backupEndTime >= backupStartTime)
00147 {
00148 LOG(VB_DATABASE, LOG_ERR,
00149 QString("DBUtil::BackupInProgress(): Found "
00150 "database backup end time of %1 later than start time "
00151 "of %2, therefore backup is not running.")
00152 .arg(backupEndTimeStr).arg(backupStartTimeStr));
00153 return false;
00154 }
00155 else if (backupStartTime.secsTo(QDateTime::currentDateTime()) > 600)
00156 {
00157 LOG(VB_DATABASE, LOG_ERR,
00158 QString("DBUtil::BackupInProgress(): "
00159 "Database backup started at %1, but has not ended yet. "
00160 "The backup started %2 seconds ago and should have "
00161 "finished by now therefore it appears it is not running")
00162 .arg(backupStartTimeStr)
00163 .arg(backupStartTime.secsTo(QDateTime::currentDateTime())));
00164 return false;
00165 }
00166 else
00167 {
00168
00169 LOG(VB_DATABASE, LOG_INFO, QString("DBUtil::BackupInProgress(): "
00170 "Database backup started at %1, and is still running.")
00171 .arg(backupStartTimeStr));
00172 return true;
00173 }
00174 }
00175
00176
00177 return false;
00178 }
00179
00205 MythDBBackupStatus DBUtil::BackupDB(QString &filename, bool disableRotation)
00206 {
00207 filename = QString();
00208
00209 #ifdef USING_MINGW
00210 LOG(VB_GENERAL, LOG_CRIT, "Database backups disabled on Windows.");
00211 return kDB_Backup_Disabled;
00212 #else
00213
00214 if (gCoreContext->GetNumSetting("DisableAutomaticBackup", 0))
00215 {
00216 LOG(VB_GENERAL, LOG_CRIT,
00217 "Database backups disabled. Skipping backup.");
00218 return kDB_Backup_Disabled;
00219 }
00220
00221 if (IsNewDatabase())
00222 {
00223 LOG(VB_GENERAL, LOG_CRIT, "New database detected. Skipping backup.");
00224 return kDB_Backup_Empty_DB;
00225 }
00226
00227 QString backupScript = GetShareDir() + "mythconverg_backup.pl";
00228 backupScript = gCoreContext->GetSetting("DatabaseBackupScript",
00229 backupScript);
00230
00231 if (!QFile::exists(backupScript))
00232 {
00233 LOG(VB_GENERAL, LOG_CRIT, QString("Database backup script does "
00234 "not exist: %1").arg(backupScript));
00235 backupScript = QString::null;
00236 }
00237
00238 bool result = false;
00239 MSqlQuery query(MSqlQuery::InitCon());
00240
00241 gCoreContext->SaveSettingOnHost("BackupDBLastRunStart",
00242 QDateTime::currentDateTime()
00243 .toString("yyyy-MM-dd hh:mm:ss"), NULL);
00244
00245 if (!backupScript.isEmpty())
00246 {
00247 result = DoBackup(backupScript, filename, disableRotation);
00248 if (!result)
00249 LOG(VB_GENERAL, LOG_CRIT, "Script-based database backup failed. "
00250 "Retrying with internal backup.");
00251 }
00252
00253 if (!result)
00254 result = DoBackup(filename);
00255
00256 gCoreContext->SaveSettingOnHost("BackupDBLastRunEnd",
00257 QDateTime::currentDateTime()
00258 .toString("yyyy-MM-dd hh:mm:ss"), NULL);
00259
00260 if (query.isConnected())
00261 {
00262 QString dbTag("BackupDB");
00263 query.prepare("DELETE FROM housekeeping WHERE tag = :TAG ;");
00264 query.bindValue(":TAG", dbTag);
00265 if (!query.exec())
00266 MythDB::DBError("DBUtil::BackupDB", query);
00267
00268 query.prepare("INSERT INTO housekeeping(tag,lastrun) "
00269 "values(:TAG ,now()) ;");
00270 query.bindValue(":TAG", dbTag);
00271 if (!query.exec())
00272 MythDB::DBError("DBUtil::BackupDB", query);
00273 }
00274
00275 if (result)
00276 return kDB_Backup_Completed;
00277
00278 return kDB_Backup_Failed;
00279 #endif // USING_MINGW
00280 }
00281
00293 bool DBUtil::CheckTables(const bool repair, const QString options)
00294 {
00295 MSqlQuery query(MSqlQuery::InitCon());
00296 if (!query.isConnected())
00297 return false;
00298
00299 const QStringList all_tables = GetTables(QStringList("MyISAM"));
00300
00301 if (all_tables.empty())
00302 return true;
00303
00304 QString sql = QString("CHECK TABLE %1 %2;").arg(all_tables.join(", "))
00305 .arg(options);
00306
00307 LOG(VB_GENERAL, LOG_CRIT, "Checking database tables.");
00308 if (!query.exec(sql))
00309 {
00310 MythDB::DBError("DBUtil Checking Tables", query);
00311 return false;
00312 }
00313
00314 QStringList tables = CheckRepairStatus(query);
00315 bool result = true;
00316 if (!tables.empty())
00317 {
00318 LOG(VB_GENERAL, LOG_CRIT, QString("Found crashed database table(s): %1")
00319 .arg(tables.join(", ")));
00320 if (repair == true)
00321
00322 result = RepairTables(tables);
00323 else
00324 result = false;
00325 }
00326
00327 return result;
00328 }
00329
00347 bool DBUtil::RepairTables(const QStringList &tables)
00348 {
00349 MSqlQuery query(MSqlQuery::InitCon());
00350 if (!query.isConnected())
00351 return false;
00352
00353 QString all_tables = tables.join(", ");
00354 LOG(VB_GENERAL, LOG_CRIT, QString("Repairing database tables: %1")
00355 .arg(all_tables));
00356
00357 QString sql = QString("REPAIR TABLE %1;").arg(all_tables);
00358 if (!query.exec(sql))
00359 {
00360 MythDB::DBError("DBUtil Repairing Tables", query);
00361 return false;
00362 }
00363
00364 QStringList bad_tables = CheckRepairStatus(query);
00365 bool result = true;
00366 if (!bad_tables.empty())
00367 {
00368 LOG(VB_GENERAL, LOG_CRIT,
00369 QString("Unable to repair crashed table(s): %1")
00370 .arg(bad_tables.join(", ")));
00371 result = false;
00372 }
00373 return result;
00374 }
00375
00394 QStringList DBUtil::CheckRepairStatus(MSqlQuery &query)
00395 {
00396 QStringList tables;
00397 QSqlRecord record = query.record();
00398 int table_index = record.indexOf("Table");
00399 int type_index = record.indexOf("Msg_type");
00400 int text_index = record.indexOf("Msg_text");
00401 QString table, type, text, previous_table;
00402 bool ok = true;
00403 while (query.next())
00404 {
00405 table = query.value(table_index).toString();
00406 type = query.value(type_index).toString();
00407 text = query.value(text_index).toString();
00408 if (table != previous_table)
00409 {
00410 if (!ok)
00411 {
00412 tables.append(previous_table);
00413 ok = true;
00414 }
00415 previous_table = table;
00416 }
00417
00418 if ("status" == type.toLower() && "ok" == text.toLower())
00419 ok = true;
00420 else if ("error" == type.toLower() ||
00421 ("status" == type.toLower() && "ok" != text.toLower()))
00422 ok = false;
00423 }
00424
00425 if (!ok)
00426 tables.append(table);
00427 return tables;
00428 }
00429
00435 QStringList DBUtil::GetTables(const QStringList &engines)
00436 {
00437 QStringList result;
00438
00439 MSqlQuery query(MSqlQuery::InitCon());
00440 if (!query.isConnected())
00441 return result;
00442
00443 QString sql = "SELECT CONCAT('`', INFORMATION_SCHEMA.TABLES.TABLE_SCHEMA, "
00444 " '`.`', INFORMATION_SCHEMA.TABLES.TABLE_NAME, "
00445 " '`') AS `TABLE_NAME` "
00446 " FROM INFORMATION_SCHEMA.TABLES "
00447 " WHERE INFORMATION_SCHEMA.TABLES.TABLE_SCHEMA = DATABASE() "
00448 " AND INFORMATION_SCHEMA.TABLES.TABLE_TYPE = 'BASE TABLE'";
00449 if (!engines.empty())
00450 sql.append(QString(" AND INFORMATION_SCHEMA.TABLES.ENGINE IN ('%1')")
00451 .arg(engines.join("', '")));
00452 if (!query.exec(sql))
00453 {
00454 MythDB::DBError("DBUtil Finding Tables", query);
00455 return result;
00456 }
00457
00458 while (query.next())
00459 {
00460 result.append(query.value(0).toString());
00461 }
00462
00463 return result;
00464 }
00465
00478 QString DBUtil::CreateBackupFilename(QString prefix, QString extension)
00479 {
00480 QDateTime now = QDateTime::currentDateTime();
00481 QString time = now.toString("yyyyMMddhhmmss");
00482 return QString("%1-%2%3").arg(prefix).arg(time).arg(extension);
00483 }
00484
00494 QString DBUtil::GetBackupDirectory()
00495 {
00496 QString directory;
00497 StorageGroup sgroup("DB Backups", gCoreContext->GetHostName());
00498 QStringList dirList = sgroup.GetDirList();
00499 if (dirList.size())
00500 {
00501 directory = sgroup.FindNextDirMostFree();
00502
00503 if (!QDir(directory).exists())
00504 {
00505 LOG(VB_FILE, LOG_INFO, "GetBackupDirectory() - ignoring " +
00506 directory + ", using /tmp");
00507 directory = QString::null;
00508 }
00509 }
00510
00511 if (directory.isNull())
00512
00513
00514
00515
00516 directory = "/tmp";
00517
00518 return directory;
00519 }
00520
00529 bool DBUtil::CreateTemporaryDBConf(
00530 const QString &privateinfo, QString &filename)
00531 {
00532 bool ok = true;
00533 filename = createTempFile("/tmp/mythtv_db_backup_conf_XXXXXX");
00534 const QByteArray tmpfile = filename.toLocal8Bit();
00535 const DatabaseParams dbParams = gCoreContext->GetDatabaseParams();
00536 const QString dbSchemaVer = gCoreContext->GetSetting("DBSchemaVer");
00537
00538 FILE *fp = fopen(tmpfile.constData(), "w");
00539 if (!fp)
00540 {
00541 LOG(VB_GENERAL, LOG_ERR, LOC +
00542 QString("Unable to create temporary "
00543 "configuration file for creating DB backup: %1")
00544 .arg(tmpfile.constData()));
00545 filename = "";
00546 ok = false;
00547 }
00548 else
00549 {
00550 chmod(tmpfile.constData(), S_IRUSR);
00551
00552 QByteArray outarr = privateinfo.toLocal8Bit();
00553 fprintf(fp, "%s", outarr.constData());
00554
00555 if (fclose(fp))
00556 {
00557 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error closing '%1'")
00558 .arg(tmpfile.constData()) + ENO);
00559 }
00560 }
00561
00562 return ok;
00563 }
00564
00571 bool DBUtil::DoBackup(const QString &backupScript, QString &filename,
00572 bool disableRotation)
00573 {
00574 DatabaseParams dbParams = gCoreContext->GetDatabaseParams();
00575 QString dbSchemaVer = gCoreContext->GetSetting("DBSchemaVer");
00576 QString backupDirectory = GetBackupDirectory();
00577 QString backupFilename = CreateBackupFilename(dbParams.dbName + "-" +
00578 dbSchemaVer, ".sql");
00579 QString scriptArgs = gCoreContext->GetSetting("BackupDBScriptArgs");
00580 QString rotate = "";
00581 if (disableRotation)
00582 {
00583 if (!(scriptArgs.contains("rotate", Qt::CaseInsensitive)))
00584 rotate = "rotate=-1";
00585 }
00586
00587
00588 QString privateinfo =
00589 QString("DBHostName=%1\nDBPort=%2\n"
00590 "DBUserName=%3\nDBPassword=%4\n"
00591 "DBName=%5\nDBSchemaVer=%6\n"
00592 "DBBackupDirectory=%7\nDBBackupFilename=%8\n%9\n")
00593 .arg(dbParams.dbHostName).arg(dbParams.dbPort)
00594 .arg(dbParams.dbUserName).arg(dbParams.dbPassword)
00595 .arg(dbParams.dbName).arg(dbSchemaVer)
00596 .arg(backupDirectory).arg(backupFilename).arg(rotate);
00597 QString tempDatabaseConfFile = QString::null;
00598 bool hastemp = CreateTemporaryDBConf(privateinfo, tempDatabaseConfFile);
00599 if (!hastemp)
00600 LOG(VB_GENERAL, LOG_ERR, LOC + "Attempting backup, anyway.");
00601
00602 LOG(VB_GENERAL, LOG_ERR, QString("Backing up database with script: '%1'")
00603 .arg(backupScript));
00604
00605 QString command = backupScript + " " + scriptArgs + " " +
00606 tempDatabaseConfFile;
00607 uint status = myth_system(command, kMSDontBlockInputDevs|kMSAnonLog);
00608
00609 if (hastemp)
00610 {
00611 QByteArray tmpfile = tempDatabaseConfFile.toLocal8Bit();
00612 unlink(tmpfile.constData());
00613 }
00614
00615 if (status != GENERIC_EXIT_OK)
00616 {
00617 LOG(VB_GENERAL, LOG_ERR, LOC +
00618 QString("Error backing up database: %1 (%2)")
00619 .arg(command).arg(status));
00620 filename = "__FAILED__";
00621 return false;
00622 }
00623
00624 LOG(VB_GENERAL, LOG_CRIT, "Database Backup complete.");
00625
00626 QDir dir(backupDirectory, backupFilename + "*");
00627 uint numfiles = dir.count();
00628 if (numfiles < 1)
00629 {
00630
00631
00632
00633 filename = "";
00634 LOG(VB_FILE, LOG_ERR, LOC +
00635 QString("No files beginning with the suggested database backup "
00636 "filename '%1' were found in '%2'.")
00637 .arg(backupFilename).arg(backupDirectory));
00638 }
00639 else
00640 {
00641 filename = dir.path() + "/" + dir[0];;
00642 if (numfiles > 1)
00643 {
00644 LOG(VB_FILE, LOG_ERR, LOC +
00645 QString("Multiple files beginning with the suggested database "
00646 "backup filename '%1' were found in '%2'. "
00647 "Assuming the first is the backup.")
00648 .arg(backupFilename).arg(backupDirectory));
00649 }
00650 }
00651
00652 if (!filename.isEmpty())
00653 {
00654 LOG(VB_GENERAL, LOG_CRIT, QString("Backed up database to file: '%1'")
00655 .arg(filename));
00656 }
00657
00658 return true;
00659 }
00660
00667 bool DBUtil::DoBackup(QString &filename)
00668 {
00669 DatabaseParams dbParams = gCoreContext->GetDatabaseParams();
00670 QString dbSchemaVer = gCoreContext->GetSetting("DBSchemaVer");
00671 QString backupDirectory = GetBackupDirectory();
00672
00673 QString command;
00674 QString compressCommand("");
00675 QString extension = ".sql";
00676 if (QFile::exists("/bin/gzip"))
00677 compressCommand = "/bin/gzip";
00678 else if (QFile::exists("/usr/bin/gzip"))
00679 compressCommand = "/usr/bin/gzip";
00680 else
00681 LOG(VB_GENERAL, LOG_CRIT, "Neither /bin/gzip nor /usr/bin/gzip exist. "
00682 "The database backup will be uncompressed.");
00683
00684 QString backupFilename = CreateBackupFilename(
00685 dbParams.dbName + "-" + dbSchemaVer, extension);
00686 QString backupPathname = backupDirectory + "/" + backupFilename;
00687
00688 QString privateinfo = QString(
00689 "[client]\npassword=%1\n[mysqldump]\npassword=%2\n")
00690 .arg(dbParams.dbPassword).arg(dbParams.dbPassword);
00691 QString tempExtraConfFile = QString::null;
00692 if (!CreateTemporaryDBConf(privateinfo, tempExtraConfFile))
00693 return false;
00694
00695 QString portArg = "";
00696 if (dbParams.dbPort > 0)
00697 portArg = QString(" --port='%1'").arg(dbParams.dbPort);
00698 command = QString("mysqldump --defaults-extra-file='%1' --host='%2'%3"
00699 " --user='%4' --add-drop-table --add-locks"
00700 " --allow-keywords --complete-insert"
00701 " --extended-insert --lock-tables --no-create-db --quick"
00702 " '%5' > '%6' 2>/dev/null")
00703 .arg(tempExtraConfFile).arg(dbParams.dbHostName)
00704 .arg(portArg).arg(dbParams.dbUserName)
00705 .arg(dbParams.dbName).arg(backupPathname);
00706
00707 LOG(VB_FILE, LOG_INFO, QString("Backing up database with command: '%1'")
00708 .arg(command));
00709 LOG(VB_GENERAL, LOG_CRIT, QString("Backing up database to file: '%1'")
00710 .arg(backupPathname));
00711
00712 uint status = myth_system(command, kMSDontBlockInputDevs|kMSAnonLog);
00713
00714 QByteArray tmpfile = tempExtraConfFile.toLocal8Bit();
00715 unlink(tmpfile.constData());
00716
00717 if (status != GENERIC_EXIT_OK)
00718 {
00719 LOG(VB_GENERAL, LOG_ERR, LOC +
00720 QString("Error backing up database: '%1' (%2)")
00721 .arg(command).arg(status));
00722 filename = "__FAILED__";
00723 return false;
00724 }
00725
00726 if (compressCommand != "")
00727 {
00728 LOG(VB_GENERAL, LOG_CRIT, "Compressing database backup file.");
00729 compressCommand += " " + backupPathname;
00730 status = myth_system(compressCommand, kMSDontBlockInputDevs);
00731
00732 if (status != GENERIC_EXIT_OK)
00733 {
00734 LOG(VB_GENERAL, LOG_CRIT,
00735 "Compression failed, backup file will remain uncompressed.");
00736 }
00737 else
00738 {
00739 backupPathname += ".gz";
00740
00741 LOG(VB_GENERAL, LOG_CRIT, QString("Database Backup filename: '%1'")
00742 .arg(backupPathname));
00743 }
00744 }
00745
00746 LOG(VB_GENERAL, LOG_CRIT, "Database Backup complete.");
00747
00748 filename = backupPathname;
00749 return true;
00750 }
00751
00756 bool DBUtil::QueryDBMSVersion(void)
00757 {
00758
00759
00760
00761 QString dbmsVersion = gCoreContext->GetSetting("DBMSVersionOverride");
00762
00763 if (dbmsVersion.isEmpty())
00764 {
00765 MSqlQuery query(MSqlQuery::InitCon());
00766 query.prepare("SELECT VERSION();");
00767 if (!query.exec() || !query.next())
00768 {
00769 LOG(VB_GENERAL, LOG_ERR, LOC +
00770 "Unable to determine MySQL version.");
00771 MythDB::DBError("DBUtil Querying DBMS version", query);
00772 dbmsVersion = QString::null;
00773 }
00774 else
00775 dbmsVersion = query.value(0).toString();
00776 }
00777 m_versionString = dbmsVersion;
00778
00779 return !m_versionString.isEmpty();
00780 }
00781
00785 bool DBUtil::ParseDBMSVersion()
00786 {
00787 if (m_versionString.isEmpty())
00788 if (!QueryDBMSVersion())
00789 return false;
00790
00791 bool ok;
00792 QString section;
00793 int pos = 0, i = 0;
00794 int version[3] = {-1, -1, -1};
00795 QRegExp digits("(\\d+)");
00796
00797 while ((i < 3) && ((pos = digits.indexIn(m_versionString, pos)) > -1))
00798 {
00799 section = digits.cap(1);
00800 pos += digits.matchedLength();
00801 version[i] = section.toInt(&ok, 10);
00802 if (!ok)
00803 version[i] = -1;
00804 i++;
00805 }
00806
00807 m_versionMajor = version[0];
00808 m_versionMinor = version[1];
00809 m_versionPoint = version[2];
00810
00811 return m_versionMajor > -1;
00812 }
00813
00817 int DBUtil::CountClients(void)
00818 {
00819 int count = 0;
00820
00821 MSqlQuery query(MSqlQuery::InitCon());
00822 if (!query.isConnected())
00823 {
00824 LOG(VB_GENERAL, LOG_DEBUG, "Not connected to DB");
00825 return count;
00826 }
00827
00828 if (!query.exec("SHOW PROCESSLIST;"))
00829 {
00830 MythDB::DBError("DBUtil CountClients", query);
00831 return count;
00832 }
00833
00834 QSqlRecord record = query.record();
00835 int db_index = record.indexOf("db");
00836 QString dbName = gCoreContext->GetDatabaseParams().dbName;
00837 QString inUseDB;
00838
00839 while (query.next())
00840 {
00841 inUseDB = query.value(db_index).toString();
00842 if (inUseDB == dbName)
00843 ++count;
00844 }
00845
00846
00847
00848 count = (count + 3)/4;
00849
00850 LOG(VB_GENERAL, LOG_DEBUG,
00851 QString("DBUtil::CountClients() found %1").arg(count));
00852
00853 return count;
00854 }
00855
00859 bool DBUtil::TryLockSchema(MSqlQuery &query, uint timeout_secs)
00860 {
00861 query.prepare("SELECT GET_LOCK('schemaLock', :TIMEOUT)");
00862 query.bindValue(":TIMEOUT", timeout_secs);
00863 return query.exec() && query.first() && query.value(0).toBool();
00864 }
00865
00866 void DBUtil::UnlockSchema(MSqlQuery &query)
00867 {
00868 query.prepare("SELECT RELEASE_LOCK('schemaLock')");
00869 query.exec();
00870 }
00871
00872