1 /***************************************************************************
2 * Copyright (C) 2005-2018 by the Quassel Project *
3 * devel@quassel-irc.org *
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. *
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. *
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 ***************************************************************************/
27 #include <QSqlDatabase>
31 class AbstractSqlMigrationReader;
32 class AbstractSqlMigrationWriter;
34 class AbstractSqlStorage : public Storage
39 AbstractSqlStorage(QObject *parent = 0);
40 virtual ~AbstractSqlStorage();
42 virtual std::unique_ptr<AbstractSqlMigrationReader> createMigrationReader() { return {}; }
43 virtual std::unique_ptr<AbstractSqlMigrationWriter> createMigrationWriter() { return {}; }
46 virtual State init(const QVariantMap &settings = QVariantMap(),
47 const QProcessEnvironment &environment = {},
48 bool loadFromEnvironment = false);
49 virtual bool setup(const QVariantMap &settings = QVariantMap(),
50 const QProcessEnvironment &environment = {},
51 bool loadFromEnvironment = false);
54 inline virtual void sync() {};
59 * Fetch an SQL query string by name and optional schema version
61 * Loads the named SQL query from the built-in SQL resource collection, returning it as a
62 * string. If a version is specified, it'll be loaded from the schema version-specific folder
65 * @see schemaVersion()
67 * @param[in] queryName File name of the SQL query, minus the .sql extension
70 * SQL schema version; if 0, fetches from current version, otherwise loads from the specified
71 * schema version instead of the current schema files.
73 * @return String with the requested SQL query, ready for parameter substitution
75 QString queryString(const QString &queryName, int version = 0);
77 QStringList setupQueries();
79 QStringList upgradeQueries(int ver);
82 bool watchQuery(QSqlQuery &query);
85 virtual int installedSchemaVersion() { return -1; };
86 virtual bool updateSchemaVersion(int newVersion) = 0;
87 virtual bool setupSchemaVersion(int version) = 0;
89 virtual void setConnectionProperties(const QVariantMap &properties,
90 const QProcessEnvironment &environment,
91 bool loadFromEnvironment) = 0;
92 virtual QString driverName() = 0;
93 inline virtual QString hostName() { return QString(); }
94 inline virtual int port() { return -1; }
95 virtual QString databaseName() = 0;
96 inline virtual QString userName() { return QString(); }
97 inline virtual QString password() { return QString(); }
99 //! Initialize db specific features on connect
100 /** This is called every time a connection to a specific SQL backend is established
101 * the default implementation does nothing.
103 * When reimplementing this method, don't use logDB() inside this function as
104 * this would cause as we're just about to initialize that DB connection.
106 inline virtual bool initDbSession(QSqlDatabase & /* db */) { return true; }
109 void connectionDestroyed();
112 void addConnectionToPool();
113 void dbConnect(QSqlDatabase &db);
118 static int _nextConnectionId;
119 QMutex _connectionPoolMutex;
120 // we let a Connection Object manage each actual db connection
121 // those objects reside in the thread the connection belongs to
122 // which allows us thread safe termination of a connection
124 QHash<QThread *, Connection *> _connectionPool;
132 friend uint qHash(const SenderData &key);
133 friend bool operator==(const SenderData &a, const SenderData &b);
136 // ========================================
137 // AbstractSqlStorage::Connection
138 // ========================================
139 class AbstractSqlStorage::Connection : public QObject
144 Connection(const QString &name, QObject *parent = 0);
147 inline QLatin1String name() const { return QLatin1String(_name); }
154 // ========================================
155 // AbstractSqlMigrator
156 // ========================================
157 class AbstractSqlMigrator
161 struct QuasselUserMO {
166 QString authenticator;
174 SenderMO() : senderId(0) {}
180 QString identityname;
183 bool awayNickEnabled;
185 bool awayReasonEnabled;
186 bool autoAwayEnabled;
188 QString autoAwayReason;
189 bool autoAwayReasonEnabled;
190 bool detachAwayEnabled;
191 QString detachAwayReason;
192 bool detachAwayReasonEnabled;
201 struct IdentityNickMO {
203 IdentityId identityId;
211 QString autoidentifyservice;
212 QString autoidentifypassword;
214 QString saslpassword;
216 QString encodingcodec;
217 QString decodingcodec;
220 QString attachperform;
221 QString detachperform;
223 IdentityId identityid;
224 int messagerateburstsize;
225 int messageratedelay;
226 int autoreconnectinterval;
227 int autoreconnectretries;
229 bool userandomserver;
230 bool useautoidentify;
232 bool useautoreconnect;
233 bool unlimitedconnectretries;
234 bool usecustommessagerate;
235 bool unlimitedmessagerate;
248 qint64 lastseenmsgid;
249 qint64 markerlinemsgid;
259 QDateTime time; // has to be in UTC!
264 QString senderprefixes;
276 bool sslverify; /// If true, validate SSL certificates
286 struct UserSettingMO {
289 QByteArray settingvalue;
297 enum MigrationObject {
310 AbstractSqlMigrator();
311 virtual ~AbstractSqlMigrator() {}
313 static QString migrationObject(MigrationObject moType);
316 void newQuery(const QString &query, QSqlDatabase db);
317 virtual void resetQuery();
318 virtual bool prepareQuery(MigrationObject mo) = 0;
320 inline bool next() { return _query->next(); }
321 inline QVariant value(int index) { return _query->value(index); }
322 inline void bindValue(const QString &placeholder, const QVariant &val) { _query->bindValue(placeholder, val); }
323 inline void bindValue(int pos, const QVariant &val) { _query->bindValue(pos, val); }
325 inline QSqlError lastError() { return _query ? _query->lastError() : QSqlError(); }
327 inline QString executedQuery() { return _query ? _query->executedQuery() : QString(); }
328 inline QVariantList boundValues();
330 virtual bool transaction() = 0;
331 virtual void rollback() = 0;
332 virtual bool commit() = 0;
339 class AbstractSqlMigrationReader : public AbstractSqlMigrator
342 AbstractSqlMigrationReader();
344 virtual bool readMo(QuasselUserMO &user) = 0;
345 virtual bool readMo(IdentityMO &identity) = 0;
346 virtual bool readMo(IdentityNickMO &identityNick) = 0;
347 virtual bool readMo(NetworkMO &network) = 0;
348 virtual bool readMo(BufferMO &buffer) = 0;
349 virtual bool readMo(SenderMO &sender) = 0;
350 virtual bool readMo(BacklogMO &backlog) = 0;
351 virtual bool readMo(IrcServerMO &ircserver) = 0;
352 virtual bool readMo(UserSettingMO &userSetting) = 0;
353 virtual bool readMo(CoreStateMO &coreState) = 0;
355 bool migrateTo(AbstractSqlMigrationWriter *writer);
358 void abortMigration(const QString &errorMsg = QString());
359 bool finalizeMigration();
361 template<typename T> bool transferMo(MigrationObject moType, T &mo);
363 AbstractSqlMigrationWriter *_writer;
367 class AbstractSqlMigrationWriter : public AbstractSqlMigrator
370 virtual bool writeMo(const QuasselUserMO &user) = 0;
371 virtual bool writeMo(const IdentityMO &identity) = 0;
372 virtual bool writeMo(const IdentityNickMO &identityNick) = 0;
373 virtual bool writeMo(const NetworkMO &network) = 0;
374 virtual bool writeMo(const BufferMO &buffer) = 0;
375 virtual bool writeMo(const SenderMO &sender) = 0;
376 virtual bool writeMo(const BacklogMO &backlog) = 0;
377 virtual bool writeMo(const IrcServerMO &ircserver) = 0;
378 virtual bool writeMo(const UserSettingMO &userSetting) = 0;
379 virtual bool writeMo(const CoreStateMO &coreState) = 0;
381 inline bool migrateFrom(AbstractSqlMigrationReader *reader) { return reader->migrateTo(this); }
383 // called after migration process
384 virtual inline bool postProcess() { return true; }
385 friend class AbstractSqlMigrationReader;