Store highlight status per buffer coreside
[quassel.git] / src / core / abstractsqlstorage.h
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #pragma once
22
23 #include "storage.h"
24
25 #include <memory>
26
27 #include <QSqlDatabase>
28 #include <QSqlQuery>
29 #include <QSqlError>
30
31 class AbstractSqlMigrationReader;
32 class AbstractSqlMigrationWriter;
33
34 class AbstractSqlStorage : public Storage
35 {
36     Q_OBJECT
37
38 public:
39     AbstractSqlStorage(QObject *parent = 0);
40     virtual ~AbstractSqlStorage();
41
42     virtual std::unique_ptr<AbstractSqlMigrationReader> createMigrationReader() { return {}; }
43     virtual std::unique_ptr<AbstractSqlMigrationWriter> createMigrationWriter() { return {}; }
44
45 public slots:
46     virtual State init(const QVariantMap &settings = QVariantMap());
47     virtual bool setup(const QVariantMap &settings = QVariantMap());
48
49 protected:
50     inline virtual void sync() {};
51
52     QSqlDatabase logDb();
53
54     /**
55      * Fetch an SQL query string by name and optional schema version
56      *
57      * Loads the named SQL query from the built-in SQL resource collection, returning it as a
58      * string.  If a version is specified, it'll be loaded from the schema version-specific folder
59      * instead.
60      *
61      * @see schemaVersion()
62      *
63      * @param[in] queryName  File name of the SQL query, minus the .sql extension
64      * @param[in] version
65      * @parblock
66      * SQL schema version; if 0, fetches from current version, otherwise loads from the specified
67      * schema version instead of the current schema files.
68      * @endparblock
69      * @return String with the requested SQL query, ready for parameter substitution
70      */
71     QString queryString(const QString &queryName, int version = 0);
72
73     QStringList setupQueries();
74
75     QStringList upgradeQueries(int ver);
76     bool upgradeDb();
77
78     bool watchQuery(QSqlQuery &query);
79
80     int schemaVersion();
81     virtual int installedSchemaVersion() { return -1; };
82     virtual bool updateSchemaVersion(int newVersion) = 0;
83     virtual bool setupSchemaVersion(int version) = 0;
84
85     virtual void setConnectionProperties(const QVariantMap &properties) = 0;
86     virtual QString driverName() = 0;
87     inline virtual QString hostName() { return QString(); }
88     inline virtual int port() { return -1; }
89     virtual QString databaseName() = 0;
90     inline virtual QString userName() { return QString(); }
91     inline virtual QString password() { return QString(); }
92
93     //! Initialize db specific features on connect
94     /** This is called every time a connection to a specific SQL backend is established
95      *  the default implementation does nothing.
96      *
97      *  When reimplementing this method, don't use logDB() inside this function as
98      *  this would cause as we're just about to initialize that DB connection.
99      */
100     inline virtual bool initDbSession(QSqlDatabase & /* db */) { return true; }
101
102 private slots:
103     void connectionDestroyed();
104
105 private:
106     void addConnectionToPool();
107     void dbConnect(QSqlDatabase &db);
108
109     int _schemaVersion;
110     bool _debug;
111
112     static int _nextConnectionId;
113     QMutex _connectionPoolMutex;
114     // we let a Connection Object manage each actual db connection
115     // those objects reside in the thread the connection belongs to
116     // which allows us thread safe termination of a connection
117     class Connection;
118     QHash<QThread *, Connection *> _connectionPool;
119 };
120
121
122 // ========================================
123 //  AbstractSqlStorage::Connection
124 // ========================================
125 class AbstractSqlStorage::Connection : public QObject
126 {
127     Q_OBJECT
128
129 public:
130     Connection(const QString &name, QObject *parent = 0);
131     ~Connection();
132
133     inline QLatin1String name() const { return QLatin1String(_name); }
134
135 private:
136     QByteArray _name;
137 };
138
139
140 // ========================================
141 //  AbstractSqlMigrator
142 // ========================================
143 class AbstractSqlMigrator
144 {
145 public:
146     // migration objects
147     struct QuasselUserMO {
148         UserId id;
149         QString username;
150         QString password;
151         int hashversion;
152         QString authenticator;
153     };
154
155     struct SenderMO {
156         int senderId;
157         QString sender;
158         SenderMO() : senderId(0) {}
159     };
160
161     struct IdentityMO {
162         IdentityId id;
163         UserId userid;
164         QString identityname;
165         QString realname;
166         QString awayNick;
167         bool awayNickEnabled;
168         QString awayReason;
169         bool awayReasonEnabled;
170         bool autoAwayEnabled;
171         int autoAwayTime;
172         QString autoAwayReason;
173         bool autoAwayReasonEnabled;
174         bool detachAwayEnabled;
175         QString detachAwayReason;
176         bool detchAwayReasonEnabled;
177         QString ident;
178         QString kickReason;
179         QString partReason;
180         QString quitReason;
181         QByteArray sslCert;
182         QByteArray sslKey;
183     };
184
185     struct IdentityNickMO {
186         int nickid;
187         IdentityId identityId;
188         QString nick;
189     };
190
191     struct NetworkMO {
192         NetworkId networkid;
193         UserId userid;
194         QString networkname;
195         IdentityId identityid;
196         QString encodingcodec;
197         QString decodingcodec;
198         QString servercodec;
199         bool userandomserver;
200         QString perform;
201         bool useautoidentify;
202         QString autoidentifyservice;
203         QString autoidentifypassword;
204         bool useautoreconnect;
205         int autoreconnectinterval;
206         int autoreconnectretries;
207         bool unlimitedconnectretries;
208         bool rejoinchannels;
209         // Custom rate limiting
210         bool usecustommessagerate;
211         int messagerateburstsize;
212         int messageratedelay;
213         bool unlimitedmessagerate;
214         // ...
215         bool connected;
216         QString usermode;
217         QString awaymessage;
218         QString attachperform;
219         QString detachperform;
220         bool usesasl;
221         QString saslaccount;
222         QString saslpassword;
223     };
224
225     struct BufferMO {
226         BufferId bufferid;
227         UserId userid;
228         int groupid;
229         NetworkId networkid;
230         QString buffername;
231         QString buffercname;
232         int buffertype;
233         int lastmsgid;
234         int lastseenmsgid;
235         int markerlinemsgid;
236         int bufferactivity;
237         int highlightcount;
238         QString key;
239         bool joined;
240         QString cipher;
241     };
242
243     struct BacklogMO {
244         MsgId messageid;
245         QDateTime time; // has to be in UTC!
246         BufferId bufferid;
247         int type;
248         int flags;
249         int senderid;
250         QString senderprefixes;
251         QString message;
252     };
253
254     struct IrcServerMO {
255         int serverid;
256         UserId userid;
257         NetworkId networkid;
258         QString hostname;
259         int port;
260         QString password;
261         bool ssl;
262         bool sslverify;     /// If true, validate SSL certificates
263         int sslversion;
264         bool useproxy;
265         int proxytype;
266         QString proxyhost;
267         int proxyport;
268         QString proxyuser;
269         QString proxypass;
270     };
271
272     struct UserSettingMO {
273         UserId userid;
274         QString settingname;
275         QByteArray settingvalue;
276     };
277
278     enum MigrationObject {
279         QuasselUser,
280         Sender,
281         Identity,
282         IdentityNick,
283         Network,
284         Buffer,
285         Backlog,
286         IrcServer,
287         UserSetting
288     };
289
290     AbstractSqlMigrator();
291     virtual ~AbstractSqlMigrator() {}
292
293     static QString migrationObject(MigrationObject moType);
294
295 protected:
296     void newQuery(const QString &query, QSqlDatabase db);
297     virtual void resetQuery();
298     virtual bool prepareQuery(MigrationObject mo) = 0;
299     bool exec();
300     inline bool next() { return _query->next(); }
301     inline QVariant value(int index) { return _query->value(index); }
302     inline void bindValue(const QString &placeholder, const QVariant &val) { _query->bindValue(placeholder, val); }
303     inline void bindValue(int pos, const QVariant &val) { _query->bindValue(pos, val); }
304
305     inline QSqlError lastError() { return _query ? _query->lastError() : QSqlError(); }
306     void dumpStatus();
307     inline QString executedQuery() { return _query ? _query->executedQuery() : QString(); }
308     inline QVariantList boundValues();
309
310     virtual bool transaction() = 0;
311     virtual void rollback() = 0;
312     virtual bool commit() = 0;
313
314 private:
315     QSqlQuery *_query;
316 };
317
318
319 class AbstractSqlMigrationReader : public AbstractSqlMigrator
320 {
321 public:
322     AbstractSqlMigrationReader();
323
324     virtual bool readMo(QuasselUserMO &user) = 0;
325     virtual bool readMo(IdentityMO &identity) = 0;
326     virtual bool readMo(IdentityNickMO &identityNick) = 0;
327     virtual bool readMo(NetworkMO &network) = 0;
328     virtual bool readMo(BufferMO &buffer) = 0;
329     virtual bool readMo(SenderMO &sender) = 0;
330     virtual bool readMo(BacklogMO &backlog) = 0;
331     virtual bool readMo(IrcServerMO &ircserver) = 0;
332     virtual bool readMo(UserSettingMO &userSetting) = 0;
333
334     bool migrateTo(AbstractSqlMigrationWriter *writer);
335
336 private:
337     void abortMigration(const QString &errorMsg = QString());
338     bool finalizeMigration();
339
340     template<typename T> bool transferMo(MigrationObject moType, T &mo);
341
342     AbstractSqlMigrationWriter *_writer;
343 };
344
345
346 class AbstractSqlMigrationWriter : public AbstractSqlMigrator
347 {
348 public:
349     virtual bool writeMo(const QuasselUserMO &user) = 0;
350     virtual bool writeMo(const IdentityMO &identity) = 0;
351     virtual bool writeMo(const IdentityNickMO &identityNick) = 0;
352     virtual bool writeMo(const NetworkMO &network) = 0;
353     virtual bool writeMo(const BufferMO &buffer) = 0;
354     virtual bool writeMo(const SenderMO &sender) = 0;
355     virtual bool writeMo(const BacklogMO &backlog) = 0;
356     virtual bool writeMo(const IrcServerMO &ircserver) = 0;
357     virtual bool writeMo(const UserSettingMO &userSetting) = 0;
358
359     inline bool migrateFrom(AbstractSqlMigrationReader *reader) { return reader->migrateTo(this); }
360
361     // called after migration process
362     virtual inline bool postProcess() { return true; }
363     friend class AbstractSqlMigrationReader;
364 };