1 /***************************************************************************
2 * Copyright (C) 2005-2020 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>
36 class AbstractSqlMigrationReader;
37 class AbstractSqlMigrationWriter;
39 class AbstractSqlStorage : public Storage
44 AbstractSqlStorage(QObject* parent = nullptr);
45 ~AbstractSqlStorage() override;
47 virtual std::unique_ptr<AbstractSqlMigrationReader> createMigrationReader() { return {}; }
48 virtual std::unique_ptr<AbstractSqlMigrationWriter> createMigrationWriter() { return {}; }
51 * An SQL query with associated resource filename
53 struct SqlQueryResource {
54 QString queryString; ///< SQL query string
55 QString queryFilename; ///< Path to the resource file providing this query
57 SqlQueryResource(const QString& queryString, const QString& queryFilename)
58 : queryString(std::move(queryString)),
59 queryFilename(std::move(queryFilename)) {}
63 State init(const QVariantMap& settings = QVariantMap(),
64 const QProcessEnvironment& environment = {},
65 bool loadFromEnvironment = false) override;
66 bool setup(const QVariantMap& settings = QVariantMap(),
67 const QProcessEnvironment& environment = {},
68 bool loadFromEnvironment = false) override;
71 inline void sync() override{};
76 * Fetch an SQL query string by name and optional schema version
78 * Loads the named SQL query from the built-in SQL resource collection, returning it as a
79 * string. If a version is specified, it'll be loaded from the schema version-specific folder
82 * @see schemaVersion()
84 * @param[in] queryName File name of the SQL query, minus the .sql extension
87 * SQL schema version; if 0, fetches from current version, otherwise loads from the specified
88 * schema version instead of the current schema files.
90 * @return String with the requested SQL query, ready for parameter substitution
92 QString queryString(const QString& queryName, int version = 0);
95 * Gets the collection of SQL setup queries and filenames to create a new database
97 * @return List of SQL query strings and filenames
99 std::vector<SqlQueryResource> setupQueries();
102 * Gets the collection of SQL upgrade queries and filenames for a given schema version
104 * @param ver SQL schema version
105 * @return List of SQL query strings and filenames
107 std::vector<SqlQueryResource> upgradeQueries(int ver);
110 bool watchQuery(QSqlQuery& query);
113 virtual int installedSchemaVersion() { return -1; };
116 * Update the stored schema version number, optionally clearing the record of mid-schema steps
118 * @param newVersion New schema version number
119 * @param clearUpgradeStep If true, clear the record of any in-progress schema upgrades
122 virtual bool updateSchemaVersion(int newVersion, bool clearUpgradeStep = true) = 0;
124 virtual bool setupSchemaVersion(int version) = 0;
127 * Gets the last successful schema upgrade step, or an empty string if no upgrade is in progress
129 * @return Filename of last successful schema upgrade query, or empty string if not upgrading
131 virtual QString schemaVersionUpgradeStep();
134 * Sets the last successful schema upgrade step
136 * @param upgradeQuery The filename of the last successful schema upgrade query
137 * @return True if successfully set, otherwise false
139 virtual bool setSchemaVersionUpgradeStep(QString upgradeQuery) = 0;
141 virtual void setConnectionProperties(const QVariantMap& properties, const QProcessEnvironment& environment, bool loadFromEnvironment) = 0;
142 virtual QString driverName() = 0;
143 inline virtual QString hostName() { return QString(); }
144 inline virtual int port() { return -1; }
145 virtual QString databaseName() = 0;
146 inline virtual QString userName() { return QString(); }
147 inline virtual QString password() { return QString(); }
149 //! Initialize db specific features on connect
150 /** This is called every time a connection to a specific SQL backend is established
151 * the default implementation does nothing.
153 * When reimplementing this method, don't use logDB() inside this function as
154 * this would cause as we're just about to initialize that DB connection.
156 inline virtual bool initDbSession(QSqlDatabase& /* db */) { return true; }
159 void connectionDestroyed();
162 void addConnectionToPool();
163 void dbConnect(QSqlDatabase& db);
165 int _schemaVersion{0};
168 static int _nextConnectionId;
169 QMutex _connectionPoolMutex;
170 // we let a Connection Object manage each actual db connection
171 // those objects reside in the thread the connection belongs to
172 // which allows us thread safe termination of a connection
174 QHash<QThread*, Connection*> _connectionPool;
183 friend uint qHash(const SenderData& key);
184 friend bool operator==(const SenderData& a, const SenderData& b);
187 // ========================================
188 // AbstractSqlStorage::Connection
189 // ========================================
190 class AbstractSqlStorage::Connection : public QObject
195 Connection(const QString& name, QObject* parent = nullptr);
196 ~Connection() override;
198 inline QLatin1String name() const { return QLatin1String(_name); }
204 // ========================================
205 // AbstractSqlMigrator
206 // ========================================
207 class AbstractSqlMigrator
217 QString authenticator;
232 QString identityname;
235 bool awayNickEnabled;
237 bool awayReasonEnabled;
238 bool autoAwayEnabled;
240 QString autoAwayReason;
241 bool autoAwayReasonEnabled;
242 bool detachAwayEnabled;
243 QString detachAwayReason;
244 bool detachAwayReasonEnabled;
253 struct IdentityNickMO
256 IdentityId identityId;
265 QString autoidentifyservice;
266 QString autoidentifypassword;
268 QString saslpassword;
270 QString encodingcodec;
271 QString decodingcodec;
274 QString attachperform;
275 QString detachperform;
278 IdentityId identityid;
279 int messagerateburstsize;
280 int messageratedelay;
281 int autoreconnectinterval;
282 int autoreconnectretries;
284 bool userandomserver;
285 bool useautoidentify;
287 bool useautoreconnect;
288 bool unlimitedconnectretries;
289 bool usecustommessagerate;
290 bool unlimitedmessagerate;
304 qint64 lastseenmsgid;
305 qint64 markerlinemsgid;
316 QDateTime time; // has to be in UTC!
321 QString senderprefixes;
334 bool sslverify; /// If true, validate SSL certificates
348 QByteArray settingvalue;
371 virtual ~AbstractSqlMigrator() = default;
373 static QString migrationObject(MigrationObject moType);
376 void newQuery(const QString& query, QSqlDatabase db);
377 virtual void resetQuery();
378 virtual bool prepareQuery(MigrationObject mo) = 0;
380 inline bool next() { return _query->next(); }
381 inline QVariant value(int index) { return _query->value(index); }
382 inline void bindValue(const QString& placeholder, const QVariant& val) { _query->bindValue(placeholder, val); }
383 inline void bindValue(int pos, const QVariant& val) { _query->bindValue(pos, val); }
385 inline QSqlError lastError() { return _query ? _query->lastError() : QSqlError(); }
387 inline QString executedQuery() { return _query ? _query->executedQuery() : QString(); }
388 inline QVariantList boundValues();
390 virtual bool transaction() = 0;
391 virtual void rollback() = 0;
392 virtual bool commit() = 0;
395 QSqlQuery* _query{nullptr};
398 class AbstractSqlMigrationReader : public AbstractSqlMigrator
401 AbstractSqlMigrationReader();
403 virtual bool readMo(QuasselUserMO& user) = 0;
404 virtual bool readMo(IdentityMO& identity) = 0;
405 virtual bool readMo(IdentityNickMO& identityNick) = 0;
406 virtual bool readMo(NetworkMO& network) = 0;
407 virtual bool readMo(BufferMO& buffer) = 0;
408 virtual bool readMo(SenderMO& sender) = 0;
409 virtual bool readMo(BacklogMO& backlog) = 0;
410 virtual bool readMo(IrcServerMO& ircserver) = 0;
411 virtual bool readMo(UserSettingMO& userSetting) = 0;
412 virtual bool readMo(CoreStateMO& coreState) = 0;
414 bool migrateTo(AbstractSqlMigrationWriter* writer);
417 void abortMigration(const QString& errorMsg = QString());
418 bool finalizeMigration();
421 bool transferMo(MigrationObject moType, T& mo);
423 AbstractSqlMigrationWriter* _writer{nullptr};
426 class AbstractSqlMigrationWriter : public AbstractSqlMigrator
429 virtual bool writeMo(const QuasselUserMO& user) = 0;
430 virtual bool writeMo(const IdentityMO& identity) = 0;
431 virtual bool writeMo(const IdentityNickMO& identityNick) = 0;
432 virtual bool writeMo(const NetworkMO& network) = 0;
433 virtual bool writeMo(const BufferMO& buffer) = 0;
434 virtual bool writeMo(const SenderMO& sender) = 0;
435 virtual bool writeMo(const BacklogMO& backlog) = 0;
436 virtual bool writeMo(const IrcServerMO& ircserver) = 0;
437 virtual bool writeMo(const UserSettingMO& userSetting) = 0;
438 virtual bool writeMo(const CoreStateMO& coreState) = 0;
440 inline bool migrateFrom(AbstractSqlMigrationReader* reader) { return reader->migrateTo(this); }
442 // called after migration process
443 virtual inline bool postProcess() { return true; }
444 friend class AbstractSqlMigrationReader;