X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fpostgresqlstorage.cpp;h=2de296046317344f692493dd032820a342dccc32;hp=2c9c5b4498dc71c95929214392033ae9414bf225;hb=636812603e3308fece0ad677977c85b5cc9f18ee;hpb=41f90ea96aad92b534a982296168baff8b8da2d7 diff --git a/src/core/postgresqlstorage.cpp b/src/core/postgresqlstorage.cpp index 2c9c5b44..2de29604 100644 --- a/src/core/postgresqlstorage.cpp +++ b/src/core/postgresqlstorage.cpp @@ -26,8 +26,6 @@ #include "network.h" #include "quassel.h" -int PostgreSqlStorage::_maxRetryCount = 150; // yes this is a large number... only other way to "handle" this is bailing out... - PostgreSqlStorage::PostgreSqlStorage(QObject *parent) : AbstractSqlStorage(parent), _port(-1) @@ -37,7 +35,20 @@ PostgreSqlStorage::PostgreSqlStorage(QObject *parent) PostgreSqlStorage::~PostgreSqlStorage() { } +AbstractSqlMigrationWriter *PostgreSqlStorage::createMigrationWriter() { + PostgreSqlMigrationWriter *writer = new PostgreSqlMigrationWriter(); + QVariantMap properties; + properties["Username"] = _userName; + properties["Password"] = _password; + properties["Hostname"] = _hostName; + properties["Port"] = _port; + properties["Database"] = _databaseName; + writer->setConnectionProperties(properties); + return writer; +} + bool PostgreSqlStorage::isAvailable() const { + qDebug() << QSqlDatabase::drivers(); if(!QSqlDatabase::isDriverAvailable("QPSQL")) return false; return true; } @@ -51,16 +62,30 @@ QString PostgreSqlStorage::description() const { return tr("PostgreSQL Turbo Bomber HD!"); } -QVariantMap PostgreSqlStorage::setupKeys() const { +QStringList PostgreSqlStorage::setupKeys() const { + QStringList keys; + keys << "Username" + << "Password" + << "Hostname" + << "Port" + << "Database"; + return keys; +} +QVariantMap PostgreSqlStorage::setupDefaults() const { QVariantMap map; map["Username"] = QVariant(QString("quassel")); - map["Password"] = QVariant(QString()); map["Hostname"] = QVariant(QString("localhost")); map["Port"] = QVariant(5432); map["Database"] = QVariant(QString("quassel")); return map; } +void PostgreSqlStorage::initDbSession(QSqlDatabase &db) { + // this blows... but unfortunately Qt's PG driver forces us to this... + db.exec("set standard_conforming_strings = off"); + db.exec("set escape_string_warning = off"); +} + void PostgreSqlStorage::setConnectionProperties(const QVariantMap &properties) { _userName = properties["Username"].toString(); _password = properties["Password"].toString(); @@ -125,12 +150,13 @@ UserId PostgreSqlStorage::addUser(const QString &user, const QString &password) return uid; } -void PostgreSqlStorage::updateUser(UserId user, const QString &password) { +bool PostgreSqlStorage::updateUser(UserId user, const QString &password) { QSqlQuery query(logDb()); query.prepare(queryString("update_userpassword")); query.bindValue(":userid", user.toInt()); query.bindValue(":password", cryptedPassword(password)); safeExec(query); + return query.numRowsAffected() != 0; } void PostgreSqlStorage::renameUser(UserId user, const QString &newName) { @@ -156,6 +182,19 @@ UserId PostgreSqlStorage::validateUser(const QString &user, const QString &passw } } +UserId PostgreSqlStorage::getUserId(const QString &user) { + QSqlQuery query(logDb()); + query.prepare(queryString("select_userid")); + query.bindValue(":username", user); + safeExec(query); + + if(query.first()) { + return query.value(0).toInt(); + } else { + return 0; + } +} + UserId PostgreSqlStorage::internalUser() { QSqlQuery query(logDb()); query.prepare(queryString("select_internaluser")); @@ -276,7 +315,7 @@ IdentityId PostgreSqlStorage::createIdentity(UserId user, CoreIdentity &identity return IdentityId(); } - qDebug() << "creatId" << query.first() << query.value(0).toInt(); + query.first(); identityId = query.value(0).toInt(); identity.setId(identityId); @@ -299,7 +338,7 @@ IdentityId PostgreSqlStorage::createIdentity(UserId user, CoreIdentity &identity } if(!db.commit()) { - qWarning() << "PostgreSqlStorage::createIdentity(): commiting data failed!"; + qWarning() << "PostgreSqlStorage::createIdentity(): committing data failed!"; qWarning() << " -" << qPrintable(db.lastError().text()); return IdentityId(); } @@ -382,7 +421,7 @@ bool PostgreSqlStorage::updateIdentity(UserId user, const CoreIdentity &identity } if(!db.commit()) { - qWarning() << "PostgreSqlStorage::updateIdentity(): commiting data failed!"; + qWarning() << "PostgreSqlStorage::updateIdentity(): committing data failed!"; qWarning() << " -" << qPrintable(db.lastError().text()); return false; } @@ -488,7 +527,7 @@ NetworkId PostgreSqlStorage::createNetwork(UserId user, const NetworkInfo &info) return NetworkId(); } - qDebug() << "createNet:" << query.first() << query.value(0).toInt(); + query.first(); networkId = query.value(0).toInt(); if(!networkId.isValid()) { @@ -511,7 +550,7 @@ NetworkId PostgreSqlStorage::createNetwork(UserId user, const NetworkInfo &info) } if(!db.commit()) { - qWarning() << "PostgreSqlStorage::updateNetwork(): commiting data failed!"; + qWarning() << "PostgreSqlStorage::createNetwork(): committing data failed!"; qWarning() << " -" << qPrintable(db.lastError().text()); return NetworkId(); } @@ -520,7 +559,7 @@ NetworkId PostgreSqlStorage::createNetwork(UserId user, const NetworkInfo &info) void PostgreSqlStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &info) { query.bindValue(":networkname", info.networkName); - query.bindValue(":identityid", info.identity.toInt()); + query.bindValue(":identityid", info.identity.isValid() ? info.identity.toInt() : QVariant()); query.bindValue(":encodingcodec", QString(info.codecForEncoding)); query.bindValue(":decodingcodec", QString(info.codecForDecoding)); query.bindValue(":servercodec", QString(info.codecForServer)); @@ -529,6 +568,9 @@ void PostgreSqlStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &inf query.bindValue(":useautoidentify", info.useAutoIdentify); query.bindValue(":autoidentifyservice", info.autoIdentifyService); query.bindValue(":autoidentifypassword", info.autoIdentifyPassword); + query.bindValue(":usesasl", info.useSasl); + query.bindValue(":saslaccount", info.saslAccount); + query.bindValue(":saslpassword", info.saslPassword); query.bindValue(":useautoreconnect", info.useAutoReconnect); query.bindValue(":autoreconnectinterval", info.autoReconnectInterval); query.bindValue(":autoreconnectretries", info.autoReconnectRetries); @@ -598,7 +640,7 @@ bool PostgreSqlStorage::updateNetwork(UserId user, const NetworkInfo &info) { } if(!db.commit()) { - qWarning() << "PostgreSqlStorage::updateNetwork(): commiting data failed!"; + qWarning() << "PostgreSqlStorage::updateNetwork(): committing data failed!"; qWarning() << " -" << qPrintable(db.lastError().text()); return false; } @@ -668,6 +710,9 @@ QList PostgreSqlStorage::networks(UserId user) { net.autoReconnectRetries = networksQuery.value(13).toInt(); net.unlimitedReconnectRetries = networksQuery.value(14).toBool(); net.rejoinChannels = networksQuery.value(15).toBool(); + net.useSasl = networksQuery.value(16).toBool(); + net.saslAccount = networksQuery.value(17).toString(); + net.saslPassword = networksQuery.value(18).toString(); serversQuery.bindValue(":networkid", net.networkId.toInt()); safeExec(serversQuery); @@ -868,6 +913,8 @@ BufferInfo PostgreSqlStorage::bufferInfo(UserId user, const NetworkId &networkId createQuery.bindValue(":buffertype", (int)type); createQuery.bindValue(":buffername", buffer); createQuery.bindValue(":buffercname", buffer.toLower()); + createQuery.bindValue(":joined", type & BufferInfo::ChannelBuffer ? true : false); + safeExec(createQuery); if(createQuery.lastError().isValid()) { @@ -973,7 +1020,7 @@ bool PostgreSqlStorage::removeBuffer(const UserId &user, const BufferId &bufferI return false; case 1: db.commit(); - return false; + return true; default: // there was more then one buffer deleted... qWarning() << "PostgreSqlStorage::removeBuffer(): Userid" << user << "BufferId" << "caused deletion of" << numRows << "Buffers! Rolling back transaction..."; @@ -1009,7 +1056,7 @@ bool PostgreSqlStorage::renameBuffer(const UserId &user, const BufferId &bufferI return false; case 1: db.commit(); - return false; + return true; default: // there was more then one buffer deleted... qWarning() << "PostgreSqlStorage::renameBuffer(): Userid" << user << "BufferId" << "affected" << numRows << "Buffers! Rolling back transaction..."; @@ -1027,7 +1074,7 @@ bool PostgreSqlStorage::mergeBuffersPermanently(const UserId &user, const Buffer } QSqlQuery checkQuery(db); - checkQuery.prepare("SELECT count(*) FROM buffer" + checkQuery.prepare("SELECT count(*) FROM buffer " "WHERE userid = :userid AND bufferid IN (:buffer1, :buffer2)"); checkQuery.bindValue(":userid", user.toInt()); checkQuery.bindValue(":buffer1", bufferId1.toInt()); @@ -1055,6 +1102,7 @@ bool PostgreSqlStorage::mergeBuffersPermanently(const UserId &user, const Buffer QSqlQuery delBufferQuery(logDb()); delBufferQuery.prepare(queryString("delete_buffer_for_bufferid")); + delBufferQuery.bindValue(":userid", user.toInt()); delBufferQuery.bindValue(":bufferid", bufferId2.toInt()); safeExec(delBufferQuery); if(!watchQuery(delBufferQuery)) { @@ -1104,7 +1152,45 @@ QHash PostgreSqlStorage::bufferLastSeenMsgIds(UserId user) { return lastSeenHash; } -MsgId PostgreSqlStorage::logMessage(Message msg) { +void PostgreSqlStorage::setBufferMarkerLineMsg(UserId user, const BufferId &bufferId, const MsgId &msgId) { + QSqlQuery query(logDb()); + query.prepare(queryString("update_buffer_markerlinemsgid")); + + query.bindValue(":userid", user.toInt()); + query.bindValue(":bufferid", bufferId.toInt()); + query.bindValue(":markerlinemsgid", msgId.toInt()); + safeExec(query); + watchQuery(query); +} + +QHash PostgreSqlStorage::bufferMarkerLineMsgIds(UserId user) { + QHash markerLineHash; + + QSqlDatabase db = logDb(); + if(!beginReadOnlyTransaction(db)) { + qWarning() << "PostgreSqlStorage::bufferMarkerLineMsgIds(): cannot start read only transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return markerLineHash; + } + + QSqlQuery query(db); + query.prepare(queryString("select_buffer_markerlinemsgids")); + query.bindValue(":userid", user.toInt()); + safeExec(query); + if(!watchQuery(query)) { + db.rollback(); + return markerLineHash; + } + + while(query.next()) { + markerLineHash[query.value(0).toInt()] = query.value(1).toInt(); + } + + db.commit(); + return markerLineHash; +} + +bool PostgreSqlStorage::logMessage(Message &msg) { QSqlDatabase db = logDb(); if(!db.transaction()) { qWarning() << "PostgreSqlStorage::logMessage(): cannot start transaction!"; @@ -1112,39 +1198,127 @@ MsgId PostgreSqlStorage::logMessage(Message msg) { return false; } - QSqlQuery logMessageQuery(db); - logMessageQuery.prepare(queryString("insert_message")); - logMessageQuery.bindValue(":time", msg.timestamp().toTime_t()); - logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt()); - logMessageQuery.bindValue(":type", msg.type()); - logMessageQuery.bindValue(":flags", (int)msg.flags()); - logMessageQuery.bindValue(":sender", msg.sender()); - logMessageQuery.bindValue(":message", msg.contents()); - safeExec(logMessageQuery); + QSqlQuery getSenderIdQuery = executePreparedQuery("select_senderid", msg.sender(), db); + int senderId; + if(getSenderIdQuery.first()) { + senderId = getSenderIdQuery.value(0).toInt(); + } else { + // it's possible that the sender was already added by another thread + // since the insert might fail we're setting a savepoint + savePoint("sender_sp1", db); + QSqlQuery addSenderQuery = executePreparedQuery("insert_sender", msg.sender(), db); + + if(addSenderQuery.lastError().isValid()) { + rollbackSavePoint("sender_sp1", db); + getSenderIdQuery = db.exec(getSenderIdQuery.lastQuery()); + getSenderIdQuery.first(); + senderId = getSenderIdQuery.value(0).toInt(); + } else { + releaseSavePoint("sender_sp1", db); + addSenderQuery.first(); + senderId = addSenderQuery.value(0).toInt(); + } + } - if(logMessageQuery.lastError().isValid()) { - // first we need to reset the transaction + QVariantList params; + params << msg.timestamp() + << msg.bufferInfo().bufferId().toInt() + << msg.type() + << (int)msg.flags() + << senderId + << msg.contents(); + QSqlQuery logMessageQuery = executePreparedQuery("insert_message", params, db); + + if(!watchQuery(logMessageQuery)) { db.rollback(); - db.transaction(); + return false; + } + + logMessageQuery.first(); + MsgId msgId = logMessageQuery.value(0).toInt(); + db.commit(); + if(msgId.isValid()) { + msg.setMsgId(msgId); + return true; + } else { + return false; + } +} + +bool PostgreSqlStorage::logMessages(MessageList &msgs) { + QSqlDatabase db = logDb(); + if(!db.transaction()) { + qWarning() << "PostgreSqlStorage::logMessage(): cannot start transaction!"; + qWarning() << " -" << qPrintable(db.lastError().text()); + return false; + } + + QList senderIdList; + QHash senderIds; + QSqlQuery addSenderQuery; + QSqlQuery selectSenderQuery;; + for(int i = 0; i < msgs.count(); i++) { + const QString &sender = msgs.at(i).sender(); + if(senderIds.contains(sender)) { + senderIdList << senderIds[sender]; + continue; + } - QSqlQuery addSenderQuery(db); - addSenderQuery.prepare(queryString("insert_sender")); - addSenderQuery.bindValue(":sender", msg.sender()); - safeExec(addSenderQuery); - safeExec(logMessageQuery); + selectSenderQuery = executePreparedQuery("select_senderid", sender, db); + if(selectSenderQuery.first()) { + senderIdList << selectSenderQuery.value(0).toInt(); + senderIds[sender] = selectSenderQuery.value(0).toInt(); + } else { + savePoint("sender_sp", db); + addSenderQuery= executePreparedQuery("insert_sender", sender, db); + if(addSenderQuery.lastError().isValid()) { + // seems it was inserted meanwhile... by a different thread + rollbackSavePoint("sender_sp", db); + selectSenderQuery = db.exec(selectSenderQuery.lastQuery()); + selectSenderQuery.first(); + senderIdList << selectSenderQuery.value(0).toInt(); + senderIds[sender] = selectSenderQuery.value(0).toInt(); + } else { + releaseSavePoint("sender_sp", db); + addSenderQuery.first(); + senderIdList << addSenderQuery.value(0).toInt(); + senderIds[sender] = addSenderQuery.value(0).toInt(); + } + } + } + // yes we loop twice over the same list. This avoids alternating queries. + bool error = false; + for(int i = 0; i < msgs.count(); i++) { + Message &msg = msgs[i]; + QVariantList params; + params << msg.timestamp() + << msg.bufferInfo().bufferId().toInt() + << msg.type() + << (int)msg.flags() + << senderIdList.at(i) + << msg.contents(); + QSqlQuery logMessageQuery = executePreparedQuery("insert_message", params, db); if(!watchQuery(logMessageQuery)) { db.rollback(); - return MsgId(); + error = true; + break; + } else { + logMessageQuery.first(); + msg.setMsgId(logMessageQuery.value(0).toInt()); } } - logMessageQuery.first(); - MsgId msgId = logMessageQuery.value(0).toInt(); - db.commit(); + if(error) { + // we had a rollback in the db so we need to reset all msgIds + for(int i = 0; i < msgs.count(); i++) { + msgs[i].setMsgId(MsgId()); + } + return false; + } - Q_ASSERT(msgId.isValid()); - return msgId; + db.commit(); + return true; } QList PostgreSqlStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit) { @@ -1163,31 +1337,42 @@ QList PostgreSqlStorage::requestMsgs(UserId user, BufferId bufferId, Ms return messagelist; } - QSqlQuery query(db); + QString queryName; + QVariantList params; if(last == -1 && first == -1) { - query.prepare(queryString("select_messages")); + queryName = "select_messages"; } else if(last == -1) { - query.prepare(queryString("select_messagesNewerThan")); - query.bindValue(":firstmsg", first.toInt()); + queryName = "select_messagesNewerThan"; + params << first.toInt(); } else { - query.prepare(queryString("select_messagesRange")); - query.bindValue(":lastmsg", last.toInt()); - query.bindValue(":firstmsg", first.toInt()); + queryName = "select_messagesRange"; + params << first.toInt(); + params << last.toInt(); } - query.bindValue(":bufferid", bufferId.toInt()); - safeExec(query); + params << bufferId.toInt(); + if(limit != -1) + params << limit; + else + params << "ALL"; + + QSqlQuery query = executePreparedQuery(queryName, params, db); + if(!watchQuery(query)) { + qDebug() << "select_messages failed"; db.rollback(); return messagelist; } - for(int i = 0; i < limit && query.next(); i++) { - Message msg(QDateTime::fromTime_t(query.value(1).toInt()), - bufferInfo, - (Message::Type)query.value(2).toUInt(), - query.value(5).toString(), - query.value(4).toString(), - (Message::Flags)query.value(3).toUInt()); + QDateTime timestamp; + while(query.next()) { + timestamp = query.value(1).toDateTime(); + timestamp.setTimeSpec(Qt::UTC); + Message msg(timestamp, + bufferInfo, + (Message::Type)query.value(2).toUInt(), + query.value(5).toString(), + query.value(4).toString(), + (Message::Flags)query.value(3).toUInt()); msg.setMsgId(query.value(0).toInt()); messagelist << msg; } @@ -1227,8 +1412,11 @@ QList PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId return messagelist; } + QDateTime timestamp; for(int i = 0; i < limit && query.next(); i++) { - Message msg(QDateTime::fromTime_t(query.value(2).toInt()), + timestamp = query.value(1).toDateTime(); + timestamp.setTimeSpec(Qt::UTC); + Message msg(timestamp, bufferInfoHash[query.value(1).toInt()], (Message::Type)query.value(3).toUInt(), query.value(6).toString(), @@ -1269,3 +1457,287 @@ bool PostgreSqlStorage::beginReadOnlyTransaction(QSqlDatabase &db) { QSqlQuery query = db.exec("BEGIN TRANSACTION READ ONLY"); return !query.lastError().isValid(); } + +QSqlQuery PostgreSqlStorage::prepareAndExecuteQuery(const QString &queryname, const QString ¶mstring, const QSqlDatabase &db) { + // Query preparing is done lazily. That means that instead of always checking if the query is already prepared + // we just EXECUTE and catch the error + QSqlQuery query; + + db.exec("SAVEPOINT quassel_prepare_query"); + if(paramstring.isNull()) { + query = db.exec(QString("EXECUTE quassel_%1").arg(queryname)); + } else { + query = db.exec(QString("EXECUTE quassel_%1 (%2)").arg(queryname).arg(paramstring)); + } + + if(db.lastError().isValid()) { + // and once again: Qt leaves us without error codes so we either parse (language dependant(!)) strings + // or we just guess the error. As we're only interested in unprepared queries, this will be our guess. :) + db.exec("ROLLBACK TO SAVEPOINT quassel_prepare_query"); + QSqlQuery checkQuery = db.exec(QString("SELECT count(name) FROM pg_prepared_statements WHERE name = 'quassel_%1' AND from_sql = TRUE").arg(queryname.toLower())); + checkQuery.first(); + if(checkQuery.value(0).toInt() == 0) { + db.exec(QString("PREPARE quassel_%1 AS %2").arg(queryname).arg(queryString(queryname))); + if(db.lastError().isValid()) { + qWarning() << "PostgreSqlStorage::prepareQuery(): unable to prepare query:" << queryname << "AS" << queryString(queryname); + qWarning() << " Error:" << db.lastError().text(); + return QSqlQuery(db); + } + } + // we alwas execute the query again, even if the query was already prepared. + // this ensures, that the error is properly propagated to the calling function + // (otherwise the last call would be the testing select to pg_prepared_statements + // which always gives a proper result and the error would be lost) + if(paramstring.isNull()) { + query = db.exec(QString("EXECUTE quassel_%1").arg(queryname)); + } else { + query = db.exec(QString("EXECUTE quassel_%1 (%2)").arg(queryname).arg(paramstring)); + } + } else { + // only release the SAVEPOINT + db.exec("RELEASE SAVEPOINT quassel_prepare_query"); + } + return query; +} + +QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString &queryname, const QVariantList ¶ms, const QSqlDatabase &db) { + QSqlDriver *driver = db.driver(); + + QStringList paramStrings; + QSqlField field; + for(int i = 0; i < params.count(); i++) { + const QVariant &value = params.at(i); + field.setType(value.type()); + if(value.isNull()) + field.clear(); + else + field.setValue(value); + + paramStrings << driver->formatValue(field); + } + + if(params.isEmpty()) { + return prepareAndExecuteQuery(queryname, db); + } else { + return prepareAndExecuteQuery(queryname, paramStrings.join(", "), db); + } +} + +QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString &queryname, const QVariant ¶m, const QSqlDatabase &db) { + QSqlField field; + field.setType(param.type()); + if(param.isNull()) + field.clear(); + else + field.setValue(param); + + QString paramString = db.driver()->formatValue(field); + return prepareAndExecuteQuery(queryname, paramString, db); +} + +void PostgreSqlStorage::deallocateQuery(const QString &queryname, const QSqlDatabase &db) { + db.exec(QString("DEALLOCATE quassel_%1").arg(queryname)); +} + +// ======================================== +// PostgreSqlMigrationWriter +// ======================================== +PostgreSqlMigrationWriter::PostgreSqlMigrationWriter() + : PostgreSqlStorage() +{ +} + +bool PostgreSqlMigrationWriter::prepareQuery(MigrationObject mo) { + QString query; + switch(mo) { + case QuasselUser: + query = queryString("migrate_write_quasseluser"); + break; + case Sender: + query = queryString("migrate_write_sender"); + break; + case Identity: + _validIdentities.clear(); + query = queryString("migrate_write_identity"); + break; + case IdentityNick: + query = queryString("migrate_write_identity_nick"); + break; + case Network: + query = queryString("migrate_write_network"); + break; + case Buffer: + query = queryString("migrate_write_buffer"); + break; + case Backlog: + query = queryString("migrate_write_backlog"); + break; + case IrcServer: + query = queryString("migrate_write_ircserver"); + break; + case UserSetting: + query = queryString("migrate_write_usersetting"); + break; + } + newQuery(query, logDb()); + return true; +} + +//bool PostgreSqlMigrationWriter::writeUser(const QuasselUserMO &user) { +bool PostgreSqlMigrationWriter::writeMo(const QuasselUserMO &user) { + bindValue(0, user.id.toInt()); + bindValue(1, user.username); + bindValue(2, user.password); + return exec(); +} + +//bool PostgreSqlMigrationWriter::writeSender(const SenderMO &sender) { +bool PostgreSqlMigrationWriter::writeMo(const SenderMO &sender) { + bindValue(0, sender.senderId); + bindValue(1, sender.sender); + return exec(); +} + +//bool PostgreSqlMigrationWriter::writeIdentity(const IdentityMO &identity) { +bool PostgreSqlMigrationWriter::writeMo(const IdentityMO &identity) { + _validIdentities << identity.id.toInt(); + bindValue(0, identity.id.toInt()); + bindValue(1, identity.userid.toInt()); + bindValue(2, identity.identityname); + bindValue(3, identity.realname); + bindValue(4, identity.awayNick); + bindValue(5, identity.awayNickEnabled); + bindValue(6, identity.awayReason); + bindValue(7, identity.awayReasonEnabled); + bindValue(8, identity.autoAwayEnabled); + bindValue(9, identity.autoAwayTime); + bindValue(10, identity.autoAwayReason); + bindValue(11, identity.autoAwayReasonEnabled); + bindValue(12, identity.detachAwayEnabled); + bindValue(13, identity.detachAwayReason); + bindValue(14, identity.detchAwayReasonEnabled); + bindValue(15, identity.ident); + bindValue(16, identity.kickReason); + bindValue(17, identity.partReason); + bindValue(18, identity.quitReason); + bindValue(19, identity.sslCert); + bindValue(20, identity.sslKey); + return exec(); +} + +//bool PostgreSqlMigrationWriter::writeIdentityNick(const IdentityNickMO &identityNick) { +bool PostgreSqlMigrationWriter::writeMo(const IdentityNickMO &identityNick) { + bindValue(0, identityNick.nickid); + bindValue(1, identityNick.identityId.toInt()); + bindValue(2, identityNick.nick); + return exec(); +} + +//bool PostgreSqlMigrationWriter::writeNetwork(const NetworkMO &network) { +bool PostgreSqlMigrationWriter::writeMo(const NetworkMO &network) { + bindValue(0, network.networkid.toInt()); + bindValue(1, network.userid.toInt()); + bindValue(2, network.networkname); + if(_validIdentities.contains(network.identityid.toInt())) + bindValue(3, network.identityid.toInt()); + else + bindValue(3, QVariant()); + bindValue(4, network.encodingcodec); + bindValue(5, network.decodingcodec); + bindValue(6, network.servercodec); + bindValue(7, network.userandomserver); + bindValue(8, network.perform); + bindValue(9, network.useautoidentify); + bindValue(10, network.autoidentifyservice); + bindValue(11, network.autoidentifypassword); + bindValue(12, network.useautoreconnect); + bindValue(13, network.autoreconnectinterval); + bindValue(14, network.autoreconnectretries); + bindValue(15, network.unlimitedconnectretries); + bindValue(16, network.rejoinchannels); + bindValue(17, network.connected); + bindValue(18, network.usermode); + bindValue(19, network.awaymessage); + bindValue(20, network.attachperform); + bindValue(21, network.detachperform); + bindValue(22, network.usesasl); + bindValue(23, network.saslaccount); + bindValue(24, network.saslpassword); + return exec(); +} + +//bool PostgreSqlMigrationWriter::writeBuffer(const BufferMO &buffer) { +bool PostgreSqlMigrationWriter::writeMo(const BufferMO &buffer) { + bindValue(0, buffer.bufferid.toInt()); + bindValue(1, buffer.userid.toInt()); + bindValue(2, buffer.groupid); + bindValue(3, buffer.networkid.toInt()); + bindValue(4, buffer.buffername); + bindValue(5, buffer.buffercname); + bindValue(6, (int)buffer.buffertype); + bindValue(7, buffer.lastseenmsgid); + bindValue(8, buffer.markerlinemsgid); + bindValue(9, buffer.key); + bindValue(10, buffer.joined); + return exec(); +} + +//bool PostgreSqlMigrationWriter::writeBacklog(const BacklogMO &backlog) { +bool PostgreSqlMigrationWriter::writeMo(const BacklogMO &backlog) { + bindValue(0, backlog.messageid.toInt()); + bindValue(1, backlog.time); + bindValue(2, backlog.bufferid.toInt()); + bindValue(3, backlog.type); + bindValue(4, (int)backlog.flags); + bindValue(5, backlog.senderid); + bindValue(6, backlog.message); + return exec(); +} + +//bool PostgreSqlMigrationWriter::writeIrcServer(const IrcServerMO &ircserver) { +bool PostgreSqlMigrationWriter::writeMo(const IrcServerMO &ircserver) { + bindValue(0, ircserver.serverid); + bindValue(1, ircserver.userid.toInt()); + bindValue(2, ircserver.networkid.toInt()); + bindValue(3, ircserver.hostname); + bindValue(4, ircserver.port); + bindValue(5, ircserver.password); + bindValue(6, ircserver.ssl); + bindValue(7, ircserver.sslversion); + bindValue(8, ircserver.useproxy); + bindValue(9, ircserver.proxytype); + bindValue(10, ircserver.proxyhost); + bindValue(11, ircserver.proxyport); + bindValue(12, ircserver.proxyuser); + bindValue(13, ircserver.proxypass); + return exec(); +} + +//bool PostgreSqlMigrationWriter::writeUserSetting(const UserSettingMO &userSetting) { +bool PostgreSqlMigrationWriter::writeMo(const UserSettingMO &userSetting) { + bindValue(0, userSetting.userid.toInt()); + bindValue(1, userSetting.settingname); + bindValue(2, userSetting.settingvalue); + return exec(); +} + +bool PostgreSqlMigrationWriter::postProcess() { + QSqlDatabase db = logDb(); + QList sequences; + sequences << Sequence("backlog", "messageid") + << Sequence("buffer", "bufferid") + << Sequence("identity", "identityid") + << Sequence("identity_nick", "nickid") + << Sequence("ircserver", "serverid") + << Sequence("network", "networkid") + << Sequence("quasseluser", "userid") + << Sequence("sender", "senderid"); + QList::const_iterator iter; + for(iter = sequences.constBegin(); iter != sequences.constEnd(); iter++) { + resetQuery(); + newQuery(QString("SELECT setval('%1_%2_seq', max(%2)) FROM %1").arg(iter->table, iter->field), db); + if(!exec()) + return false; + } + return true; +}