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 ***************************************************************************/
25 #include <QSqlDatabase>
31 class AbstractSqlMigrationReader;
32 class AbstractSqlMigrationWriter;
34 class AbstractSqlStorage : public Storage
39 AbstractSqlStorage(QObject* parent = nullptr);
40 ~AbstractSqlStorage() override;
42 virtual std::unique_ptr<AbstractSqlMigrationReader> createMigrationReader() { return {}; }
43 virtual std::unique_ptr<AbstractSqlMigrationWriter> createMigrationWriter() { return {}; }
46 State init(const QVariantMap& settings = QVariantMap(),
47 const QProcessEnvironment& environment = {},
48 bool loadFromEnvironment = false) override;
49 bool setup(const QVariantMap& settings = QVariantMap(),
50 const QProcessEnvironment& environment = {},
51 bool loadFromEnvironment = false) override;
54 inline void sync() override{};
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, const QProcessEnvironment& environment, bool loadFromEnvironment) = 0;
90 virtual QString driverName() = 0;
91 inline virtual QString hostName() { return QString(); }
92 inline virtual int port() { return -1; }
93 virtual QString databaseName() = 0;
94 inline virtual QString userName() { return QString(); }
95 inline virtual QString password() { return QString(); }
97 //! Initialize db specific features on connect
98 /** This is called every time a connection to a specific SQL backend is established
99 * the default implementation does nothing.
101 * When reimplementing this method, don't use logDB() inside this function as
102 * this would cause as we're just about to initialize that DB connection.
104 inline virtual bool initDbSession(QSqlDatabase& /* db */) { return true; }
107 void connectionDestroyed();
110 void addConnectionToPool();
111 void dbConnect(QSqlDatabase& db);
113 int _schemaVersion{0};
116 static int _nextConnectionId;
117 QMutex _connectionPoolMutex;
118 // we let a Connection Object manage each actual db connection
119 // those objects reside in the thread the connection belongs to
120 // which allows us thread safe termination of a connection
122 QHash<QThread*, Connection*> _connectionPool;
131 friend uint qHash(const SenderData& key);
132 friend bool operator==(const SenderData& a, const SenderData& b);
135 // ========================================
136 // AbstractSqlStorage::Connection
137 // ========================================
138 class AbstractSqlStorage::Connection : public QObject
143 Connection(const QString& name, QObject* parent = nullptr);
144 ~Connection() override;
146 inline QLatin1String name() const { return QLatin1String(_name); }
152 // ========================================
153 // AbstractSqlMigrator
154 // ========================================
155 class AbstractSqlMigrator
165 QString authenticator;
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
204 IdentityId identityId;
213 QString autoidentifyservice;
214 QString autoidentifypassword;
216 QString saslpassword;
218 QString encodingcodec;
219 QString decodingcodec;
222 QString attachperform;
223 QString detachperform;
225 IdentityId identityid;
226 int messagerateburstsize;
227 int messageratedelay;
228 int autoreconnectinterval;
229 int autoreconnectretries;
231 bool userandomserver;
232 bool useautoidentify;
234 bool useautoreconnect;
235 bool unlimitedconnectretries;
236 bool usecustommessagerate;
237 bool unlimitedmessagerate;
251 qint64 lastseenmsgid;
252 qint64 markerlinemsgid;
263 QDateTime time; // has to be in UTC!
268 QString senderprefixes;
281 bool sslverify; /// If true, validate SSL certificates
295 QByteArray settingvalue;
318 virtual ~AbstractSqlMigrator() = default;
320 static QString migrationObject(MigrationObject moType);
323 void newQuery(const QString& query, QSqlDatabase db);
324 virtual void resetQuery();
325 virtual bool prepareQuery(MigrationObject mo) = 0;
327 inline bool next() { return _query->next(); }
328 inline QVariant value(int index) { return _query->value(index); }
329 inline void bindValue(const QString& placeholder, const QVariant& val) { _query->bindValue(placeholder, val); }
330 inline void bindValue(int pos, const QVariant& val) { _query->bindValue(pos, val); }
332 inline QSqlError lastError() { return _query ? _query->lastError() : QSqlError(); }
334 inline QString executedQuery() { return _query ? _query->executedQuery() : QString(); }
335 inline QVariantList boundValues();
337 virtual bool transaction() = 0;
338 virtual void rollback() = 0;
339 virtual bool commit() = 0;
342 QSqlQuery* _query{nullptr};
345 class AbstractSqlMigrationReader : public AbstractSqlMigrator
348 AbstractSqlMigrationReader();
350 virtual bool readMo(QuasselUserMO& user) = 0;
351 virtual bool readMo(IdentityMO& identity) = 0;
352 virtual bool readMo(IdentityNickMO& identityNick) = 0;
353 virtual bool readMo(NetworkMO& network) = 0;
354 virtual bool readMo(BufferMO& buffer) = 0;
355 virtual bool readMo(SenderMO& sender) = 0;
356 virtual bool readMo(BacklogMO& backlog) = 0;
357 virtual bool readMo(IrcServerMO& ircserver) = 0;
358 virtual bool readMo(UserSettingMO& userSetting) = 0;
359 virtual bool readMo(CoreStateMO& coreState) = 0;
361 bool migrateTo(AbstractSqlMigrationWriter* writer);
364 void abortMigration(const QString& errorMsg = QString());
365 bool finalizeMigration();
368 bool transferMo(MigrationObject moType, T& mo);
370 AbstractSqlMigrationWriter* _writer{nullptr};
373 class AbstractSqlMigrationWriter : public AbstractSqlMigrator
376 virtual bool writeMo(const QuasselUserMO& user) = 0;
377 virtual bool writeMo(const IdentityMO& identity) = 0;
378 virtual bool writeMo(const IdentityNickMO& identityNick) = 0;
379 virtual bool writeMo(const NetworkMO& network) = 0;
380 virtual bool writeMo(const BufferMO& buffer) = 0;
381 virtual bool writeMo(const SenderMO& sender) = 0;
382 virtual bool writeMo(const BacklogMO& backlog) = 0;
383 virtual bool writeMo(const IrcServerMO& ircserver) = 0;
384 virtual bool writeMo(const UserSettingMO& userSetting) = 0;
385 virtual bool writeMo(const CoreStateMO& coreState) = 0;
387 inline bool migrateFrom(AbstractSqlMigrationReader* reader) { return reader->migrateTo(this); }
389 // called after migration process
390 virtual inline bool postProcess() { return true; }
391 friend class AbstractSqlMigrationReader;