1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/* ============================================================
 *
 * This file is a part of digiKam project
 * https://www.digikam.org
 *
 * Date        : 2007-03-18
 * Description : Core database access wrapper.
 *
 * SPDX-FileCopyrightText: 2007-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
 * SPDX-FileCopyrightText: 2010-2025 by Gilles Caulier <caulier dot gilles at gmail dot com>
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 *
 * ============================================================ */

#pragma once

// Local includes

#include "digikam_export.h"
#include "dbengineparameters.h"

namespace Digikam
{

class CoreDbBackend;
class CoreDB;
class CoreDbWatch;
class InitializationObserver;
class DbEngineErrorHandler;
class CoreDbAccessStaticPriv;

/**
 * The CoreDbAccess provides access to the database:
 * Create an instance of this class on the stack to retrieve a pointer to the database.
 * While you hold an instance of CoreDbAccess, the database access is locked for other threads,
 * but _not_ for other processes. This is due to the fact that while databases allow
 * concurrent access (of course), their client libs may not be thread-safe.
 *
 * When initializing your application, you need to call two methods:
 * - in a not-yet-multithreaded context, you need to call setParameters
 * - to make sure that the database is available and the schema
 *   is properly initialized, call checkReadyForUse()
 */
class DIGIKAM_DATABASE_EXPORT CoreDbAccess
{
public:

    enum ApplicationStatus
    {
        MainApplication,
        DatabaseSlave
    };

public:

    /**
     * Create a CoreDbAccess object for the default database.
     * Note that when initializing your app, setParameters need to be called
     * (in a not-yet-multithreaded context) for this to work.
     * If the database is not yet opened, it will be opened.
     * The schema will not be checked, use checkReadyForUse()
     * for a full opening process including schema update and error messages.
     */
    CoreDbAccess();
    ~CoreDbAccess();

    /**
     * Retrieve a pointer to the album database
     */
    CoreDB* db()             const;

    /**
     * Retrieve a pointer to the database backend
     */
    CoreDbBackend* backend() const;

    /**
     * Returns the error message for the last error that occurred,
     * or a null QString of no error occurred.
     */
    QString lastError();<--- Function 'lastError()' should return member 'lastError' by const reference.

    /**
     * Set the "last error" message. This method is not for public use.
     */
    void setLastError(const QString& error);

public:

    /**
     * Return the default parameters
     */
    static DbEngineParameters parameters();

    /**
     * Set the default parameters.
     * Call this function at least once in the starting phase of your application,
     * when no other threads will yet access the database, to initialize DatabaseAcccess.
     * After this initial call, it is thread-safe to call this function again.
     * In a subsequent call, if the parameters are identical, nothing is done.
     * If the parameters change, the current database will be closed.
     * When parameters have been set or changed, the new one will be opened on-demand,
     * i.e. when the first CoreDbAccess object is constructed.
     */
    static void setParameters(const DbEngineParameters& parameters);
    static void setParameters(const DbEngineParameters& parameters, ApplicationStatus status);

    /**
     * Method to one-time initialize a database when new parameters have been set:
     * Make sure that the database is open, that the schema has properly been initialized.
     * If the parameters were not changed, this method has no effect.
     * @returns if the database is ready for use
     */
    static bool checkReadyForUse(InitializationObserver* const observer = nullptr);

    /**
     * Clean up the database access.
     * When this function has been called, the access can be restored by calling setParameters.
     * Construction a database access object otherwise after calling this method will crash.
     */
    static void cleanUpDatabase();

    /**
     * Return the CoreDbWatch.
     */
    static CoreDbWatch* databaseWatch();

    /**
     * Setup the errors handler instance.
     */
    static void initDbEngineErrorHandler(DbEngineErrorHandler* const errorhandler);

private:

    // Disable
    explicit CoreDbAccess(bool);
    CoreDbAccess(const CoreDbAccess&)            = delete;
    CoreDbAccess& operator=(const CoreDbAccess&) = delete;

    friend class CoreDbAccessUnlock;
    static CoreDbAccessStaticPriv* d;
};

// -----------------------------------------------------------------------------

class CoreDbAccessUnlock
{
public:

    /**
     * Acquire an object of this class if you want to assure
     * that the CoreDbAccess is _not_ held during the lifetime of the object.
     * At creation, the lock is obtained shortly, then all locks are released.
     * At destruction, all locks are acquired again.
     * If you need to access any locked structures during lifetime, acquire a new
     * CoreDbAccess.
     */
    CoreDbAccessUnlock();
    explicit CoreDbAccessUnlock(CoreDbAccess* const access);
    ~CoreDbAccessUnlock();

private:

    // Disable
    CoreDbAccessUnlock(const CoreDbAccessUnlock&)            = delete;
    CoreDbAccessUnlock& operator=(const CoreDbAccessUnlock&) = delete;

    int count = 0;
};

} // namespace Digikam