File indexing completed on 2025-01-19 03:53:44

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2017-07-01
0007  * Description : Similarity DB schema update
0008  *
0009  * SPDX-FileCopyrightText: 2007-2009 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText:      2017 by Swati  Lodha   <swatilodha27 at gmail dot com>
0012  * SPDX-FileCopyrightText:      2018 by Mario Frank    <mario dot frank at uni minus potsdam dot de>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #include "similaritydbschemaupdater.h"
0019 
0020 // Qt includes
0021 
0022 #include <QFileInfo>
0023 #include <QFile>
0024 #include <QDir>
0025 
0026 // KDE includes
0027 
0028 #include <klocalizedstring.h>
0029 
0030 // Local includes
0031 
0032 #include "digikam_debug.h"
0033 #include "collectionscannerobserver.h"
0034 #include "dbenginebackend.h"
0035 #include "similaritydbaccess.h"
0036 #include "similaritydb.h"
0037 
0038 namespace Digikam
0039 {
0040 
0041 int SimilarityDbSchemaUpdater::schemaVersion()
0042 {
0043     return 1;
0044 }
0045 
0046 // -------------------------------------------------------------------------------------
0047 
0048 class Q_DECL_HIDDEN SimilarityDbSchemaUpdater::Private
0049 {
0050 
0051 public:
0052 
0053     explicit Private()
0054       : setError(false),
0055         currentVersion(0),
0056         currentRequiredVersion(0),
0057         dbAccess(nullptr),
0058         observer(nullptr)
0059     {
0060     }
0061 
0062 public:
0063 
0064     bool                    setError;
0065 
0066     int                     currentVersion;
0067     int                     currentRequiredVersion;
0068 
0069     SimilarityDbAccess*     dbAccess;
0070 
0071     InitializationObserver* observer;
0072 };
0073 
0074 SimilarityDbSchemaUpdater::SimilarityDbSchemaUpdater(SimilarityDbAccess* const dbAccess)
0075     : d(new Private)
0076 {
0077     d->dbAccess = dbAccess;
0078 }
0079 
0080 SimilarityDbSchemaUpdater::~SimilarityDbSchemaUpdater()
0081 {
0082     delete d;
0083 }
0084 
0085 bool SimilarityDbSchemaUpdater::update()
0086 {
0087     bool success = startUpdates();
0088 
0089     // even on failure, try to set current version - it may have incremented
0090     if (d->currentVersion)
0091     {
0092         d->dbAccess->db()->setSetting(QLatin1String("DBSimilarityVersion"),
0093                                       QString::number(d->currentVersion));
0094     }
0095 
0096     if (d->currentRequiredVersion)
0097     {
0098         d->dbAccess->db()->setSetting(QLatin1String("DBSimilarityVersionRequired"),
0099                                       QString::number(d->currentRequiredVersion));
0100     }
0101 
0102     return success;
0103 }
0104 
0105 void SimilarityDbSchemaUpdater::setObserver(InitializationObserver* const observer)
0106 {
0107     d->observer = observer;
0108 }
0109 
0110 bool SimilarityDbSchemaUpdater::startUpdates()
0111 {
0112     // First step: do we have an empty database?
0113     QStringList tables = d->dbAccess->backend()->tables();
0114 
0115     if (tables.contains(QLatin1String("SimilaritySettings"), Qt::CaseInsensitive))
0116     {
0117         // Find out schema version of db file
0118         QString version         = d->dbAccess->db()->getSetting(QLatin1String("DBSimilarityVersion"));
0119         QString versionRequired = d->dbAccess->db()->getSetting(QLatin1String("DBSimilarityVersionRequired"));
0120 
0121         qCDebug(DIGIKAM_SIMILARITYDB_LOG) << "Similarity database: have a structure version "
0122                                           << version;
0123 
0124         // mini schema update
0125         if (version.isEmpty() && d->dbAccess->parameters().isSQLite())
0126         {
0127             version = d->dbAccess->db()->getSetting(QLatin1String("DBVersion"));
0128         }
0129 
0130         if (version.isEmpty() && d->dbAccess->parameters().isMySQL())
0131         {
0132             version         = d->dbAccess->db()->getLegacySetting(QLatin1String("DBSimilarityVersion"));
0133             versionRequired = d->dbAccess->db()->getLegacySetting(QLatin1String("DBSimilarityVersionRequired"));
0134         }
0135 
0136         // We absolutely require the DBSimilarityVersion setting
0137         if (version.isEmpty())
0138         {
0139             // Something is damaged. Give up.
0140 
0141             qCCritical(DIGIKAM_SIMILARITYDB_LOG) << "Similarity database: database version not available! Giving up schema upgrading.";
0142 
0143             QString errorMsg = i18n("The database is not valid: "
0144                                     "the \"DBSimilarityVersion\" setting does not exist. "
0145                                     "The current database schema version cannot be verified. "
0146                                     "Try to start with an empty database. ");
0147 
0148             d->dbAccess->setLastError(errorMsg);
0149 
0150             if (d->observer)
0151             {
0152                 d->observer->error(errorMsg);
0153                 d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
0154             }
0155 
0156             return false;
0157         }
0158 
0159         // current version describes the current state of the schema in the db,
0160         // schemaVersion is the version required by the program.
0161         d->currentVersion = version.toInt();
0162 
0163         if (d->currentVersion > schemaVersion())
0164         {
0165             // trying to open a database with a more advanced than this SimilarityDbSchemaUpdater supports
0166             if (!versionRequired.isEmpty() && versionRequired.toInt() <= schemaVersion())
0167             {
0168                 // version required may be less than current version
0169                 return true;
0170             }
0171             else
0172             {
0173                 QString errorMsg = i18n("The database has been used with a more recent version of digiKam "
0174                                         "and has been updated to a database schema which cannot be used with this version. "
0175                                         "(This means this digiKam version is too old, or the database format is to recent) "
0176                                         "Please use the more recent version of digikam that you used before. ");
0177                 d->dbAccess->setLastError(errorMsg);
0178 
0179                 if (d->observer)
0180                 {
0181                     d->observer->error(errorMsg);
0182                     d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
0183                 }
0184 
0185                 return false;
0186             }
0187         }
0188         else
0189         {
0190             return makeUpdates();
0191         }
0192     }
0193     else
0194     {
0195         qCDebug(DIGIKAM_SIMILARITYDB_LOG) << "Similarity database: no database file available";
0196 
0197         DbEngineParameters parameters = d->dbAccess->parameters();
0198 
0199         // No legacy handling: start with a fresh db
0200         if (!createDatabase())
0201         {
0202             QString errorMsg = i18n("Failed to create tables in database.\n ") +
0203                                d->dbAccess->backend()->lastError();
0204             d->dbAccess->setLastError(errorMsg);
0205 
0206             if (d->observer)
0207             {
0208                 d->observer->error(errorMsg);
0209                 d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
0210             }
0211 
0212             return false;
0213         }
0214 
0215         return true;
0216     }
0217 }
0218 
0219 
0220 bool SimilarityDbSchemaUpdater::createDatabase()
0221 {
0222     if (createTables()  &&
0223         createIndices() &&
0224         createTriggers())
0225     {
0226         d->currentVersion         = schemaVersion();
0227         d->currentRequiredVersion = 1;
0228         return true;
0229     }
0230     else
0231     {
0232         return false;
0233     }
0234 }
0235 
0236 bool SimilarityDbSchemaUpdater::createTables()
0237 {
0238     return d->dbAccess->backend()->execDBAction(d->dbAccess->backend()->getDBAction(QLatin1String("CreateSimilarityDB")));
0239 }
0240 
0241 bool SimilarityDbSchemaUpdater::createIndices()
0242 {
0243     return d->dbAccess->backend()->execDBAction(d->dbAccess->backend()->getDBAction(QLatin1String("CreateSimilarityDBIndices")));
0244 }
0245 
0246 bool SimilarityDbSchemaUpdater::createTriggers()
0247 {
0248     return d->dbAccess->backend()->execDBAction(d->dbAccess->backend()->getDBAction(QLatin1String("CreateSimilarityDBTriggers")));
0249 }
0250 
0251 bool SimilarityDbSchemaUpdater::makeUpdates()
0252 {
0253     if (d->currentVersion < schemaVersion())
0254     {
0255         if (d->currentVersion == 1)
0256         {
0257             updateV1ToV2();
0258         }
0259     }
0260 
0261     return true;
0262 }
0263 
0264 bool SimilarityDbSchemaUpdater::updateV1ToV2()
0265 {
0266     // Do nothing for now.
0267     return true;
0268 }
0269 
0270 } // namespace Digikam