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