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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2007-04-15
0007  * Description : Database engine abstract database backend
0008  *
0009  * SPDX-FileCopyrightText: 2007-2010 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 #ifndef DIGIKAM_DB_ENGINE_BACKEND_PRIVATE_H
0017 #define DIGIKAM_DB_ENGINE_BACKEND_PRIVATE_H
0018 
0019 #include "dbenginebackend.h"
0020 
0021 // Qt includes
0022 
0023 #include <QHash>
0024 #include <QSqlDatabase>
0025 #include <QThread>
0026 #include <QThreadStorage>
0027 #include <QWaitCondition>
0028 
0029 // Local includes
0030 
0031 #include "digikam_export.h"
0032 #include "dbengineparameters.h"
0033 #include "dbengineerrorhandler.h"
0034 
0035 namespace Digikam
0036 {
0037 
0038 class Q_DECL_HIDDEN DbEngineThreadData
0039 {
0040 public:
0041 
0042     explicit DbEngineThreadData();
0043     ~DbEngineThreadData();
0044 
0045     void closeDatabase();
0046 
0047 public:
0048 
0049     int       valid;
0050     int       transactionCount;
0051     QString   connectionName;
0052     QSqlError lastError;
0053 };
0054 
0055 // ------------------------------------------------------------------------
0056 
0057 class DIGIKAM_EXPORT BdEngineBackendPrivate : public DbEngineErrorAnswer
0058 {
0059 public:
0060 
0061     explicit BdEngineBackendPrivate(BdEngineBackend* const backend);
0062     ~BdEngineBackendPrivate()                                              override;
0063 
0064     void init(const QString& connectionName, DbEngineLocking* const locking);
0065 
0066     QSqlDatabase databaseForThread();
0067     QSqlError    databaseErrorForThread();
0068     void         setDatabaseErrorForThread(const QSqlError& lastError);
0069 
0070     QString      connectionName();
0071     QSqlDatabase createDatabaseConnection();
0072 
0073     void closeDatabaseForThread();
0074     bool incrementTransactionCount();
0075     bool decrementTransactionCount();
0076 
0077     bool isInMainThread()                                            const;
0078     bool isInUIThread()                                              const;
0079 
0080     bool reconnectOnError()                                          const;
0081     bool isSQLiteLockError(const DbEngineSqlQuery& query)            const;
0082     bool isSQLiteLockTransactionError(const QSqlError& lastError)    const;
0083     bool isConnectionError(const DbEngineSqlQuery& query)            const;
0084     bool needToConsultUserForError(const DbEngineSqlQuery& query)    const;
0085     bool needToHandleWithErrorHandler(const DbEngineSqlQuery& query) const;
0086     void debugOutputFailedQuery(const QSqlQuery& query)              const;
0087     void debugOutputFailedTransaction(const QSqlError& error)        const;
0088 
0089     bool checkRetrySQLiteLockError(int retries);
0090     bool checkOperationStatus();
0091     bool handleWithErrorHandler(const DbEngineSqlQuery* const query);
0092     void setQueryOperationFlag(BdEngineBackend::QueryOperationStatus status);
0093     void queryOperationWakeAll(BdEngineBackend::QueryOperationStatus status);
0094 
0095     /// called by DbEngineErrorHandler, implementing DbEngineErrorAnswer
0096     void connectionErrorContinueQueries()                                  override;
0097     void connectionErrorAbortQueries()                                     override;
0098 
0099     virtual void transactionFinished();
0100 
0101 public:
0102 
0103     QThreadStorage<DbEngineThreadData*>       threadDataStorage;
0104 
0105     /**
0106      * This compares to DbEngineThreadData's valid.
0107      * If currentValidity is increased and > valid, the db is marked as invalid
0108      */
0109     int                                       currentValidity;
0110 
0111     bool                                      isInTransaction;
0112 
0113     QString                                   backendName;
0114 
0115     DbEngineParameters                        parameters;
0116 
0117     BdEngineBackend::Status                   status;
0118 
0119     DbEngineLocking*                          lock;
0120 
0121     BdEngineBackend::QueryOperationStatus     operationStatus;
0122 
0123     QMutex                                    errorLockMutex;
0124     QWaitCondition                            errorLockCondVar;
0125     BdEngineBackend::QueryOperationStatus     errorLockOperationStatus;
0126 
0127     QMutex                                    busyWaitMutex;
0128     QWaitCondition                            busyWaitCondVar;
0129 
0130     DbEngineErrorHandler*                     errorHandler;
0131 
0132 public:
0133 
0134     class Q_DECL_HIDDEN AbstractUnlocker
0135     {
0136     public:
0137 
0138         explicit AbstractUnlocker(BdEngineBackendPrivate* const d);
0139         ~AbstractUnlocker();
0140 
0141         void finishAcquire();
0142 
0143     protected:
0144 
0145         int                           count;
0146         BdEngineBackendPrivate* const d;
0147     };
0148 
0149     friend class AbstractUnlocker;
0150 
0151     // ------------------------------------------------------------------
0152 
0153     class Q_DECL_HIDDEN AbstractWaitingUnlocker : public AbstractUnlocker
0154     {
0155     public:
0156 
0157         explicit AbstractWaitingUnlocker(BdEngineBackendPrivate* const d,
0158                                          QMutex* const mutex,
0159                                          QWaitCondition* const condVar);
0160         ~AbstractWaitingUnlocker();
0161 
0162         bool wait(unsigned long time = ULONG_MAX);
0163 
0164     protected:
0165 
0166         QMutex*         const mutex;
0167         QWaitCondition* const condVar;
0168     };
0169 
0170     // ------------------------------------------------------------------
0171 
0172     class Q_DECL_HIDDEN ErrorLocker : public AbstractWaitingUnlocker
0173     {
0174     public:
0175 
0176         explicit ErrorLocker(BdEngineBackendPrivate* const d);
0177         void wait();
0178     };
0179 
0180     // ------------------------------------------------------------------
0181 
0182     class Q_DECL_HIDDEN BusyWaiter : public AbstractWaitingUnlocker
0183     {
0184     public:
0185 
0186         explicit BusyWaiter(BdEngineBackendPrivate* const d);
0187     };
0188 
0189 public:
0190 
0191     BdEngineBackend* const q;
0192 };
0193 
0194 } // namespace Digikam
0195 
0196 #endif // DIGIKAM_DB_ENGINE_BACKEND_PRIVATE_H