int connectionId = _nextConnectionId++;
- Connection *connection = new Connection(QLatin1String(QString("quassel_connection_%1").arg(connectionId).toLatin1()));
+ Connection *connection = new Connection(QLatin1String(QString("quassel_%1_con_%2").arg(driverName()).arg(connectionId).toLatin1()));
connection->moveToThread(currentThread);
connect(this, SIGNAL(destroyed()), connection, SLOT(deleteLater()));
connect(currentThread, SIGNAL(destroyed()), connection, SLOT(deleteLater()));
}
QSqlDatabase::removeDatabase(name());
}
+
+
+
+
+// ========================================
+// AbstractSqlMigrator
+// ========================================
+AbstractSqlMigrator::AbstractSqlMigrator()
+ : _query(0)
+{
+}
+
+void AbstractSqlMigrator::newQuery(const QString &query, QSqlDatabase db) {
+ Q_ASSERT(!_query);
+ _query = new QSqlQuery(db);
+ _query->prepare(query);
+}
+
+void AbstractSqlMigrator::resetQuery() {
+ delete _query;
+ _query = 0;
+}
+
+bool AbstractSqlMigrator::exec() {
+ Q_ASSERT(_query);
+ _query->exec();
+ return !_query->lastError().isValid();
+}
+
+QString AbstractSqlMigrator::migrationObject(MigrationObject moType) {
+ switch(moType) {
+ case QuasselUser:
+ return "QuasselUser";
+ case Sender:
+ return "Sender";
+ case Identity:
+ return "Identity";
+ case IdentityNick:
+ return "IdentityNick";
+ case Network:
+ return "Network";
+ case Buffer:
+ return "Buffer";
+ case Backlog:
+ return "Backlog";
+ case IrcServer:
+ return "IrcServer";
+ case UserSetting:
+ return "UserSetting";
+ };
+ return QString();
+}
+
+QVariantList AbstractSqlMigrator::boundValues() {
+ QVariantList values;
+ if(!_query)
+ return values;
+
+ int numValues = _query->boundValues().count();
+ for(int i = 0; i < numValues; i++) {
+ values << _query->boundValue(i);
+ }
+ return values;
+}
+
+void AbstractSqlMigrator::dumpStatus() {
+ qWarning() << " executed Query:";
+ qWarning() << qPrintable(executedQuery());
+ qWarning() << " bound Values:";
+ QList<QVariant> list = boundValues();
+ for (int i = 0; i < list.size(); ++i)
+ qWarning() << i << ": " << list.at(i).toString().toAscii().data();
+ qWarning() << " Error Number:" << lastError().number();
+ qWarning() << " Error Message:" << lastError().text();
+}
+
+
+// ========================================
+// AbstractSqlMigrationReader
+// ========================================
+AbstractSqlMigrationReader::AbstractSqlMigrationReader()
+ : AbstractSqlMigrator(),
+ _writer(0)
+{
+}
+
+bool AbstractSqlMigrationReader::migrateTo(AbstractSqlMigrationWriter *writer) {
+ if(!transaction()) {
+ qWarning() << "AbstractSqlMigrationReader::migrateTo(): unable to start reader stransaction!";
+ return false;
+ }
+ if(!writer->transaction()) {
+ qWarning() << "AbstractSqlMigrationReader::migrateTo(): unable to start writer stransaction!";
+ rollback(); // close the reader transaction;
+ return false;
+ }
+
+ _writer = writer;
+
+ // due to the incompatibility across Migration objects we can't run this in a loop... :/
+ QuasselUserMO quasselUserMo;
+ if(!transferMo(QuasselUser, quasselUserMo))
+ return false;
+
+ SenderMO senderMo;
+ if(!transferMo(Sender, senderMo))
+ return false;
+
+ IdentityMO identityMo;
+ if(!transferMo(Identity, identityMo))
+ return false;
+
+ IdentityNickMO identityNickMo;
+ if(!transferMo(IdentityNick, identityNickMo))
+ return false;
+
+ NetworkMO networkMo;
+ if(!transferMo(Network, networkMo))
+ return false;
+
+ BufferMO bufferMo;
+ if(!transferMo(Buffer, bufferMo))
+ return false;
+
+ BacklogMO backlogMo;
+ if(!transferMo(Backlog, backlogMo))
+ return false;
+
+ IrcServerMO ircServerMo;
+ if(!transferMo(IrcServer, ircServerMo))
+ return false;
+
+ UserSettingMO userSettingMo;
+ if(!transferMo(UserSetting, userSettingMo))
+ return false;
+
+ return finalizeMigration();
+}
+
+void AbstractSqlMigrationReader::abortMigration(const QString &errorMsg) {
+ qWarning() << "Migration Failed!";
+ if(!errorMsg.isNull()) {
+ qWarning() << qPrintable(errorMsg);
+ }
+ if(lastError().isValid()) {
+ qWarning() << "ReaderError:";
+ dumpStatus();
+ }
+
+
+ if(_writer->lastError().isValid()) {
+ qWarning() << "WriterError:";
+ _writer->dumpStatus();
+ }
+
+ rollback();
+ _writer->rollback();
+ _writer = 0;
+}
+
+bool AbstractSqlMigrationReader::finalizeMigration() {
+ resetQuery();
+ _writer->resetQuery();
+
+ commit();
+ if(!_writer->commit()) {
+ _writer = 0;
+ return false;
+ }
+ _writer = 0;
+ return true;
+}
+
+template<typename T>
+bool AbstractSqlMigrationReader::transferMo(MigrationObject moType, T &mo) {
+ resetQuery();
+ _writer->resetQuery();
+
+ if(!prepareQuery(moType)) {
+ abortMigration(QString("AbstractSqlMigrationReader::migrateTo(): unable to prepare reader query of type %1!").arg(AbstractSqlMigrator::migrationObject(moType)));
+ return false;
+ }
+ if(!_writer->prepareQuery(moType)) {
+ abortMigration(QString("AbstractSqlMigrationReader::migrateTo(): unable to prepare writer query of type %1!").arg(AbstractSqlMigrator::migrationObject(moType)));
+ return false;
+ }
+
+ qDebug() << qPrintable(QString("Transfering %1...").arg(AbstractSqlMigrator::migrationObject(moType)));
+ int i = 0;
+ QFile file;
+ file.open(stdout, QIODevice::WriteOnly);
+ while(readMo(mo)) {
+ if(!_writer->writeMo(mo)) {
+ abortMigration(QString("AbstractSqlMigrationReader::transferMo(): unable to transfer Migratable Object of type %1!").arg(AbstractSqlMigrator::migrationObject(moType)));
+ return false;
+ }
+ i++;
+ if(i % 1000 == 0) {
+ file.write("*");
+ file.flush();
+ }
+ }
+ if(i > 1000) {
+ file.write("\n");
+ file.flush();
+ }
+ qDebug() << "Done.";
+ return true;
+}
+
#include "storage.h"
#include <QSqlDatabase>
-
-class QSqlQuery;
+#include <QSqlQuery>
+#include <QSqlError>
class AbstractSqlStorage : public Storage {
Q_OBJECT
AbstractSqlStorage(QObject *parent = 0);
virtual ~AbstractSqlStorage();
-protected:
virtual State init(const QVariantMap &settings = QVariantMap());
+
+protected:
inline virtual void sync() {};
-
+
QSqlDatabase logDb();
-
+
QString queryString(const QString &queryName, int version);
inline QString queryString(const QString &queryName) { return queryString(queryName, 0); }
bool upgradeDb();
bool watchQuery(QSqlQuery &query);
-
+
int schemaVersion();
virtual int installedSchemaVersion() { return -1; };
virtual bool updateSchemaVersion(int newVersion) = 0;
public:
Connection(const QString &name, QObject *parent = 0);
~Connection();
-
+
inline QLatin1String name() const { return QLatin1String(_name); }
private:
QByteArray _name;
};
+
+// ========================================
+// AbstractSqlMigrator
+// ========================================
+class AbstractSqlMigrator {
+public:
+ // migration objects
+ struct QuasselUserMO {
+ UserId id;
+ QString username;
+ QString password;
+ };
+
+ struct SenderMO {
+ int senderId;
+ QString sender;
+ };
+
+ struct IdentityMO {
+ IdentityId id;
+ UserId userid;
+ QString identityname;
+ QString realname;
+ QString awayNick;
+ bool awayNickEnabled;
+ QString awayReason;
+ bool awayReasonEnabled;
+ bool autoAwayEnabled;
+ int autoAwayTime;
+ QString autoAwayReason;
+ bool autoAwayReasonEnabled;
+ bool detachAwayEnabled;
+ QString detachAwayReason;
+ bool detchAwayReasonEnabled;
+ QString ident;
+ QString kickReason;
+ QString partReason;
+ QString quitReason;
+ QByteArray sslCert;
+ QByteArray sslKey;
+ };
+
+ struct IdentityNickMO {
+ int nickid;
+ IdentityId identityId;
+ QString nick;
+ };
+
+ struct NetworkMO {
+ NetworkId networkid;
+ UserId userid;
+ QString networkname;
+ IdentityId identityid;
+ QString encodingcodec;
+ QString decodingcodec;
+ QString servercodec;
+ bool userandomserver;
+ QString perform;
+ bool useautoidentify;
+ QString autoidentifyservice;
+ QString autoidentifypassword;
+ bool useautoreconnect;
+ int autoreconnectinterval;
+ int autoreconnectretries;
+ bool unlimitedconnectretries;
+ bool rejoinchannels;
+ bool connected;
+ QString usermode;
+ QString awaymessage;
+ QString attachperform;
+ QString detachperform;
+ };
+
+ struct BufferMO {
+ BufferId bufferid;
+ UserId userid;
+ int groupid;
+ NetworkId networkid;
+ QString buffername;
+ QString buffercname;
+ int buffertype;
+ int lastseenmsgid;
+ QString key;
+ bool joined;
+ };
+
+ struct BacklogMO {
+ MsgId messageid;
+ QDateTime time; // has to be in UTC!
+ BufferId bufferid;
+ int type;
+ int flags;
+ int senderid;
+ QString message;
+ };
+
+ struct IrcServerMO {
+ int serverid;
+ UserId userid;
+ NetworkId networkid;
+ QString hostname;
+ int port;
+ QString password;
+ bool ssl;
+ int sslversion;
+ bool useproxy;
+ int proxytype;
+ QString proxyhost;
+ int proxyport;
+ QString proxyuser;
+ QString proxypass;
+ };
+
+ struct UserSettingMO {
+ UserId userid;
+ QString settingname;
+ QByteArray settingvalue;
+ };
+
+ enum MigrationObject {
+ QuasselUser,
+ Sender,
+ Identity,
+ IdentityNick,
+ Network,
+ Buffer,
+ Backlog,
+ IrcServer,
+ UserSetting
+ };
+
+ AbstractSqlMigrator();
+ virtual ~AbstractSqlMigrator() {}
+
+ static QString migrationObject(MigrationObject moType);
+
+protected:
+ void newQuery(const QString &query, QSqlDatabase db);
+ virtual void resetQuery();
+ virtual bool prepareQuery(MigrationObject mo) = 0;
+ bool exec();
+ inline bool next() { return _query->next(); }
+ inline QVariant value(int index) { return _query->value(index); }
+ inline void bindValue(const QString &placeholder, const QVariant &val) { _query->bindValue(placeholder, val); }
+ inline void bindValue(int pos, const QVariant &val) { _query->bindValue(pos, val); }
+
+ inline QSqlError lastError() { return _query ? _query->lastError() : QSqlError(); }
+ void dumpStatus();
+ inline QString executedQuery() { return _query ? _query->executedQuery() : QString(); }
+ inline QVariantList boundValues();
+
+ virtual bool transaction() = 0;
+ virtual void rollback() = 0;
+ virtual bool commit() = 0;
+
+private:
+ QSqlQuery *_query;
+};
+
+class AbstractSqlMigrationWriter;
+class AbstractSqlMigrationReader : public AbstractSqlMigrator {
+public:
+ AbstractSqlMigrationReader();
+
+ virtual bool readMo(QuasselUserMO &user) = 0;
+ virtual bool readMo(SenderMO &sender) = 0;
+ virtual bool readMo(IdentityMO &identity) = 0;
+ virtual bool readMo(IdentityNickMO &identityNick) = 0;
+ virtual bool readMo(NetworkMO &network) = 0;
+ virtual bool readMo(BufferMO &buffer) = 0;
+ virtual bool readMo(BacklogMO &backlog) = 0;
+ virtual bool readMo(IrcServerMO &ircserver) = 0;
+ virtual bool readMo(UserSettingMO &userSetting) = 0;
+
+ bool migrateTo(AbstractSqlMigrationWriter *writer);
+
+private:
+ void abortMigration(const QString &errorMsg = QString());
+ bool finalizeMigration();
+
+ template<typename T> bool transferMo(MigrationObject moType, T &mo);
+
+ AbstractSqlMigrationWriter *_writer;
+};
+
+class AbstractSqlMigrationWriter : public AbstractSqlMigrator {
+public:
+ virtual bool writeMo(const QuasselUserMO &user) = 0;
+ virtual bool writeMo(const SenderMO &sender) = 0;
+ virtual bool writeMo(const IdentityMO &identity) = 0;
+ virtual bool writeMo(const IdentityNickMO &identityNick) = 0;
+ virtual bool writeMo(const NetworkMO &network) = 0;
+ virtual bool writeMo(const BufferMO &buffer) = 0;
+ virtual bool writeMo(const BacklogMO &backlog) = 0;
+ virtual bool writeMo(const IrcServerMO &ircserver) = 0;
+ virtual bool writeMo(const UserSettingMO &userSetting) = 0;
+
+ inline bool migrateFrom(AbstractSqlMigrationReader *reader) { return reader->migrateTo(this); }
+
+ friend class AbstractSqlMigrationReader;
+};
+
#endif