1 /* ============================================================ 2 * 3 * This file is a part of digiKam project 4 * https://www.digikam.org 5 * 6 * Date : 2017-06-28 7 * Description : Similarity Database access wrapper. 8 * 9 * Copyright (C) 2007-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 10 * Copyright (C) 2010-2017 by Gilles Caulier <caulier dot gilles at gmail dot com> 11 * Copyright (C) 2017 by Swati Lodha <swatilodha27 at gmail dot com> 12 * Copyright (C) 2018 by Mario Frank <mario dot frank at uni minus potsdam dot de> 13 * 14 * This program is free software; you can redistribute it 15 * and/or modify it under the terms of the GNU General 16 * Public License as published by the Free Software Foundation; 17 * either version 2, or (at your option) 18 * any later version. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 24 * 25 * ============================================================ */ 26 27 #include "similaritydbaccess.h" 28 29 // Qt includes 30 31 #include <QMutex> 32 #include <QSqlDatabase> 33 34 // KDE includes 35 36 #include <klocalizedstring.h> 37 38 // Local includes 39 40 #include "digikam_debug.h" 41 #include "similaritydbbackend.h" 42 #include "similaritydb.h" 43 #include "similaritydbschemaupdater.h" 44 #include "dbengineparameters.h" 45 #include "dbengineaccess.h" 46 #include "dbengineerrorhandler.h" 47 48 namespace Digikam 49 { 50 51 class Q_DECL_HIDDEN SimilarityDbAccessStaticPriv 52 { 53 public: 54 SimilarityDbAccessStaticPriv()55 SimilarityDbAccessStaticPriv() 56 : backend (nullptr), 57 db (nullptr), 58 initializing(false) 59 { 60 } 61 ~SimilarityDbAccessStaticPriv()62 ~SimilarityDbAccessStaticPriv() 63 { 64 }; 65 66 SimilarityDbBackend* backend; 67 SimilarityDb* db; 68 DbEngineParameters parameters; 69 DbEngineLocking lock; 70 QString lastError; 71 72 bool initializing; 73 }; 74 75 SimilarityDbAccessStaticPriv* SimilarityDbAccess::d = nullptr; 76 77 // ----------------------------------------------------------------------------- 78 79 class Q_DECL_HIDDEN SimilarityDbAccessMutexLocker : public QMutexLocker 80 { 81 public: 82 SimilarityDbAccessMutexLocker(SimilarityDbAccessStaticPriv * const dd)83 explicit SimilarityDbAccessMutexLocker(SimilarityDbAccessStaticPriv* const dd) 84 : QMutexLocker(&dd->lock.mutex), 85 d (dd) 86 { 87 d->lock.lockCount++; 88 } 89 ~SimilarityDbAccessMutexLocker()90 ~SimilarityDbAccessMutexLocker() 91 { 92 d->lock.lockCount--; 93 } 94 95 public: 96 97 SimilarityDbAccessStaticPriv* const d; 98 }; 99 100 // ----------------------------------------------------------------------------- 101 SimilarityDbAccess()102SimilarityDbAccess::SimilarityDbAccess() 103 { 104 // You will want to call setParameters before constructing SimilarityDbAccess. 105 106 Q_ASSERT(d); 107 108 d->lock.mutex.lock(); 109 d->lock.lockCount++; 110 111 if (!d->backend->isOpen() && !d->initializing) 112 { 113 // avoid endless loops 114 115 d->initializing = true; 116 117 d->backend->open(d->parameters); 118 119 d->initializing = false; 120 } 121 } 122 ~SimilarityDbAccess()123SimilarityDbAccess::~SimilarityDbAccess() 124 { 125 d->lock.lockCount--; 126 d->lock.mutex.unlock(); 127 } 128 SimilarityDbAccess(bool)129SimilarityDbAccess::SimilarityDbAccess(bool) 130 { 131 // private constructor, when mutex is locked and 132 // backend should not be checked 133 134 d->lock.mutex.lock(); 135 d->lock.lockCount++; 136 } 137 db() const138SimilarityDb* SimilarityDbAccess::db() const 139 { 140 return d->db; 141 } 142 backend() const143SimilarityDbBackend* SimilarityDbAccess::backend() const 144 { 145 return d->backend; 146 } 147 parameters()148DbEngineParameters SimilarityDbAccess::parameters() 149 { 150 if (d) 151 { 152 return d->parameters; 153 } 154 155 return DbEngineParameters(); 156 } 157 isInitialized()158bool SimilarityDbAccess::isInitialized() 159 { 160 return d; 161 } 162 initDbEngineErrorHandler(DbEngineErrorHandler * const errorhandler)163void SimilarityDbAccess::initDbEngineErrorHandler(DbEngineErrorHandler* const errorhandler) 164 { 165 if (!d) 166 { 167 d = new SimilarityDbAccessStaticPriv(); 168 } 169 170 //DbEngineErrorHandler* const errorhandler = new DbEngineGuiErrorHandler(d->parameters); 171 172 d->backend->setDbEngineErrorHandler(errorhandler); 173 } 174 setParameters(const DbEngineParameters & parameters)175void SimilarityDbAccess::setParameters(const DbEngineParameters& parameters) 176 { 177 if (!d) 178 { 179 d = new SimilarityDbAccessStaticPriv(); 180 } 181 182 SimilarityDbAccessMutexLocker lock(d); 183 184 if (d->parameters == parameters) 185 { 186 return; 187 } 188 189 if (d->backend && d->backend->isOpen()) 190 { 191 d->backend->close(); 192 } 193 194 // Kill the old database error handler 195 196 if (d->backend) 197 { 198 d->backend->setDbEngineErrorHandler(nullptr); 199 } 200 201 d->parameters = parameters; 202 203 if (!d->backend || !d->backend->isCompatible(parameters)) 204 { 205 delete d->db; 206 delete d->backend; 207 d->backend = new SimilarityDbBackend(&d->lock); 208 d->db = new SimilarityDb(d->backend); 209 } 210 } 211 checkReadyForUse(InitializationObserver * const observer)212bool SimilarityDbAccess::checkReadyForUse(InitializationObserver* const observer) 213 { 214 if (!DbEngineAccess::checkReadyForUse(d->lastError)) 215 { 216 return false; 217 } 218 219 // create an object with private shortcut constructor 220 221 SimilarityDbAccess access(false); 222 223 if (!d->backend) 224 { 225 qCWarning(DIGIKAM_SIMILARITYDB_LOG) << "Similarity database: no database backend available in checkReadyForUse. " 226 "Did you call setParameters before?"; 227 return false; 228 } 229 230 if (d->backend->isReady()) 231 { 232 return true; 233 } 234 235 if (!d->backend->isOpen()) 236 { 237 if (!d->backend->open(d->parameters)) 238 { 239 access.setLastError(i18n("Error opening database backend.\n%1", 240 d->backend->lastError())); 241 return false; 242 } 243 } 244 245 // avoid endless loops (if called methods create new SimilarityDbAccess objects) 246 247 d->initializing = true; 248 249 // update schema 250 251 SimilarityDbSchemaUpdater updater(&access); 252 updater.setObserver(observer); 253 254 if (!d->backend->initSchema(&updater)) 255 { 256 qCWarning(DIGIKAM_SIMILARITYDB_LOG) << "Similarity database: cannot process schema initialization"; 257 258 d->initializing = false; 259 return false; 260 } 261 262 d->initializing = false; 263 264 return d->backend->isReady(); 265 } 266 lastError() const267QString SimilarityDbAccess::lastError() const 268 { 269 return d->lastError; 270 } 271 setLastError(const QString & error)272void SimilarityDbAccess::setLastError(const QString& error) 273 { 274 d->lastError = error; 275 } 276 cleanUpDatabase()277void SimilarityDbAccess::cleanUpDatabase() 278 { 279 if (d) 280 { 281 SimilarityDbAccessMutexLocker locker(d); 282 283 if (d->backend) 284 { 285 d->backend->close(); 286 delete d->db; 287 delete d->backend; 288 } 289 } 290 291 delete d; 292 d = nullptr; 293 } 294 295 } // namespace Digikam 296