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