Akonadi

datastore.h
1 /***************************************************************************
2  * SPDX-FileCopyrightText: 2006 Andreas Gungl <[email protected]> *
3  * *
4  * SPDX-License-Identifier: LGPL-2.0-or-later *
5  ***************************************************************************/
6 
7 #pragma once
8 
9 #include <QList>
10 #include <QMutex>
11 #include <QObject>
12 #include <QSqlDatabase>
13 #include <QThreadStorage>
14 #include <QVector>
15 
16 class QSqlQuery;
17 class QTimer;
18 
19 #include "entities.h"
20 #include "notificationcollector.h"
21 
22 #include <memory>
23 
24 namespace Akonadi
25 {
26 namespace Server
27 {
28 class DataStore;
29 class DataStoreFactory
30 {
31 public:
32  virtual ~DataStoreFactory() = default;
33  virtual DataStore *createStore() = 0;
34 
35 protected:
36  explicit DataStoreFactory() = default;
37 
38 private:
39  Q_DISABLE_COPY_MOVE(DataStoreFactory)
40 };
41 
42 class NotificationCollector;
43 
44 /**
45  This class handles all the database access.
46 
47  <h4>Database configuration</h4>
48 
49  You can select between various database backends during runtime using the
50  @c $HOME/.config/akonadi/akonadiserverrc configuration file.
51 
52  Example:
53 @verbatim
54 [%General]
55 Driver=QMYSQL
56 
57 [QMYSQL_EMBEDDED]
58 Name=akonadi
59 Options=SERVER_DATADIR=/home/foo/.local/share/akonadi/db_data
60 
61 [QMYSQL]
62 Name=akonadi
63 Host=localhost
64 User=foo
65 Password=*****
66 #Options=UNIX_SOCKET=/home/foo/.local/share/akonadi/socket-bar/mysql.socket
67 StartServer=true
68 ServerPath=/usr/sbin/mysqld
69 
70 [QSQLITE]
71 Name=/home/foo/.local/share/akonadi/akonadi.db
72 @endverbatim
73 
74  Use @c General/Driver to select the QSql driver to use for database
75  access. The following drivers are currently supported, other might work
76  but are untested:
77 
78  - QMYSQL
79  - QMYSQL_EMBEDDED
80  - QSQLITE
81 
82  The options for each driver are read from the corresponding group.
83  The following options are supported, dependent on the driver not all of them
84  might have an effect:
85 
86  - Name: Database name, for sqlite that's the file name of the database.
87  - Host: Hostname of the database server
88  - User: Username for the database server
89  - Password: Password for the database server
90  - Options: Additional options, format is driver-dependent
91  - StartServer: Start the database locally just for Akonadi instead of using an existing one
92  - ServerPath: Path to the server executable
93 */
94 class DataStore : public QObject
95 {
96  Q_OBJECT
97 public:
98  const constexpr static bool Silent = true;
99 
100  static void setFactory(std::unique_ptr<DataStoreFactory> factory);
101 
102  /**
103  Closes the database connection and destroys the DataStore object.
104  */
105  ~DataStore() override;
106 
107  /**
108  Opens the database connection.
109  */
110  virtual void open();
111 
112  /**
113  Closes the database connection.
114  */
115  void close();
116 
117  /**
118  Initializes the database. Should be called during startup by the main thread.
119  */
120  virtual bool init();
121 
122  /**
123  Per thread singleton.
124  */
125  static DataStore *self();
126 
127  /**
128  * Returns whether per thread DataStore has been created.
129  */
130  static bool hasDataStore();
131 
132  /* --- ItemFlags ----------------------------------------------------- */
133  virtual bool setItemsFlags(const PimItem::List &items,
134  const QVector<Flag> *currentFlags,
135  const QVector<Flag> &newFlags,
136  bool *flagsChanged = nullptr,
137  const Collection &col = Collection(),
138  bool silent = false);
139  virtual bool appendItemsFlags(const PimItem::List &items,
140  const QVector<Flag> &flags,
141  bool *flagsChanged = nullptr,
142  bool checkIfExists = true,
143  const Collection &col = Collection(),
144  bool silent = false);
145  virtual bool removeItemsFlags(const PimItem::List &items,
146  const QVector<Flag> &flags,
147  bool *tagsChanged = nullptr,
148  const Collection &collection = Collection(),
149  bool silent = false);
150 
151  /* --- ItemTags ----------------------------------------------------- */
152  virtual bool setItemsTags(const PimItem::List &items, const Tag::List &tags, bool *tagsChanged = nullptr, bool silent = false);
153  virtual bool appendItemsTags(const PimItem::List &items,
154  const Tag::List &tags,
155  bool *tagsChanged = nullptr,
156  bool checkIfExists = true,
157  const Collection &col = Collection(),
158  bool silent = false);
159  virtual bool removeItemsTags(const PimItem::List &items, const Tag::List &tags, bool *tagsChanged = nullptr, bool silent = false);
160  virtual bool removeTags(const Tag::List &tags, bool silent = false);
161 
162  /* --- ItemParts ----------------------------------------------------- */
163  virtual bool removeItemParts(const PimItem &item, const QSet<QByteArray> &parts);
164 
165  // removes all payload parts for this item.
166  virtual bool invalidateItemCache(const PimItem &item);
167 
168  /* --- Collection ------------------------------------------------------ */
169  virtual bool appendCollection(Collection &collection, const QStringList &mimeTypes, const QMap<QByteArray, QByteArray> &attributes);
170 
171  /// removes the given collection and all its content
172  virtual bool cleanupCollection(Collection &collection);
173  /// same as the above but for database backends without working referential actions on foreign keys
174  virtual bool cleanupCollection_slow(Collection &collection);
175 
176  /// moves the collection @p collection to @p newParent.
177  virtual bool moveCollection(Collection &collection, const Collection &newParent);
178 
179  virtual bool appendMimeTypeForCollection(qint64 collectionId, const QStringList &mimeTypes);
180 
181  static QString collectionDelimiter()
182  {
183  return QStringLiteral("/");
184  }
185 
186  /**
187  Determines the active cache policy for this Collection.
188  The active cache policy is set in the corresponding Collection fields.
189  */
190  virtual void activeCachePolicy(Collection &col);
191 
192  /// Returns all virtual collections the @p item is linked to
193  QVector<Collection> virtualCollections(const PimItem &item);
194 
195  QMap<Server::Entity::Id, QList<PimItem>> virtualCollections(const Akonadi::Server::PimItem::List &items);
196 
197  /* --- PimItem ------------------------------------------------------- */
198  virtual bool appendPimItem(QVector<Part> &parts,
199  const QVector<Flag> &flags,
200  const MimeType &mimetype,
201  const Collection &collection,
202  const QDateTime &dateTime,
203  const QString &remote_id,
204  const QString &remoteRevision,
205  const QString &gid,
206  PimItem &pimItem);
207  /**
208  * Removes the pim item and all referenced data ( e.g. flags )
209  */
210  virtual bool cleanupPimItems(const PimItem::List &items, bool silent = false);
211 
212  /**
213  * Unhides the specified PimItem. Emits the itemAdded() notification as
214  * the hidden flag is assumed to have been set by appendPimItem() before
215  * pushing the item to the preprocessor chain. The hidden item had his
216  * notifications disabled until now (so for the clients the "unhide" operation
217  * is actually a new item arrival).
218  *
219  * This function does NOT verify if the item was *really* hidden: this is
220  * responsibility of the caller.
221  */
222  virtual bool unhidePimItem(PimItem &pimItem);
223 
224  /**
225  * Unhides all the items which have the "hidden" flag set.
226  * This function doesn't emit any notification about the items
227  * being unhidden so it's meant to be called only in rare circumstances.
228  * The most notable call to this function is at server startup
229  * when we attempt to restore a clean state of the database.
230  */
231  virtual bool unhideAllPimItems();
232 
233  /* --- Collection attributes ------------------------------------------ */
234  virtual bool addCollectionAttribute(const Collection &col, const QByteArray &key, const QByteArray &value, bool silent = false);
235  /**
236  * Removes the given collection attribute for @p col.
237  * @throws HandlerException on database errors
238  * @returns @c true if the attribute existed, @c false otherwise
239  */
240  virtual bool removeCollectionAttribute(const Collection &col, const QByteArray &key);
241 
242  /* --- Helper functions ---------------------------------------------- */
243 
244  /**
245  Begins a transaction. No changes will be written to the database and
246  no notification signal will be emitted unless you call commitTransaction().
247  @return @c true if successful.
248  */
249  virtual bool beginTransaction(const QString &name);
250 
251  /**
252  Reverts all changes within the current transaction.
253  */
254  virtual bool rollbackTransaction();
255 
256  /**
257  Commits all changes within the current transaction and emits all
258  collected notification signals. If committing fails, the transaction
259  will be rolled back.
260  */
261  virtual bool commitTransaction();
262 
263  /**
264  Returns true if there is a transaction in progress.
265  */
266  bool inTransaction() const;
267 
268  /**
269  Returns the notification collector of this DataStore object.
270  Use this to listen to change notification signals.
271  */
273 
274  /**
275  Returns the QSqlDatabase object. Use this for generating queries yourself.
276 
277  Will [re-]open the database, if it is closed.
278  */
280 
281  /**
282  Sets the current session id.
283  */
284  void setSessionId(const QByteArray &sessionId)
285  {
286  mSessionId = sessionId;
287  }
288 
289  /**
290  Returns if the database is currently open
291  */
292  bool isOpened() const
293  {
294  return m_dbOpened;
295  }
296 
297  bool doRollback();
298  void transactionKilledByDB();
299 
300 Q_SIGNALS:
301  /**
302  Emitted if a transaction has been successfully committed.
303  */
304  void transactionCommitted();
305  /**
306  Emitted if a transaction has been aborted.
307  */
308  void transactionRolledBack();
309 
310 protected:
311  /**
312  Creates a new DataStore object and opens it.
313  */
314  DataStore(AkonadiServer &akonadi);
315 
316  void debugLastDbError(const char *actionDescription) const;
317  void debugLastQueryError(const QSqlQuery &query, const char *actionDescription) const;
318 
319 private:
320  bool doAppendItemsFlag(const PimItem::List &items, const Flag &flag, const QSet<PimItem::Id> &existing, const Collection &col, bool silent);
321 
322  bool doAppendItemsTag(const PimItem::List &items, const Tag &tag, const QSet<Entity::Id> &existing, const Collection &col, bool silent);
323 
324  /** Converts the given date/time to the database format, i.e.
325  "YYYY-MM-DD HH:MM:SS".
326  @param dateTime the date/time in UTC
327  @return the date/time in database format
328  @see dateTimeToQDateTime
329  */
330  static QString dateTimeFromQDateTime(const QDateTime &dateTime);
331 
332  /** Converts the given date/time from database format to QDateTime.
333  @param dateTime the date/time in database format
334  @return the date/time as QDateTime
335  @see dateTimeFromQDateTime
336  */
337  static QDateTime dateTimeToQDateTime(const QByteArray &dateTime);
338 
339 private Q_SLOTS:
340  void sendKeepAliveQuery();
341 
342 protected:
343  static std::unique_ptr<DataStoreFactory> sFactory;
344  std::unique_ptr<NotificationCollector> mNotificationCollector;
345  AkonadiServer &m_akonadi;
346 
347 private:
349 
350  void cleanupAfterRollback();
351  QString m_connectionName;
352  QSqlDatabase m_database;
353  bool m_dbOpened;
354  bool m_transactionKilledByDB = false;
355  uint m_transactionLevel;
356  struct TransactionQuery {
357  QString query;
358  QVector<QVariant> boundValues;
359  bool isBatch;
360  };
361  QByteArray mSessionId;
362  QTimer *m_keepAliveTimer = nullptr;
363  static bool s_hasForeignKeyConstraints;
364  static QMutex sTransactionMutex;
365 
366  friend class DataStoreFactory;
367 };
368 
369 } // namespace Server
370 } // namespace Akonadi
371 
Q_OBJECTQ_OBJECT
NotificationCollector * notificationCollector()
Returns the notification collector of this DataStore object.
Definition: datastore.cpp:206
This class handles all the database access.
Definition: datastore.h:94
virtual bool cleanupCollection_slow(Collection &collection)
same as the above but for database backends without working referential actions on foreign keys
Definition: datastore.cpp:848
virtual void open()
Opens the database connection.
Definition: datastore.cpp:101
Q_SLOTSQ_SLOTS
Part of the DataStore, collects change notifications and emits them after the current transaction has...
QVector< Collection > virtualCollections(const PimItem &item)
Returns all virtual collections the item is linked to.
Definition: datastore.cpp:1033
bool inTransaction() const
Returns true if there is a transaction in progress.
Definition: datastore.cpp:1451
An Akonadi Tag.
Definition: tag.h:25
QSqlDatabase database()
Returns the QSqlDatabase object.
Definition: datastore.cpp:135
Represents a collection of PIM items.
Definition: collection.h:61
void close()
Closes the database connection.
Definition: datastore.cpp:143
virtual bool beginTransaction(const QString &name)
Begins a transaction.
Definition: datastore.cpp:1350
virtual bool unhidePimItem(PimItem &pimItem)
Unhides the specified PimItem.
Definition: datastore.cpp:1158
Q_DISABLE_COPY_MOVE(Class)
virtual bool rollbackTransaction()
Reverts all changes within the current transaction.
Definition: datastore.cpp:1393
virtual void activeCachePolicy(Collection &col)
Determines the active cache policy for this Collection.
Definition: datastore.cpp:1008
virtual bool cleanupPimItems(const PimItem::List &items, bool silent=false)
Removes the pim item and all referenced data ( e.g.
Definition: datastore.cpp:1186
void transactionRolledBack()
Emitted if a transaction has been aborted.
virtual bool commitTransaction()
Commits all changes within the current transaction and emits all collected notification signals.
Definition: datastore.cpp:1415
void transactionCommitted()
Emitted if a transaction has been successfully committed.
DataStore(AkonadiServer &akonadi)
Creates a new DataStore object and opens it.
Definition: datastore.cpp:80
~DataStore() override
Closes the database connection and destroys the DataStore object.
Definition: datastore.cpp:96
Q_SIGNALSQ_SIGNALS
virtual bool moveCollection(Collection &collection, const Collection &newParent)
moves the collection collection to newParent.
Definition: datastore.cpp:942
virtual bool cleanupCollection(Collection &collection)
removes the given collection and all its content
Definition: datastore.cpp:801
bool isOpened() const
Returns if the database is currently open.
Definition: datastore.h:292
virtual bool removeCollectionAttribute(const Collection &col, const QByteArray &key)
Removes the given collection attribute for col.
Definition: datastore.cpp:1266
static bool hasDataStore()
Returns whether per thread DataStore has been created.
Definition: datastore.cpp:223
void setSessionId(const QByteArray &sessionId)
Sets the current session id.
Definition: datastore.h:284
virtual bool unhideAllPimItems()
Unhides all the items which have the "hidden" flag set.
Definition: datastore.cpp:1170
virtual bool init()
Initializes the database.
Definition: datastore.cpp:170
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Jun 30 2022 03:51:45 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.