File indexing completed on 2025-01-05 03:54:13
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-11-14 0007 * Description : Mysql internal database server 0008 * 0009 * SPDX-FileCopyrightText: 2009-2011 by Holger Foerster <Hamsi2k at freenet dot de> 0010 * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * SPDX-FileCopyrightText: 2016 by Swati Lodha <swatilodha27 at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "databaseserver.h" 0018 0019 // Qt includes 0020 0021 #include <QProgressDialog> 0022 #include <QStandardPaths> 0023 #include <QApplication> 0024 #include <QTcpServer> 0025 #include <QDateTime> 0026 #include <QFileInfo> 0027 #include <QFile> 0028 #include <QSqlDatabase> 0029 #include <QSqlQuery> 0030 #include <QSqlError> 0031 #include <QtGlobal> 0032 #include <QPointer> 0033 #include <QDir> 0034 0035 // KDE includes 0036 0037 #include <klocalizedstring.h> 0038 0039 // Local includes 0040 0041 #include "digikam_debug.h" 0042 #include "digikam_globals.h" 0043 0044 namespace Digikam 0045 { 0046 0047 class Q_DECL_HIDDEN DatabaseServer::Private 0048 { 0049 public: 0050 0051 explicit Private() 0052 : databaseProcess(nullptr), 0053 serverPort(3307) 0054 { 0055 } 0056 0057 DbEngineParameters params; 0058 QProcess* databaseProcess; 0059 0060 QString internalDBName; 0061 QString mysqlUpgradePath; 0062 QString mysqlServerPath; 0063 QString mysqlAdminPath; 0064 QString mysqlInitPath; 0065 QString dataDir; 0066 QString miscDir; 0067 QString fileDataDir; 0068 QString actualConfig; 0069 QString globalConfig; 0070 0071 int serverPort; 0072 }; 0073 0074 DatabaseServer::DatabaseServer(const DbEngineParameters& params, DatabaseServerStarter* const parent) 0075 : QThread(parent), 0076 d (new Private) 0077 { 0078 d->params = params; 0079 0080 qCDebug(DIGIKAM_DATABASESERVER_LOG) << d->params; 0081 0082 QString defaultAkDir = DbEngineParameters::serverPrivatePath(); 0083 QString dataDir; 0084 0085 if (d->params.internalServerPath().isEmpty()) 0086 { 0087 dataDir = QDir(defaultAkDir).absoluteFilePath(QLatin1String("db_data")); 0088 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "No internal server data path is given, we will use the default." << dataDir; 0089 } 0090 else 0091 { 0092 dataDir = QDir(d->params.internalServerPath()).absoluteFilePath(QLatin1String(".mysql.digikam/db_data")); 0093 } 0094 0095 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Internal Server data path:" << dataDir; 0096 0097 d->internalDBName = QLatin1String("digikam"); 0098 d->mysqlUpgradePath = d->params.internalServerMysqlUpgradeCmd; 0099 d->mysqlServerPath = d->params.internalServerMysqlServerCmd; 0100 d->mysqlAdminPath = d->params.internalServerMysqlAdminCmd; 0101 d->mysqlInitPath = d->params.internalServerMysqlInitCmd; 0102 d->dataDir = dataDir; 0103 d->miscDir = QDir(defaultAkDir).absoluteFilePath(QLatin1String("db_misc")); 0104 d->fileDataDir = QDir(defaultAkDir).absoluteFilePath(QLatin1String("file_db_data")); 0105 d->actualConfig = QDir(defaultAkDir).absoluteFilePath(QLatin1String("mysql.conf")); 0106 d->globalConfig = QStandardPaths::locate(QStandardPaths::GenericDataLocation, 0107 QLatin1String("digikam/database/mysql-global.conf")); 0108 databaseServerStateEnum = started; 0109 } 0110 0111 DatabaseServer::~DatabaseServer() 0112 { 0113 delete d; 0114 } 0115 0116 void DatabaseServer::run() 0117 { 0118 quint64 runningTime = 0; 0119 int debugTime = 0; 0120 int waitTime = 1; 0121 0122 // Loop to wait for stopping the server. 0123 0124 do 0125 { 0126 if (!debugTime) 0127 { 0128 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Running" << runningTime << "seconds..."; 0129 debugTime = 30; 0130 } 0131 0132 QThread::sleep(waitTime); 0133 ++runningTime; 0134 --debugTime; 0135 } 0136 while (databaseServerStateEnum != stopped); 0137 0138 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Shutting down database server"; 0139 Q_EMIT done(); 0140 } 0141 0142 DatabaseServerError DatabaseServer::startDatabaseProcess() 0143 { 0144 DatabaseServerError error; 0145 0146 if (d->params.isMySQL()) 0147 { 0148 error = startMysqlDatabaseProcess(); 0149 } 0150 else 0151 { 0152 error = DatabaseServerError(DatabaseServerError::NotSupported, 0153 i18n("Database type is not supported.")); 0154 } 0155 0156 if (error.getErrorType() == DatabaseServerError::StartError) 0157 { 0158 databaseServerStateEnum = notRunning; 0159 } 0160 else if (error.getErrorType() == DatabaseServerError::NotSupported) 0161 { 0162 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "This database type is not supported."; 0163 databaseServerStateEnum = notRunning; 0164 } 0165 else 0166 { 0167 databaseServerStateEnum = running; 0168 } 0169 0170 return error; 0171 } 0172 0173 void DatabaseServer::stopDatabaseProcess() 0174 { 0175 if (!d->databaseProcess) 0176 { 0177 return; 0178 } 0179 0180 QStringList mysqlShutDownArgs; 0181 mysqlShutDownArgs << QLatin1String("-u"); 0182 mysqlShutDownArgs << QLatin1String("root"); 0183 mysqlShutDownArgs << QLatin1String("shutdown"); 0184 0185 #ifdef Q_OS_WIN 0186 0187 mysqlShutDownArgs << QString::fromLatin1("--port=%1").arg(d->serverPort); 0188 0189 #else 0190 0191 mysqlShutDownArgs << QString::fromLatin1("--socket=%1/mysql.socket").arg(d->miscDir); 0192 0193 #endif 0194 0195 QProcess mysqlShutDownProcess; 0196 mysqlShutDownProcess.setProcessEnvironment(adjustedEnvironmentForAppImage()); 0197 0198 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Send stop to database server"; 0199 0200 mysqlShutDownProcess.start(d->mysqlAdminPath, mysqlShutDownArgs); 0201 mysqlShutDownProcess.waitForFinished(); 0202 0203 if (!d->databaseProcess->waitForFinished() && (d->databaseProcess->state() == QProcess::Running)) 0204 { 0205 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Database process will be killed now"; 0206 d->databaseProcess->kill(); 0207 d->databaseProcess->waitForFinished(); 0208 } 0209 0210 delete d->databaseProcess; 0211 d->databaseProcess = nullptr; 0212 databaseServerStateEnum = stopped; 0213 0214 wait(); 0215 } 0216 0217 bool DatabaseServer::isRunning() const 0218 { 0219 if (!d->databaseProcess) 0220 { 0221 return false; 0222 } 0223 0224 return (databaseServerStateEnum == running); 0225 } 0226 0227 DatabaseServerError DatabaseServer::startMysqlDatabaseProcess() 0228 { 0229 DatabaseServerError error = checkDatabaseDirs(); 0230 0231 if (error.getErrorType() != DatabaseServerError::NoErrors) 0232 { 0233 return error; 0234 } 0235 0236 error = initMysqlConfig(); 0237 0238 if (error.getErrorType() != DatabaseServerError::NoErrors) 0239 { 0240 return error; 0241 } 0242 0243 copyAndRemoveMysqlLogs(); 0244 0245 error = createMysqlFiles(); 0246 0247 if (error.getErrorType() != DatabaseServerError::NoErrors) 0248 { 0249 return error; 0250 } 0251 0252 error = startMysqlServer(); 0253 0254 if (error.getErrorType() != DatabaseServerError::NoErrors) 0255 { 0256 return error; 0257 } 0258 0259 error = initMysqlDatabase(false); 0260 0261 if (error.getErrorType() != DatabaseServerError::NoErrors) 0262 { 0263 return error; 0264 } 0265 0266 error = upgradeMysqlDatabase(); 0267 0268 if (error.getErrorType() != DatabaseServerError::NoErrors) 0269 { 0270 return error; 0271 } 0272 0273 error = initMysqlDatabase(true); 0274 0275 if (error.getErrorType() != DatabaseServerError::NoErrors) 0276 { 0277 return error; 0278 } 0279 0280 databaseServerStateEnum = running; 0281 0282 return error; 0283 } 0284 0285 DatabaseServerError DatabaseServer::checkDatabaseDirs() const 0286 { 0287 DatabaseServerError error; 0288 0289 if (d->mysqlUpgradePath.isEmpty()) 0290 { 0291 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "No path to mysql upgrade command set in configuration file!"; 0292 0293 return DatabaseServerError(DatabaseServerError::StartError, 0294 i18n("No path to mysql upgrade command set " 0295 "in configuration file.")); 0296 } 0297 0298 if (d->mysqlServerPath.isEmpty()) 0299 { 0300 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "No path to mysql server command set in configuration file!"; 0301 0302 return DatabaseServerError(DatabaseServerError::StartError, 0303 i18n("No path to mysql server command set " 0304 "in configuration file.")); 0305 } 0306 0307 if (d->mysqlAdminPath.isEmpty()) 0308 { 0309 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "No path to mysql administration command set in configuration file!"; 0310 0311 return DatabaseServerError(DatabaseServerError::StartError, 0312 i18n("No path to mysql administration " 0313 "command set in configuration file.")); 0314 } 0315 0316 if (d->mysqlInitPath.isEmpty()) 0317 { 0318 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "No path to mysql initialization command set in configuration file!"; 0319 0320 return DatabaseServerError(DatabaseServerError::StartError, 0321 i18n("No path to mysql initialization " 0322 "command set in configuration file.")); 0323 } 0324 0325 if (!QFile::exists(d->dataDir) && !QDir().mkpath(d->dataDir)) 0326 { 0327 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Cannot create directory " 0328 << d->dataDir; 0329 0330 return DatabaseServerError(DatabaseServerError::StartError, 0331 i18n("Cannot create directory %1", 0332 QDir::toNativeSeparators(d->dataDir))); 0333 } 0334 0335 if (!QFile::exists(d->miscDir) && !QDir().mkpath(d->miscDir)) 0336 { 0337 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Cannot create directory " 0338 << d->miscDir; 0339 0340 return DatabaseServerError(DatabaseServerError::StartError, 0341 i18n("Cannot create directory %1", 0342 QDir::toNativeSeparators(d->miscDir))); 0343 } 0344 0345 if (!QFile::exists(d->fileDataDir) && !QDir().mkpath(d->fileDataDir)) 0346 { 0347 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Cannot create directory " 0348 << d->fileDataDir; 0349 0350 return DatabaseServerError(DatabaseServerError::StartError, 0351 i18n("Cannot create directory %1", 0352 QDir::toNativeSeparators(d->fileDataDir))); 0353 } 0354 0355 return error; 0356 } 0357 0358 DatabaseServerError DatabaseServer::initMysqlConfig() const 0359 { 0360 DatabaseServerError error; 0361 0362 QString localConfig = QStandardPaths::locate(QStandardPaths::GenericDataLocation, 0363 QLatin1String("digikam/database/mysql-local.conf")); 0364 0365 if (!d->globalConfig.isEmpty()) 0366 { 0367 bool confUpdate = false; 0368 bool confShouldUpdate = false; 0369 QFile actualFile(d->actualConfig); 0370 0371 // Update actualconf only if either global or local is newer than actual 0372 // If actual does not yet exist it was initialised with datetime 0 0373 // so it will get updated too 0374 0375 if ((QFileInfo(d->globalConfig).lastModified() > QFileInfo(actualFile).lastModified()) || 0376 (QFileInfo(localConfig).lastModified() > QFileInfo(actualFile).lastModified())) 0377 { 0378 confShouldUpdate = true; 0379 0380 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "The mysql configuration is outdated," 0381 << d->actualConfig 0382 << "will be updated."; 0383 0384 QFile globalFile(d->globalConfig); 0385 QFile localFile(localConfig); 0386 0387 if (globalFile.open(QFile::ReadOnly) && actualFile.open(QFile::WriteOnly)) 0388 { 0389 actualFile.write(globalFile.readAll()); 0390 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Updated mysql configuration with" << d->globalConfig; 0391 0392 if (!localConfig.isEmpty() && localFile.open(QFile::ReadOnly)) 0393 { 0394 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Updated mysql configuration with" << localConfig; 0395 actualFile.write(localFile.readAll()); 0396 localFile.close(); 0397 } 0398 0399 globalFile.close(); 0400 actualFile.close(); 0401 0402 confUpdate = true; 0403 } 0404 } 0405 0406 // MySQL doesn't like world writeable config files (which makes sense), but 0407 // our config file somehow ends up being world-writable on some systems for no 0408 // apparent reason nevertheless, so fix that 0409 0410 if (confUpdate) 0411 { 0412 const QFile::Permissions allowedPerms = actualFile.permissions() & 0413 (QFile::ReadOwner | QFile::WriteOwner | 0414 QFile::ReadGroup | QFile::WriteGroup | QFile::ReadOther); 0415 0416 if (allowedPerms != actualFile.permissions()) 0417 { 0418 actualFile.setPermissions(allowedPerms); 0419 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Fixed permissions of mysql configuration file."; 0420 } 0421 } 0422 else if (confShouldUpdate) 0423 { 0424 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Unable to create MySQL server configuration file." 0425 << "This means that either the default configuration file" 0426 << d->globalConfig 0427 << "was not readable or the target file" 0428 << d->actualConfig 0429 << "could not be written."; 0430 0431 QString errorMsg = i18n("Unable to create MySQL server configuration file." 0432 "<p>This means that either the default configuration file</p>" 0433 "<p>%1</p>" 0434 "<p>was not readable or the target file</p>" 0435 "<p>%2</p>" 0436 "<p>could not be written.</p>", 0437 d->globalConfig, 0438 d->actualConfig); 0439 0440 error = DatabaseServerError(DatabaseServerError::StartError, errorMsg); 0441 } 0442 else 0443 { 0444 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "The mysql configuration was already up-to-date:" 0445 << d->actualConfig; 0446 } 0447 } 0448 else 0449 { 0450 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Cannot find MySQL server default configuration (mysql-global.conf)"; 0451 0452 error = DatabaseServerError(DatabaseServerError::StartError, 0453 i18n("Cannot find MySQL server default " 0454 "configuration (mysql-global.conf).")); 0455 } 0456 0457 return error; 0458 } 0459 0460 void DatabaseServer::copyAndRemoveMysqlLogs() const 0461 { 0462 // Move mysql error log file out of the way 0463 0464 const QFileInfo errorLog(d->dataDir, 0465 QLatin1String("mysql.err")); 0466 0467 if (errorLog.exists()) 0468 { 0469 QFile logFile(errorLog.absoluteFilePath()); 0470 QFile oldLogFile(QDir(d->dataDir).absoluteFilePath(QLatin1String("mysql.err.old"))); 0471 0472 if (oldLogFile.exists() && (oldLogFile.size() > (100 * 1024 * 1024))) 0473 { 0474 oldLogFile.remove(); 0475 } 0476 0477 if (logFile.open(QFile::ReadOnly) && oldLogFile.open(QFile::Append)) 0478 { 0479 QByteArray ba = logFile.readAll(); 0480 oldLogFile.write(ba); 0481 oldLogFile.close(); 0482 logFile.close(); 0483 logFile.remove(); 0484 } 0485 else 0486 { 0487 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Failed to open MySQL error log."; 0488 } 0489 } 0490 } 0491 0492 DatabaseServerError DatabaseServer::createMysqlFiles() const 0493 { 0494 DatabaseServerError error; 0495 0496 // Initialize the database 0497 0498 if (!QFile(QDir(d->dataDir).absoluteFilePath(QLatin1String("mysql"))).exists()) 0499 { 0500 QPointer<QProgressDialog> dialog = new QProgressDialog; 0501 dialog->setLabelText(i18n("The internal MySQL database is " 0502 "initializing, please wait...")); 0503 dialog->setCancelButton(nullptr); 0504 dialog->setMinimumDuration(2000); 0505 dialog->setModal(true); 0506 dialog->setMinimum(0); 0507 dialog->setMaximum(0); 0508 0509 // Synthesize the server initialization command line arguments 0510 0511 QStringList mysqlInitCmdArgs; 0512 0513 #ifndef Q_OS_WIN 0514 0515 mysqlInitCmdArgs << QDir::toNativeSeparators(QString::fromLatin1("--defaults-file=%1") 0516 .arg(d->globalConfig)); 0517 0518 #endif 0519 0520 #ifdef Q_OS_MACOS 0521 0522 mysqlInitCmdArgs << QDir::toNativeSeparators(QString::fromLatin1("--basedir=%1/lib/mariadb/") 0523 .arg(macOSBundlePrefix())); 0524 0525 #endif 0526 0527 mysqlInitCmdArgs << QDir::toNativeSeparators(QString::fromLatin1("--datadir=%1") 0528 .arg(d->dataDir)); 0529 0530 QProcess initProcess; 0531 initProcess.setProcessEnvironment(adjustedEnvironmentForAppImage()); 0532 initProcess.start(d->mysqlInitPath, mysqlInitCmdArgs); 0533 0534 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Database initializer:" 0535 << initProcess.program() 0536 << initProcess.arguments(); 0537 0538 while (!initProcess.waitForFinished(250)) 0539 { 0540 qApp->processEvents(); 0541 } 0542 0543 delete dialog; 0544 0545 if (initProcess.exitCode() != 0) 0546 { 0547 error = DatabaseServerError(DatabaseServerError::StartError, 0548 processErrorLog(&initProcess, 0549 i18n("Could not start database initializer."))); 0550 } 0551 } 0552 0553 return error; 0554 } 0555 0556 DatabaseServerError DatabaseServer::startMysqlServer() 0557 { 0558 DatabaseServerError error; 0559 0560 // Synthesize the server command line arguments 0561 0562 QStringList mysqldServCmdArgs; 0563 mysqldServCmdArgs << QDir::toNativeSeparators(QString::fromLatin1("--defaults-file=%1").arg(d->actualConfig)) 0564 << QDir::toNativeSeparators(QString::fromLatin1("--datadir=%1").arg(d->dataDir)); 0565 0566 #ifdef Q_OS_MACOS 0567 0568 mysqldServCmdArgs << QDir::toNativeSeparators(QString::fromLatin1("--basedir=%1/lib/mariadb/") 0569 .arg(macOSBundlePrefix())); 0570 0571 #endif 0572 0573 #ifdef Q_OS_WIN 0574 0575 QTcpServer* const server = new QTcpServer(); 0576 0577 if (!server->listen(QHostAddress::LocalHost, d->serverPort)) 0578 { 0579 qCWarning(DIGIKAM_DATABASESERVER_LOG) << "Port 3307 not free for the MySQL server"; 0580 0581 server->listen(QHostAddress::LocalHost, 0); 0582 d->serverPort = server->serverPort(); 0583 0584 qCWarning(DIGIKAM_DATABASESERVER_LOG) << "Now use the free port:" << d->serverPort; 0585 } 0586 0587 server->close(); 0588 delete server; 0589 0590 mysqldServCmdArgs << QLatin1String("--skip-networking=0") 0591 << QString::fromLatin1("--port=%1").arg(d->serverPort); 0592 0593 #else 0594 0595 mysqldServCmdArgs << QString::fromLatin1("--socket=%1/mysql.socket").arg(d->miscDir); 0596 0597 #endif 0598 0599 // Start the database server 0600 0601 d->databaseProcess = new QProcess(); 0602 d->databaseProcess->setProcessEnvironment(adjustedEnvironmentForAppImage()); 0603 d->databaseProcess->start(d->mysqlServerPath, mysqldServCmdArgs); 0604 0605 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Database server:" 0606 << d->databaseProcess->program() 0607 << d->databaseProcess->arguments(); 0608 0609 if (!d->databaseProcess->waitForStarted() || (d->databaseProcess->exitCode() != 0)) 0610 { 0611 QString errorMsg = processErrorLog(d->databaseProcess, 0612 i18n("Could not start database server.")); 0613 0614 delete d->databaseProcess; 0615 d->databaseProcess = nullptr; 0616 0617 error = DatabaseServerError(DatabaseServerError::StartError, errorMsg); 0618 } 0619 0620 return error; 0621 } 0622 0623 DatabaseServerError DatabaseServer::initMysqlDatabase(bool useDatabase) const 0624 { 0625 DatabaseServerError error; 0626 0627 const QLatin1String initCon("initConnection"); 0628 0629 { 0630 QSqlDatabase db = QSqlDatabase::addDatabase(DbEngineParameters::MySQLDatabaseType(), initCon); 0631 0632 #ifdef Q_OS_WIN 0633 0634 db.setHostName(QLatin1String("localhost")); 0635 db.setPort(d->serverPort); 0636 0637 #else 0638 0639 db.setConnectOptions(QString::fromLatin1("UNIX_SOCKET=%1/mysql.socket").arg(d->miscDir)); 0640 0641 #endif 0642 0643 db.setUserName(QLatin1String("root")); 0644 0645 // might not exist yet, then connecting to the actual db will fail 0646 0647 db.setDatabaseName(QString()); 0648 0649 if (!db.isValid()) 0650 { 0651 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Invalid database object during database server startup"; 0652 0653 return DatabaseServerError(DatabaseServerError::StartError, 0654 i18n("Invalid database object during database " 0655 "server startup")); 0656 } 0657 0658 bool opened = false; 0659 bool exited = false; 0660 0661 for (int i = 0 ; i < 120 ; ++i) 0662 { 0663 opened = db.open(); 0664 0665 if (opened) 0666 { 0667 break; 0668 } 0669 0670 if (d->databaseProcess && d->databaseProcess->waitForFinished(500)) 0671 { 0672 exited = true; 0673 break; 0674 } 0675 } 0676 0677 if (!opened) 0678 { 0679 QString firstLine; 0680 QString errorMsg; 0681 0682 if (exited) 0683 { 0684 errorMsg = processErrorLog(d->databaseProcess, 0685 i18n("Database process exited unexpectedly " 0686 "during initial connection.")); 0687 } 0688 else 0689 { 0690 errorMsg = processErrorLog(d->databaseProcess, 0691 i18n("Could not connect to Database after " 0692 "trying for 60 seconds.")); 0693 } 0694 0695 return DatabaseServerError(DatabaseServerError::StartError, errorMsg); 0696 } 0697 0698 if (useDatabase) 0699 { 0700 QSqlQuery query(db); 0701 0702 if (!query.exec(QString::fromLatin1("USE %1;").arg(d->internalDBName))) 0703 { 0704 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Failed to use database" 0705 << d->internalDBName; 0706 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Query error:" 0707 << query.lastError().text(); 0708 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Database error:" 0709 << db.lastError().text(); 0710 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Trying to create database now"; 0711 0712 if (query.exec(QString::fromLatin1("CREATE DATABASE %1;").arg(d->internalDBName))) 0713 { 0714 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Database was successfully created"; 0715 } 0716 else 0717 { 0718 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Failed to create database"; 0719 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Query error:" 0720 << query.lastError().text(); 0721 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Database error:" 0722 << db.lastError().text(); 0723 0724 QString errorMsg = i18n("Failed to create database" 0725 "<p>Query error: %1</p>" 0726 "<p>Database error: %2</p>", 0727 query.lastError().text(), 0728 db.lastError().text()); 0729 0730 error = DatabaseServerError(DatabaseServerError::StartError, errorMsg); 0731 } 0732 } 0733 } 0734 0735 // Make sure query is destroyed before we close the db 0736 0737 db.close(); 0738 } 0739 0740 QSqlDatabase::removeDatabase(initCon); 0741 0742 return error; 0743 } 0744 0745 DatabaseServerError DatabaseServer::upgradeMysqlDatabase() 0746 { 0747 QPointer<QProgressDialog> dialog = new QProgressDialog; 0748 dialog->setLabelText(i18n("A MySQL database upgrade is " 0749 "in progress, please wait...")); 0750 dialog->setCancelButton(nullptr); 0751 dialog->setMinimumDuration(5000); 0752 dialog->setModal(true); 0753 dialog->setMinimum(0); 0754 dialog->setMaximum(0); 0755 0756 DatabaseServerError error; 0757 0758 // Synthesize the mysql upgrade command line arguments 0759 0760 QStringList upgradeCmdArgs; 0761 0762 #ifdef Q_OS_WIN 0763 0764 upgradeCmdArgs << QString::fromLatin1("--port=%1").arg(d->serverPort); 0765 0766 #else 0767 0768 upgradeCmdArgs << QString::fromLatin1("--socket=%1/mysql.socket").arg(d->miscDir); 0769 0770 #endif 0771 0772 // Start the upgrade program 0773 0774 QProcess upgradeProcess; 0775 upgradeProcess.setProcessEnvironment(adjustedEnvironmentForAppImage()); 0776 upgradeProcess.start(d->mysqlUpgradePath, upgradeCmdArgs); 0777 0778 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Upgrade database:" 0779 << upgradeProcess.program() 0780 << upgradeProcess.arguments(); 0781 0782 while (!upgradeProcess.waitForFinished(250)) 0783 { 0784 qApp->processEvents(); 0785 } 0786 0787 delete dialog; 0788 0789 if (upgradeProcess.exitCode() != 0) 0790 { 0791 QString errorMsg = processErrorLog(&upgradeProcess, 0792 i18n("Could not upgrade database.")); 0793 0794 error = DatabaseServerError(DatabaseServerError::StartError, errorMsg); 0795 } 0796 0797 return error; 0798 } 0799 0800 QString DatabaseServer::getcurrentAccountUserName() const 0801 { 0802 QString name = QString::fromUtf8(qgetenv("USER")); // Linux and OSX 0803 0804 if (name.isEmpty()) 0805 { 0806 name = QString::fromUtf8(qgetenv("USERNAME")); // Windows 0807 } 0808 0809 return name; 0810 } 0811 0812 QString DatabaseServer::processErrorLog(QProcess* const process, const QString& msg) const 0813 { 0814 qCDebug(DIGIKAM_DATABASESERVER_LOG) << msg; 0815 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Executable:" 0816 << process->program(); 0817 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Arguments:" 0818 << process->arguments().join(QLatin1String(", ")); 0819 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Stdout:" 0820 << process->readAllStandardOutput(); 0821 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Stderr:" 0822 << process->readAllStandardError(); 0823 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Exit code:" 0824 << process->exitCode(); 0825 qCDebug(DIGIKAM_DATABASESERVER_LOG) << "Process error:" 0826 << process->errorString(); 0827 0828 return i18n("%1" 0829 "<p>Executable: %2</p>" 0830 "<p>Arguments: %3</p>" 0831 "<p>Process error: %4</p>", 0832 msg, 0833 process->program(), 0834 process->arguments().join(QLatin1String(", ")), 0835 process->errorString()); 0836 } 0837 0838 } // namespace Digikam 0839 0840 #include "moc_databaseserver.cpp"