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 : 2017-06-28 0007 * Description : Similarity Database access wrapper. 0008 * 0009 * SPDX-FileCopyrightText: 2007-2008 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 "similaritydbaccess.h" 0019 0020 // Qt includes 0021 0022 #include <QMutex> 0023 #include <QMutexLocker> 0024 #include <QSqlDatabase> 0025 0026 // KDE includes 0027 0028 #include <klocalizedstring.h> 0029 0030 // Local includes 0031 0032 #include "digikam_debug.h" 0033 #include "similaritydbbackend.h" 0034 #include "similaritydb.h" 0035 #include "similaritydbschemaupdater.h" 0036 #include "dbengineaccess.h" 0037 #include "dbengineerrorhandler.h" 0038 0039 namespace Digikam 0040 { 0041 0042 class Q_DECL_HIDDEN SimilarityDbAccessStaticPriv 0043 { 0044 public: 0045 0046 SimilarityDbAccessStaticPriv() 0047 : backend (nullptr), 0048 db (nullptr), 0049 initializing(false) 0050 { 0051 } 0052 0053 ~SimilarityDbAccessStaticPriv() 0054 { 0055 }; 0056 0057 SimilarityDbBackend* backend; 0058 SimilarityDb* db; 0059 DbEngineParameters parameters; 0060 DbEngineLocking lock; 0061 QString lastError; 0062 0063 bool initializing; 0064 }; 0065 0066 SimilarityDbAccessStaticPriv* SimilarityDbAccess::d = nullptr; 0067 0068 // ----------------------------------------------------------------------------- 0069 0070 class Q_DECL_HIDDEN SimilarityDbAccessMutexLocker 0071 0072 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0073 0074 : public QMutexLocker<QRecursiveMutex> 0075 0076 #else 0077 0078 : public QMutexLocker 0079 0080 #endif 0081 0082 { 0083 public: 0084 0085 explicit SimilarityDbAccessMutexLocker(SimilarityDbAccessStaticPriv* const dd) 0086 : QMutexLocker(&dd->lock.mutex), 0087 d (dd) 0088 { 0089 d->lock.lockCount++; 0090 } 0091 0092 ~SimilarityDbAccessMutexLocker() 0093 { 0094 d->lock.lockCount--; 0095 } 0096 0097 public: 0098 0099 SimilarityDbAccessStaticPriv* const d; 0100 }; 0101 0102 // ----------------------------------------------------------------------------- 0103 0104 SimilarityDbAccess::SimilarityDbAccess() 0105 { 0106 // You will want to call setParameters before constructing SimilarityDbAccess. 0107 0108 Q_ASSERT(d); 0109 0110 d->lock.mutex.lock(); 0111 d->lock.lockCount++; 0112 0113 if (!d->backend->isOpen() && !d->initializing) 0114 { 0115 // avoid endless loops 0116 0117 d->initializing = true; 0118 0119 d->backend->open(d->parameters); 0120 0121 d->initializing = false; 0122 } 0123 } 0124 0125 SimilarityDbAccess::~SimilarityDbAccess() 0126 { 0127 d->lock.lockCount--; 0128 d->lock.mutex.unlock(); 0129 } 0130 0131 SimilarityDbAccess::SimilarityDbAccess(bool) 0132 { 0133 // private constructor, when mutex is locked and 0134 // backend should not be checked 0135 0136 d->lock.mutex.lock(); 0137 d->lock.lockCount++; 0138 } 0139 0140 SimilarityDb* SimilarityDbAccess::db() const 0141 { 0142 return d->db; 0143 } 0144 0145 SimilarityDbBackend* SimilarityDbAccess::backend() const 0146 { 0147 return d->backend; 0148 } 0149 0150 DbEngineParameters SimilarityDbAccess::parameters() 0151 { 0152 if (d) 0153 { 0154 return d->parameters; 0155 } 0156 0157 return DbEngineParameters(); 0158 } 0159 0160 bool SimilarityDbAccess::isInitialized() 0161 { 0162 return d; 0163 } 0164 0165 void SimilarityDbAccess::initDbEngineErrorHandler(DbEngineErrorHandler* const errorhandler) 0166 { 0167 if (!d) 0168 { 0169 d = new SimilarityDbAccessStaticPriv(); 0170 } 0171 0172 //DbEngineErrorHandler* const errorhandler = new DbEngineGuiErrorHandler(d->parameters); 0173 0174 d->backend->setDbEngineErrorHandler(errorhandler); 0175 } 0176 0177 void SimilarityDbAccess::setParameters(const DbEngineParameters& parameters) 0178 { 0179 if (!d) 0180 { 0181 d = new SimilarityDbAccessStaticPriv(); 0182 } 0183 0184 SimilarityDbAccessMutexLocker lock(d); 0185 0186 if (d->parameters == parameters) 0187 { 0188 return; 0189 } 0190 0191 if (d->backend && d->backend->isOpen()) 0192 { 0193 d->backend->close(); 0194 } 0195 0196 // Kill the old database error handler 0197 0198 if (d->backend) 0199 { 0200 d->backend->setDbEngineErrorHandler(nullptr); 0201 } 0202 0203 d->parameters = parameters; 0204 0205 if (!d->backend || !d->backend->isCompatible(parameters)) 0206 { 0207 delete d->db; 0208 delete d->backend; 0209 d->backend = new SimilarityDbBackend(&d->lock); 0210 d->db = new SimilarityDb(d->backend); 0211 } 0212 } 0213 0214 bool SimilarityDbAccess::checkReadyForUse(InitializationObserver* const observer) 0215 { 0216 if (!DbEngineAccess::checkReadyForUse(d->lastError)) 0217 { 0218 return false; 0219 } 0220 0221 // Create an object with private shortcut constructor 0222 0223 SimilarityDbAccess access(false); 0224 0225 if (!d->backend) 0226 { 0227 qCWarning(DIGIKAM_SIMILARITYDB_LOG) << "Similarity database: no database backend available in checkReadyForUse. " 0228 "Did you call setParameters before?"; 0229 return false; 0230 } 0231 0232 if (d->backend->isReady()) 0233 { 0234 return true; 0235 } 0236 0237 if (!d->backend->isOpen()) 0238 { 0239 if (!d->backend->open(d->parameters)) 0240 { 0241 access.setLastError(i18n("Error opening database backend.\n%1", 0242 d->backend->lastError())); 0243 return false; 0244 } 0245 } 0246 0247 // Avoid endless loops (if called methods create new SimilarityDbAccess objects) 0248 0249 d->initializing = true; 0250 0251 // Update schema 0252 0253 SimilarityDbSchemaUpdater updater(&access); 0254 updater.setObserver(observer); 0255 0256 // Check or set WAL mode for SQLite database from DbEngineParameters 0257 0258 d->backend->checkOrSetWALMode(); 0259 0260 if (!d->backend->initSchema(&updater)) 0261 { 0262 qCWarning(DIGIKAM_SIMILARITYDB_LOG) << "Similarity database: cannot process schema initialization"; 0263 0264 d->initializing = false; 0265 return false; 0266 } 0267 0268 d->initializing = false; 0269 0270 return d->backend->isReady(); 0271 } 0272 0273 QString SimilarityDbAccess::lastError() const 0274 { 0275 return d->lastError; 0276 } 0277 0278 void SimilarityDbAccess::setLastError(const QString& error) 0279 { 0280 d->lastError = error; 0281 } 0282 0283 void SimilarityDbAccess::cleanUpDatabase() 0284 { 0285 if (d) 0286 { 0287 SimilarityDbAccessMutexLocker locker(d); 0288 0289 if (d->backend) 0290 { 0291 d->backend->close(); 0292 delete d->db; 0293 delete d->backend; 0294 } 0295 } 0296 0297 delete d; 0298 d = nullptr; 0299 } 0300 0301 } // namespace Digikam