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