Separate persistency for marker line (backend only)
[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
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 void initDbSession(QSqlDatabase & /* db */) {}
84
85 private slots:
86   void connectionDestroyed();
87
88 private:
89   void addConnectionToPool();
90
91   int _schemaVersion;
92
93   static int _nextConnectionId;
94   QMutex _connectionPoolMutex;
95   // we let a Connection Object manage each actual db connection
96   // those objects reside in the thread the connection belongs to
97   // which allows us thread safe termination of a connection
98   class Connection;
99   QHash<QThread *, Connection *> _connectionPool;
100 };
101
102 // ========================================
103 //  AbstractSqlStorage::Connection
104 // ========================================
105 class AbstractSqlStorage::Connection : public QObject {
106   Q_OBJECT
107
108 public:
109   Connection(const QString &name, QObject *parent = 0);
110   ~Connection();
111
112   inline QLatin1String name() const { return QLatin1String(_name); }
113
114 private:
115   QByteArray _name;
116 };
117
118
119 // ========================================
120 //  AbstractSqlMigrator
121 // ========================================
122 class AbstractSqlMigrator {
123 public:
124   // migration objects
125   struct QuasselUserMO {
126     UserId id;
127     QString username;
128     QString password;
129   };
130
131   struct SenderMO {
132     int senderId;
133     QString sender;
134     SenderMO() : senderId(0) {}
135   };
136
137   struct IdentityMO {
138     IdentityId id;
139     UserId userid;
140     QString identityname;
141     QString realname;
142     QString awayNick;
143     bool awayNickEnabled;
144     QString awayReason;
145     bool awayReasonEnabled;
146     bool autoAwayEnabled;
147     int autoAwayTime;
148     QString autoAwayReason;
149     bool autoAwayReasonEnabled;
150     bool detachAwayEnabled;
151     QString detachAwayReason;
152     bool detchAwayReasonEnabled;
153     QString ident;
154     QString kickReason;
155     QString partReason;
156     QString quitReason;
157     QByteArray sslCert;
158     QByteArray sslKey;
159   };
160
161   struct IdentityNickMO {
162     int nickid;
163     IdentityId identityId;
164     QString nick;
165   };
166
167   struct NetworkMO {
168     NetworkId networkid;
169     UserId userid;
170     QString networkname;
171     IdentityId identityid;
172     QString encodingcodec;
173     QString decodingcodec;
174     QString servercodec;
175     bool userandomserver;
176     QString perform;
177     bool useautoidentify;
178     QString autoidentifyservice;
179     QString autoidentifypassword;
180     bool useautoreconnect;
181     int autoreconnectinterval;
182     int autoreconnectretries;
183     bool unlimitedconnectretries;
184     bool rejoinchannels;
185     bool connected;
186     QString usermode;
187     QString awaymessage;
188     QString attachperform;
189     QString detachperform;
190   };
191
192   struct BufferMO {
193     BufferId bufferid;
194     UserId userid;
195     int groupid;
196     NetworkId networkid;
197     QString buffername;
198     QString buffercname;
199     int buffertype;
200     int lastseenmsgid;
201     int markerlinemsgid;
202     QString key;
203     bool joined;
204   };
205
206   struct BacklogMO {
207     MsgId messageid;
208     QDateTime time; // has to be in UTC!
209     BufferId bufferid;
210     int type;
211     int flags;
212     int senderid;
213     QString message;
214   };
215
216   struct IrcServerMO {
217     int serverid;
218     UserId userid;
219     NetworkId networkid;
220     QString hostname;
221     int port;
222     QString password;
223     bool ssl;
224     int sslversion;
225     bool useproxy;
226     int proxytype;
227     QString proxyhost;
228     int proxyport;
229     QString proxyuser;
230     QString proxypass;
231   };
232
233   struct UserSettingMO {
234     UserId userid;
235     QString settingname;
236     QByteArray settingvalue;
237   };
238
239   enum MigrationObject {
240     QuasselUser,
241     Sender,
242     Identity,
243     IdentityNick,
244     Network,
245     Buffer,
246     Backlog,
247     IrcServer,
248     UserSetting
249   };
250
251   AbstractSqlMigrator();
252   virtual ~AbstractSqlMigrator() {}
253
254   static QString migrationObject(MigrationObject moType);
255
256 protected:
257   void newQuery(const QString &query, QSqlDatabase db);
258   virtual void resetQuery();
259   virtual bool prepareQuery(MigrationObject mo) = 0;
260   bool exec();
261   inline bool next() { return _query->next(); }
262   inline QVariant value(int index) { return _query->value(index); }
263   inline void bindValue(const QString &placeholder, const QVariant &val) { _query->bindValue(placeholder, val); }
264   inline void bindValue(int pos, const QVariant &val) { _query->bindValue(pos, val); }
265
266   inline QSqlError lastError() { return _query ? _query->lastError() : QSqlError(); }
267   void dumpStatus();
268   inline QString executedQuery() { return _query ? _query->executedQuery() : QString(); }
269   inline QVariantList boundValues();
270
271   virtual bool transaction() = 0;
272   virtual void rollback() = 0;
273   virtual bool commit() = 0;
274
275 private:
276   QSqlQuery *_query;
277 };
278
279 class AbstractSqlMigrationReader : public AbstractSqlMigrator {
280 public:
281   AbstractSqlMigrationReader();
282
283   virtual bool readMo(QuasselUserMO &user) = 0;
284   virtual bool readMo(IdentityMO &identity) = 0;
285   virtual bool readMo(IdentityNickMO &identityNick) = 0;
286   virtual bool readMo(NetworkMO &network) = 0;
287   virtual bool readMo(BufferMO &buffer) = 0;
288   virtual bool readMo(SenderMO &sender) = 0;
289   virtual bool readMo(BacklogMO &backlog) = 0;
290   virtual bool readMo(IrcServerMO &ircserver) = 0;
291   virtual bool readMo(UserSettingMO &userSetting) = 0;
292
293   bool migrateTo(AbstractSqlMigrationWriter *writer);
294
295 private:
296   void abortMigration(const QString &errorMsg = QString());
297   bool finalizeMigration();
298
299   template<typename T> bool transferMo(MigrationObject moType, T &mo);
300
301   AbstractSqlMigrationWriter *_writer;
302 };
303
304 class AbstractSqlMigrationWriter : public AbstractSqlMigrator {
305 public:
306   virtual bool writeMo(const QuasselUserMO &user) = 0;
307   virtual bool writeMo(const IdentityMO &identity) = 0;
308   virtual bool writeMo(const IdentityNickMO &identityNick) = 0;
309   virtual bool writeMo(const NetworkMO &network) = 0;
310   virtual bool writeMo(const BufferMO &buffer) = 0;
311   virtual bool writeMo(const SenderMO &sender) = 0;
312   virtual bool writeMo(const BacklogMO &backlog) = 0;
313   virtual bool writeMo(const IrcServerMO &ircserver) = 0;
314   virtual bool writeMo(const UserSettingMO &userSetting) = 0;
315
316   inline bool migrateFrom(AbstractSqlMigrationReader *reader) { return reader->migrateTo(this); }
317
318   // called after migration process
319   virtual inline bool postProcess() { return true; }
320   friend class AbstractSqlMigrationReader;
321 };
322
323 #endif