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