1 /***************************************************************************
2 * Copyright (C) 2005-2019 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 ***************************************************************************/
28 #include <QSqlDatabase>
32 class AbstractSqlMigrationReader;
33 class AbstractSqlMigrationWriter;
35 class AbstractSqlStorage : public Storage
40 AbstractSqlStorage(QObject *parent = 0);
41 virtual ~AbstractSqlStorage();
43 virtual std::unique_ptr<AbstractSqlMigrationReader> createMigrationReader() { return {}; }
44 virtual std::unique_ptr<AbstractSqlMigrationWriter> createMigrationWriter() { return {}; }
47 * An SQL query with associated resource filename
49 struct SqlQueryResource {
50 QString queryString; ///< SQL query string
51 QString queryFilename; ///< Path to the resource file providing this query
53 SqlQueryResource(const QString& queryString, const QString& queryFilename)
54 : queryString(std::move(queryString)),
55 queryFilename(std::move(queryFilename)) {}
59 virtual State init(const QVariantMap &settings = QVariantMap(),
60 const QProcessEnvironment &environment = {},
61 bool loadFromEnvironment = false);
62 virtual bool setup(const QVariantMap &settings = QVariantMap(),
63 const QProcessEnvironment &environment = {},
64 bool loadFromEnvironment = false);
67 inline virtual void sync() {};
72 * Fetch an SQL query string by name and optional schema version
74 * Loads the named SQL query from the built-in SQL resource collection, returning it as a
75 * string. If a version is specified, it'll be loaded from the schema version-specific folder
78 * @see schemaVersion()
80 * @param[in] queryName File name of the SQL query, minus the .sql extension
83 * SQL schema version; if 0, fetches from current version, otherwise loads from the specified
84 * schema version instead of the current schema files.
86 * @return String with the requested SQL query, ready for parameter substitution
88 QString queryString(const QString &queryName, int version = 0);
90 QStringList setupQueries();
93 * Gets the collection of SQL upgrade queries and filenames for a given schema version
95 * @param ver SQL schema version
96 * @return List of SQL query strings and filenames
98 QList<SqlQueryResource> upgradeQueries(int ver);
101 bool watchQuery(QSqlQuery &query);
104 virtual int installedSchemaVersion() { return -1; };
107 * Update the stored schema version number, optionally clearing the record of mid-schema steps
109 * @param newVersion New schema version number
110 * @param clearUpgradeStep If true, clear the record of any in-progress schema upgrades
113 virtual bool updateSchemaVersion(int newVersion, bool clearUpgradeStep = true) = 0;
115 virtual bool setupSchemaVersion(int version) = 0;
118 * Gets the last successful schema upgrade step, or an empty string if no upgrade is in progress
120 * @return Filename of last successful schema upgrade query, or empty string if not upgrading
122 virtual QString schemaVersionUpgradeStep();
125 * Sets the last successful schema upgrade step
127 * @param upgradeQuery The filename of the last successful schema upgrade query
128 * @return True if successfully set, otherwise false
130 virtual bool setSchemaVersionUpgradeStep(QString upgradeQuery) = 0;
131 virtual void setConnectionProperties(const QVariantMap &properties,
132 const QProcessEnvironment &environment,
133 bool loadFromEnvironment) = 0;
134 virtual QString driverName() = 0;
135 inline virtual QString hostName() { return QString(); }
136 inline virtual int port() { return -1; }
137 virtual QString databaseName() = 0;
138 inline virtual QString userName() { return QString(); }
139 inline virtual QString password() { return QString(); }
141 //! Initialize db specific features on connect
142 /** This is called every time a connection to a specific SQL backend is established
143 * the default implementation does nothing.
145 * When reimplementing this method, don't use logDB() inside this function as
146 * this would cause as we're just about to initialize that DB connection.
148 inline virtual bool initDbSession(QSqlDatabase & /* db */) { return true; }
151 void connectionDestroyed();
154 void addConnectionToPool();
155 void dbConnect(QSqlDatabase &db);
160 static int _nextConnectionId;
161 QMutex _connectionPoolMutex;
162 // we let a Connection Object manage each actual db connection
163 // those objects reside in the thread the connection belongs to
164 // which allows us thread safe termination of a connection
166 QHash<QThread *, Connection *> _connectionPool;
174 friend uint qHash(const SenderData &key);
175 friend bool operator==(const SenderData &a, const SenderData &b);
178 // ========================================
179 // AbstractSqlStorage::Connection
180 // ========================================
181 class AbstractSqlStorage::Connection : public QObject
186 Connection(const QString &name, QObject *parent = 0);
189 inline QLatin1String name() const { return QLatin1String(_name); }
196 // ========================================
197 // AbstractSqlMigrator
198 // ========================================
199 class AbstractSqlMigrator
203 struct QuasselUserMO {
208 QString authenticator;
216 SenderMO() : senderId(0) {}
222 QString identityname;
225 bool awayNickEnabled;
227 bool awayReasonEnabled;
228 bool autoAwayEnabled;
230 QString autoAwayReason;
231 bool autoAwayReasonEnabled;
232 bool detachAwayEnabled;
233 QString detachAwayReason;
234 bool detachAwayReasonEnabled;
243 struct IdentityNickMO {
245 IdentityId identityId;
253 QString autoidentifyservice;
254 QString autoidentifypassword;
256 QString saslpassword;
258 QString encodingcodec;
259 QString decodingcodec;
262 QString attachperform;
263 QString detachperform;
265 IdentityId identityid;
266 int messagerateburstsize;
267 int messageratedelay;
268 int autoreconnectinterval;
269 int autoreconnectretries;
271 bool userandomserver;
272 bool useautoidentify;
274 bool useautoreconnect;
275 bool unlimitedconnectretries;
276 bool usecustommessagerate;
277 bool unlimitedmessagerate;
290 qint64 lastseenmsgid;
291 qint64 markerlinemsgid;
301 QDateTime time; // has to be in UTC!
306 QString senderprefixes;
318 bool sslverify; /// If true, validate SSL certificates
328 struct UserSettingMO {
331 QByteArray settingvalue;
339 enum MigrationObject {
352 AbstractSqlMigrator();
353 virtual ~AbstractSqlMigrator() {}
355 static QString migrationObject(MigrationObject moType);
358 void newQuery(const QString &query, QSqlDatabase db);
359 virtual void resetQuery();
360 virtual bool prepareQuery(MigrationObject mo) = 0;
362 inline bool next() { return _query->next(); }
363 inline QVariant value(int index) { return _query->value(index); }
364 inline void bindValue(const QString &placeholder, const QVariant &val) { _query->bindValue(placeholder, val); }
365 inline void bindValue(int pos, const QVariant &val) { _query->bindValue(pos, val); }
367 inline QSqlError lastError() { return _query ? _query->lastError() : QSqlError(); }
369 inline QString executedQuery() { return _query ? _query->executedQuery() : QString(); }
370 inline QVariantList boundValues();
372 virtual bool transaction() = 0;
373 virtual void rollback() = 0;
374 virtual bool commit() = 0;
381 class AbstractSqlMigrationReader : public AbstractSqlMigrator
384 AbstractSqlMigrationReader();
386 virtual bool readMo(QuasselUserMO &user) = 0;
387 virtual bool readMo(IdentityMO &identity) = 0;
388 virtual bool readMo(IdentityNickMO &identityNick) = 0;
389 virtual bool readMo(NetworkMO &network) = 0;
390 virtual bool readMo(BufferMO &buffer) = 0;
391 virtual bool readMo(SenderMO &sender) = 0;
392 virtual bool readMo(BacklogMO &backlog) = 0;
393 virtual bool readMo(IrcServerMO &ircserver) = 0;
394 virtual bool readMo(UserSettingMO &userSetting) = 0;
395 virtual bool readMo(CoreStateMO &coreState) = 0;
397 bool migrateTo(AbstractSqlMigrationWriter *writer);
400 void abortMigration(const QString &errorMsg = QString());
401 bool finalizeMigration();
403 template<typename T> bool transferMo(MigrationObject moType, T &mo);
405 AbstractSqlMigrationWriter *_writer;
409 class AbstractSqlMigrationWriter : public AbstractSqlMigrator
412 virtual bool writeMo(const QuasselUserMO &user) = 0;
413 virtual bool writeMo(const IdentityMO &identity) = 0;
414 virtual bool writeMo(const IdentityNickMO &identityNick) = 0;
415 virtual bool writeMo(const NetworkMO &network) = 0;
416 virtual bool writeMo(const BufferMO &buffer) = 0;
417 virtual bool writeMo(const SenderMO &sender) = 0;
418 virtual bool writeMo(const BacklogMO &backlog) = 0;
419 virtual bool writeMo(const IrcServerMO &ircserver) = 0;
420 virtual bool writeMo(const UserSettingMO &userSetting) = 0;
421 virtual bool writeMo(const CoreStateMO &coreState) = 0;
423 inline bool migrateFrom(AbstractSqlMigrationReader *reader) { return reader->migrateTo(this); }
425 // called after migration process
426 virtual inline bool postProcess() { return true; }
427 friend class AbstractSqlMigrationReader;