Treating invalid IdentityIds as NULL values
[quassel.git] / src / core / postgresqlstorage.cpp
index c37bab4..d65b4ee 100644 (file)
@@ -35,6 +35,18 @@ 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 {
   if(!QSqlDatabase::isDriverAvailable("QPSQL")) return false;
   return true;
@@ -49,16 +61,32 @@ 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;
 }
 
+bool PostgreSqlStorage::setup(const QVariantMap &settings) {
+  bool success = AbstractSqlStorage::setup(settings);
+  if(success) {
+    logDb().exec(QString("ALTER USER %1 SET standard_conforming_strings TO on").arg(userName()));
+  }
+  return success;
+}
+
 void PostgreSqlStorage::setConnectionProperties(const QVariantMap &properties) {
   _userName = properties["Username"].toString();
   _password = properties["Password"].toString();
@@ -509,7 +537,7 @@ NetworkId PostgreSqlStorage::createNetwork(UserId user, const NetworkInfo &info)
   }
 
   if(!db.commit()) {
-    qWarning() << "PostgreSqlStorage::updateNetwork(): commiting data failed!";
+    qWarning() << "PostgreSqlStorage::createNetwork(): commiting data failed!";
     qWarning() << " -" << qPrintable(db.lastError().text());
     return NetworkId();
   }
@@ -518,7 +546,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));
@@ -971,7 +999,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...";
@@ -1007,7 +1035,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...";
@@ -1247,34 +1275,49 @@ QList<Message> 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";
+
+  if(!prepareQuery(queryName, queryString(queryName), db)) {
+    qWarning() << "PostgreSqlStorage::logMessages(): unable to prepare query:" << queryString(queryName);
+    qWarning() << "  Error:" << db.lastError().text();
+    db.rollback();
+    return messagelist;
+  }
+
+  QSqlQuery query = executePreparedQuery(queryName, params, db);
+
   if(!watchQuery(query)) {
+    qDebug() << "select_messages failed";
     db.rollback();
     return messagelist;
   }
 
   QDateTime timestamp;
-  for(int i = 0; i < limit && query.next(); i++) {
+  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());
+               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;
   }
@@ -1381,7 +1424,7 @@ bool PostgreSqlStorage::prepareQuery(const QString &handle, const QString &query
 QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString &handle, const QVariantList &params, const QSqlDatabase &db) {
   if(!_preparedQueries.contains(db.connectionName()) || !_preparedQueries[db.connectionName()].contains(handle)) {
     qWarning() << "PostgreSqlStorage::executePreparedQuery() no prepared Query with handle" << handle << "on Database" << db.connectionName();
-    return QSqlQuery();
+    return QSqlQuery(db);
   }
 
   QSqlDriver *driver = db.driver();
@@ -1411,7 +1454,7 @@ QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString &handle, const Q
 QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString &handle, const QVariant &param, const QSqlDatabase &db) {
   if(!_preparedQueries.contains(db.connectionName()) || !_preparedQueries[db.connectionName()].contains(handle)) {
     qWarning() << "PostgreSqlStorage::executePreparedQuery() no prepared Query with handle" << handle << "on Database" << db.connectionName();
-    return QSqlQuery();
+    return QSqlQuery(db);
   }
 
   QSqlField field;
@@ -1437,10 +1480,6 @@ void PostgreSqlStorage::deallocateQuery(const QString &handle, const QSqlDatabas
   db.exec(QString("DEALLOCATE %1").arg(queryId));
 }
 
-
-
-
-
 // ========================================
 //  PostgreSqlMigrationWriter
 // ========================================
@@ -1459,6 +1498,7 @@ bool PostgreSqlMigrationWriter::prepareQuery(MigrationObject mo) {
     query = queryString("migrate_write_sender");
     break;
   case Identity:
+    _validIdentities.clear();
     query = queryString("migrate_write_identity");
     break;
   case IdentityNick:
@@ -1501,6 +1541,7 @@ bool PostgreSqlMigrationWriter::writeMo(const SenderMO &sender) {
 
 //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);
@@ -1538,7 +1579,10 @@ bool PostgreSqlMigrationWriter::writeMo(const NetworkMO &network) {
   bindValue(0, network.networkid.toInt());
   bindValue(1, network.userid.toInt());
   bindValue(2, network.networkname);
-  bindValue(3, network.identityid.toInt());
+  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);
@@ -1613,3 +1657,24 @@ bool PostgreSqlMigrationWriter::writeMo(const UserSettingMO &userSetting) {
   bindValue(2, userSetting.settingvalue);
   return exec();
 }
+
+bool PostgreSqlMigrationWriter::postProcess() {
+  QSqlDatabase db = logDb();
+  QList<Sequence> 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<Sequence>::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;
+}