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 IdentityId identityid;
212 QString encodingcodec;
213 QString decodingcodec;
215 bool userandomserver;
217 bool useautoidentify;
218 QString autoidentifyservice;
219 QString autoidentifypassword;
220 bool useautoreconnect;
221 int autoreconnectinterval;
222 int autoreconnectretries;
223 bool unlimitedconnectretries;
225 // Custom rate limiting
226 bool usecustommessagerate;
227 int messagerateburstsize;
228 int messageratedelay;
229 bool unlimitedmessagerate;
234 QString attachperform;
235 QString detachperform;
238 QString saslpassword;
250 qint64 lastseenmsgid;
251 qint64 markerlinemsgid;
261 QDateTime time; // has to be in UTC!
266 QString senderprefixes;
278 bool sslverify; /// If true, validate SSL certificates
288 struct UserSettingMO {
291 QByteArray settingvalue;
299 enum MigrationObject {
312 AbstractSqlMigrator();
313 virtual ~AbstractSqlMigrator() {}
315 static QString migrationObject(MigrationObject moType);
318 void newQuery(const QString &query, QSqlDatabase db);
319 virtual void resetQuery();
320 virtual bool prepareQuery(MigrationObject mo) = 0;
322 inline bool next() { return _query->next(); }
323 inline QVariant value(int index) { return _query->value(index); }
324 inline void bindValue(const QString &placeholder, const QVariant &val) { _query->bindValue(placeholder, val); }
325 inline void bindValue(int pos, const QVariant &val) { _query->bindValue(pos, val); }
327 inline QSqlError lastError() { return _query ? _query->lastError() : QSqlError(); }
329 inline QString executedQuery() { return _query ? _query->executedQuery() : QString(); }
330 inline QVariantList boundValues();
332 virtual bool transaction() = 0;
333 virtual void rollback() = 0;
334 virtual bool commit() = 0;
341 class AbstractSqlMigrationReader : public AbstractSqlMigrator
344 AbstractSqlMigrationReader();
346 virtual bool readMo(QuasselUserMO &user) = 0;
347 virtual bool readMo(IdentityMO &identity) = 0;
348 virtual bool readMo(IdentityNickMO &identityNick) = 0;
349 virtual bool readMo(NetworkMO &network) = 0;
350 virtual bool readMo(BufferMO &buffer) = 0;
351 virtual bool readMo(SenderMO &sender) = 0;
352 virtual bool readMo(BacklogMO &backlog) = 0;
353 virtual bool readMo(IrcServerMO &ircserver) = 0;
354 virtual bool readMo(UserSettingMO &userSetting) = 0;
355 virtual bool readMo(CoreStateMO &coreState) = 0;
357 bool migrateTo(AbstractSqlMigrationWriter *writer);
360 void abortMigration(const QString &errorMsg = QString());
361 bool finalizeMigration();
363 template<typename T> bool transferMo(MigrationObject moType, T &mo);
365 AbstractSqlMigrationWriter *_writer;
369 class AbstractSqlMigrationWriter : public AbstractSqlMigrator
372 virtual bool writeMo(const QuasselUserMO &user) = 0;
373 virtual bool writeMo(const IdentityMO &identity) = 0;
374 virtual bool writeMo(const IdentityNickMO &identityNick) = 0;
375 virtual bool writeMo(const NetworkMO &network) = 0;
376 virtual bool writeMo(const BufferMO &buffer) = 0;
377 virtual bool writeMo(const SenderMO &sender) = 0;
378 virtual bool writeMo(const BacklogMO &backlog) = 0;
379 virtual bool writeMo(const IrcServerMO &ircserver) = 0;
380 virtual bool writeMo(const UserSettingMO &userSetting) = 0;
381 virtual bool writeMo(const CoreStateMO &coreState) = 0;
383 inline bool migrateFrom(AbstractSqlMigrationReader *reader) { return reader->migrateTo(this); }
385 // called after migration process
386 virtual inline bool postProcess() { return true; }
387 friend class AbstractSqlMigrationReader;