0ae14046ca9bca688aa8d6ae86de54b4f5cb282e
[quassel.git] / src / core / abstractsqlstorage.h
1 /***************************************************************************
2  *   Copyright (C) 2005-2016 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 #ifndef ABSTRACTSQLSTORAGE_H
22 #define ABSTRACTSQLSTORAGE_H
23
24 #include "storage.h"
25
26 #include <QSqlDatabase>
27 #include <QSqlQuery>
28 #include <QSqlError>
29
30 class AbstractSqlMigrationReader;
31 class AbstractSqlMigrationWriter;
32
33 class AbstractSqlStorage : public Storage
34 {
35     Q_OBJECT
36
37 public:
38     AbstractSqlStorage(QObject *parent = 0);
39     virtual ~AbstractSqlStorage();
40
41     virtual inline AbstractSqlMigrationReader *createMigrationReader() { return 0; }
42     virtual inline AbstractSqlMigrationWriter *createMigrationWriter() { return 0; }
43
44 public slots:
45     virtual State init(const QVariantMap &settings = QVariantMap());
46     virtual bool setup(const QVariantMap &settings = QVariantMap());
47
48 protected:
49     inline virtual void sync() {};
50
51     QSqlDatabase logDb();
52
53     QString queryString(const QString &queryName, int version);
54     inline QString queryString(const QString &queryName) { return queryString(queryName, 0); }
55
56     QStringList setupQueries();
57
58     QStringList upgradeQueries(int ver);
59     bool upgradeDb();
60
61     bool watchQuery(QSqlQuery &query);
62
63     int schemaVersion();
64     virtual int installedSchemaVersion() { return -1; };
65     virtual bool updateSchemaVersion(int newVersion) = 0;
66     virtual bool setupSchemaVersion(int version) = 0;
67
68     virtual void setConnectionProperties(const QVariantMap &properties) = 0;
69     virtual QString driverName() = 0;
70     inline virtual QString hostName() { return QString(); }
71     inline virtual int port() { return -1; }
72     virtual QString databaseName() = 0;
73     inline virtual QString userName() { return QString(); }
74     inline virtual QString password() { return QString(); }
75
76     //! Initialize db specific features on connect
77     /** This is called every time a connection to a specific SQL backend is established
78      *  the default implementation does nothing.
79      *
80      *  When reimplementing this method, don't use logDB() inside this function as
81      *  this would cause as we're just about to initialize that DB connection.
82      */
83     inline virtual bool initDbSession(QSqlDatabase & /* db */) { return true; }
84
85 private slots:
86     void connectionDestroyed();
87
88 private:
89     void addConnectionToPool();
90     void dbConnect(QSqlDatabase &db);
91
92     int _schemaVersion;
93     bool _debug;
94
95     static int _nextConnectionId;
96     QMutex _connectionPoolMutex;
97     // we let a Connection Object manage each actual db connection
98     // those objects reside in the thread the connection belongs to
99     // which allows us thread safe termination of a connection
100     class Connection;
101     QHash<QThread *, Connection *> _connectionPool;
102 };
103
104
105 // ========================================
106 //  AbstractSqlStorage::Connection
107 // ========================================
108 class AbstractSqlStorage::Connection : public QObject
109 {
110     Q_OBJECT
111
112 public:
113     Connection(const QString &name, QObject *parent = 0);
114     ~Connection();
115
116     inline QLatin1String name() const { return QLatin1String(_name); }
117
118 private:
119     QByteArray _name;
120 };
121
122
123 // ========================================
124 //  AbstractSqlMigrator
125 // ========================================
126 class AbstractSqlMigrator
127 {
128 public:
129     // migration objects
130     struct QuasselUserMO {
131         UserId id;
132         QString username;
133         QString password;
134         int hashversion;
135     };
136
137     struct SenderMO {
138         int senderId;
139         QString sender;
140         SenderMO() : senderId(0) {}
141     };
142
143     struct IdentityMO {
144         IdentityId id;
145         UserId userid;
146         QString identityname;
147         QString realname;
148         QString awayNick;
149         bool awayNickEnabled;
150         QString awayReason;
151         bool awayReasonEnabled;
152         bool autoAwayEnabled;
153         int autoAwayTime;
154         QString autoAwayReason;
155         bool autoAwayReasonEnabled;
156         bool detachAwayEnabled;
157         QString detachAwayReason;
158         bool detchAwayReasonEnabled;
159         QString ident;
160         QString kickReason;
161         QString partReason;
162         QString quitReason;
163         QByteArray sslCert;
164         QByteArray sslKey;
165     };
166
167     struct IdentityNickMO {
168         int nickid;
169         IdentityId identityId;
170         QString nick;
171     };
172
173     struct NetworkMO {
174         NetworkId networkid;
175         UserId userid;
176         QString networkname;
177         IdentityId identityid;
178         QString encodingcodec;
179         QString decodingcodec;
180         QString servercodec;
181         bool userandomserver;
182         QString perform;
183         bool useautoidentify;
184         QString autoidentifyservice;
185         QString autoidentifypassword;
186         bool useautoreconnect;
187         int autoreconnectinterval;
188         int autoreconnectretries;
189         bool unlimitedconnectretries;
190         bool rejoinchannels;
191         // Custom rate limiting
192         bool usecustommessagerate;
193         int messagerateburstsize;
194         int messageratedelay;
195         bool unlimitedmessagerate;
196         // ...
197         bool connected;
198         QString usermode;
199         QString awaymessage;
200         QString attachperform;
201         QString detachperform;
202         bool usesasl;
203         QString saslaccount;
204         QString saslpassword;
205     };
206
207     struct BufferMO {
208         BufferId bufferid;
209         UserId userid;
210         int groupid;
211         NetworkId networkid;
212         QString buffername;
213         QString buffercname;
214         int buffertype;
215         int lastseenmsgid;
216         int markerlinemsgid;
217         QString key;
218         bool joined;
219     };
220
221     struct BacklogMO {
222         MsgId messageid;
223         QDateTime time; // has to be in UTC!
224         BufferId bufferid;
225         int type;
226         int flags;
227         int senderid;
228         QString message;
229     };
230
231     struct IrcServerMO {
232         int serverid;
233         UserId userid;
234         NetworkId networkid;
235         QString hostname;
236         int port;
237         QString password;
238         bool ssl;
239         bool sslverify;     /// If true, validate SSL certificates
240         int sslversion;
241         bool useproxy;
242         int proxytype;
243         QString proxyhost;
244         int proxyport;
245         QString proxyuser;
246         QString proxypass;
247     };
248
249     struct UserSettingMO {
250         UserId userid;
251         QString settingname;
252         QByteArray settingvalue;
253     };
254
255     enum MigrationObject {
256         QuasselUser,
257         Sender,
258         Identity,
259         IdentityNick,
260         Network,
261         Buffer,
262         Backlog,
263         IrcServer,
264         UserSetting
265     };
266
267     AbstractSqlMigrator();
268     virtual ~AbstractSqlMigrator() {}
269
270     static QString migrationObject(MigrationObject moType);
271
272 protected:
273     void newQuery(const QString &query, QSqlDatabase db);
274     virtual void resetQuery();
275     virtual bool prepareQuery(MigrationObject mo) = 0;
276     bool exec();
277     inline bool next() { return _query->next(); }
278     inline QVariant value(int index) { return _query->value(index); }
279     inline void bindValue(const QString &placeholder, const QVariant &val) { _query->bindValue(placeholder, val); }
280     inline void bindValue(int pos, const QVariant &val) { _query->bindValue(pos, val); }
281
282     inline QSqlError lastError() { return _query ? _query->lastError() : QSqlError(); }
283     void dumpStatus();
284     inline QString executedQuery() { return _query ? _query->executedQuery() : QString(); }
285     inline QVariantList boundValues();
286
287     virtual bool transaction() = 0;
288     virtual void rollback() = 0;
289     virtual bool commit() = 0;
290
291 private:
292     QSqlQuery *_query;
293 };
294
295
296 class AbstractSqlMigrationReader : public AbstractSqlMigrator
297 {
298 public:
299     AbstractSqlMigrationReader();
300
301     virtual bool readMo(QuasselUserMO &user) = 0;
302     virtual bool readMo(IdentityMO &identity) = 0;
303     virtual bool readMo(IdentityNickMO &identityNick) = 0;
304     virtual bool readMo(NetworkMO &network) = 0;
305     virtual bool readMo(BufferMO &buffer) = 0;
306     virtual bool readMo(SenderMO &sender) = 0;
307     virtual bool readMo(BacklogMO &backlog) = 0;
308     virtual bool readMo(IrcServerMO &ircserver) = 0;
309     virtual bool readMo(UserSettingMO &userSetting) = 0;
310
311     bool migrateTo(AbstractSqlMigrationWriter *writer);
312
313 private:
314     void abortMigration(const QString &errorMsg = QString());
315     bool finalizeMigration();
316
317     template<typename T> bool transferMo(MigrationObject moType, T &mo);
318
319     AbstractSqlMigrationWriter *_writer;
320 };
321
322
323 class AbstractSqlMigrationWriter : public AbstractSqlMigrator
324 {
325 public:
326     virtual bool writeMo(const QuasselUserMO &user) = 0;
327     virtual bool writeMo(const IdentityMO &identity) = 0;
328     virtual bool writeMo(const IdentityNickMO &identityNick) = 0;
329     virtual bool writeMo(const NetworkMO &network) = 0;
330     virtual bool writeMo(const BufferMO &buffer) = 0;
331     virtual bool writeMo(const SenderMO &sender) = 0;
332     virtual bool writeMo(const BacklogMO &backlog) = 0;
333     virtual bool writeMo(const IrcServerMO &ircserver) = 0;
334     virtual bool writeMo(const UserSettingMO &userSetting) = 0;
335
336     inline bool migrateFrom(AbstractSqlMigrationReader *reader) { return reader->migrateTo(this); }
337
338     // called after migration process
339     virtual inline bool postProcess() { return true; }
340     friend class AbstractSqlMigrationReader;
341 };
342
343
344 #endif