From 7560db024de435dc3ba9013c682c1fa602f918d4 Mon Sep 17 00:00:00 2001 From: Luke A Pitt Date: Tue, 30 Aug 2016 22:42:58 +0100 Subject: [PATCH] Use UPSERT for PostgreSQL, REPLACE INTO for other databases. Used place holder marks for PostgreSQL UPSERT values instead of positional binding since the statements require the values twice (once for the INSERT, and once for the UPDATE should the insert fail). The values to use for the ON CONFLICT DO UPDATE part of the UPSERT have been prefixed with u_ . This commit reverts to using REPLACE INTO for non-PostgreSQL databases and uses the same code for them as the upstream master mumble-voip/mumble. Previously this branch used the same code for all databases. This commit uses if statements to treat PostgreSQL differently from other databases where it needs to use UPSERT instead of REPLACE INTO. --- src/murmur/ServerDB.cpp | 369 ++++++++++++++++++---------------------- 1 file changed, 161 insertions(+), 208 deletions(-) diff --git a/src/murmur/ServerDB.cpp b/src/murmur/ServerDB.cpp index 2b9ff18b0..4f0385c02 100644 --- a/src/murmur/ServerDB.cpp +++ b/src/murmur/ServerDB.cpp @@ -839,28 +839,21 @@ int Server::registerUser(const QMap &info) { id = res; } - int rows = 0; - - SQLPREP("SELECT COUNT(*) AS rows FROM `%1users` WHERE `server_id` = ? AND `name` = ?"); - query.addBindValue(iServerNum); - query.addBindValue(name); - SQLEXEC(); - if (query.next()) { - rows = query.value(0).toInt(); - - if(rows > 0) { - SQLPREP("UPDATE `%1users` SET `user_id` = ? WHERE `server_id` = ? AND `name` = ?"); - query.addBindValue(id); - query.addBindValue(iServerNum); - query.addBindValue(name); - SQLEXEC(); - } else { - SQLPREP("INSERT INTO `%1users` (`server_id`, `user_id`, `name`) VALUES (?,?,?)"); - query.addBindValue(iServerNum); - query.addBindValue(id); - query.addBindValue(name); - SQLEXEC(); - } + if (Meta::mp.qsDBDriver == "QPSQL") { + SQLPREP("INSERT INTO `%1users` (`server_id`, `user_id`, `name`) VALUES (:server_id,:user_id,:name) ON CONFLICT (`server_id`, `name`) DO UPDATE SET `user_id` = :u_user_id WHERE `%1users`.`server_id` = :u_server_id AND `%1users`.`name` = :u_name"); + query.bindValue(":server_id", iServerNum); + query.bindValue(":user_id", id); + query.bindValue(":name", name); + query.bindValue(":u_server_id", iServerNum); + query.bindValue(":u_user_id", id); + query.bindValue(":u_name", name); + SQLEXEC(); + } else { + SQLPREP("REPLACE INTO `%1users` (`server_id`, `user_id`, `name`) VALUES (?,?,?)"); + query.addBindValue(iServerNum); + query.addBindValue(id); + query.addBindValue(name); + SQLEXEC(); } qhUserNameCache.remove(id); @@ -1030,31 +1023,25 @@ int Server::authenticate(QString &name, const QString &password, int sessionId, int lchan=readLastChannel(res); if (lchan < 0) lchan = 0; - - int rows = 0; - - SQLPREP("SELECT COUNT(*) AS rows FROM `%1users` WHERE `server_id` = ? AND `user_id` = ?"); - query.addBindValue(iServerNum); - query.addBindValue(res); - SQLEXEC(); - if (query.next()) { - rows = query.value(0).toInt(); - - if(rows > 0) { - SQLPREP("UPDATE `%1users` SET `name` = ?, `lastchannel` = ? WHERE `server_id` = ? AND `user_id` = ?"); - query.addBindValue(name); - query.addBindValue(lchan); - query.addBindValue(iServerNum); - query.addBindValue(res); - SQLEXEC(); - } else { - SQLPREP("INSERT INTO `%1users` (`server_id`, `user_id`, `name`, `lastchannel`) VALUES (?,?,?,?)"); - query.addBindValue(iServerNum); - query.addBindValue(res); - query.addBindValue(name); - query.addBindValue(lchan); - SQLEXEC(); - } + + if (Meta::mp.qsDBDriver == "QPSQL") { + SQLPREP("INSERT INTO `%1users` (`server_id`, `user_id`, `name`, `lastchannel`) VALUES (:server_id,:user_id,:name,:lastchannel) ON CONFLICT (`server_id`, `user_id`) DO UPDATE SET `name` = :u_name, `lastchannel` = :u_lastchannel WHERE `%1users`.`server_id` = :u_server_id AND `%1users`.`user_id` = :u_user_id"); + query.bindValue(":server_id", iServerNum); + query.bindValue(":user_id", res); + query.bindValue(":name", name); + query.bindValue(":lastchannel", lchan); + query.bindValue(":u_server_id", iServerNum); + query.bindValue(":u_user_id", res); + query.bindValue(":u_name", name); + query.bindValue(":u_lastchannel", lchan); + SQLEXEC(); + } else { + SQLPREP("REPLACE INTO `%1users` (`server_id`, `user_id`, `name`, `lastchannel`) VALUES (?,?,?,?)"); + query.addBindValue(iServerNum); + query.addBindValue(res); + query.addBindValue(name); + query.addBindValue(lchan); + SQLEXEC(); } } if (res >= 0) { @@ -1173,59 +1160,43 @@ int Server::authenticate(QString &name, const QString &password, int sessionId, } } if (! certhash.isEmpty() && (res > 0)) { - int rows = 0; - - SQLPREP("SELECT COUNT(*) AS rows FROM `%1user_info` WHERE `server_id` = ? AND `user_id` = ? AND `key` = ?"); - query.addBindValue(iServerNum); - query.addBindValue(res); - query.addBindValue(ServerDB::User_Hash); - SQLEXEC(); - if (query.next()) { - rows = query.value(0).toInt(); - - if(rows > 0) { - SQLPREP("UPDATE `%1user_info` SET `value` = ? WHERE `server_id` = ? AND `user_id` = ? AND `key` = ?"); - query.addBindValue(certhash); - query.addBindValue(iServerNum); - query.addBindValue(res); - query.addBindValue(ServerDB::User_Hash); - SQLEXEC(); - } else { - SQLPREP("INSERT INTO `%1user_info` (`server_id`, `user_id`, `key`, `value`) VALUES (?, ?, ?, ?)"); - query.addBindValue(iServerNum); - query.addBindValue(res); - query.addBindValue(ServerDB::User_Hash); - query.addBindValue(certhash); - SQLEXEC(); - } + if (Meta::mp.qsDBDriver == "QPSQL") { + SQLPREP("INSERT INTO `%1user_info` (`server_id`, `user_id`, `key`, `value`) VALUES (:server_id, :user_id, :key, :value) ON CONFLICT (`server_id`, `user_id`, `key`) DO UPDATE SET `value` = :u_value WHERE `%1user_info`.`server_id` = :u_server_id AND `%1user_info`.`user_id` = :u_user_id AND `%1user_info`.`key` = :u_key"); + query.bindValue(":server_id", iServerNum); + query.bindValue(":user_id", res); + query.bindValue(":key", ServerDB::User_Hash); + query.bindValue(":value", certhash); + query.bindValue(":u_server_id", iServerNum); + query.bindValue(":u_user_id", res); + query.bindValue(":u_key", ServerDB::User_Hash); + query.bindValue(":u_value", certhash); + SQLEXEC(); + } else { + SQLPREP("REPLACE INTO `%1user_info` (`server_id`, `user_id`, `key`, `value`) VALUES (?, ?, ?, ?)"); + query.addBindValue(iServerNum); + query.addBindValue(res); + query.addBindValue(ServerDB::User_Hash); + query.addBindValue(certhash); + SQLEXEC(); } if (! emails.isEmpty()) { - rows = 0; - - SQLPREP("SELECT COUNT(*) AS rows FROM `%1user_info` WHERE `server_id` = ? AND `user_id` = ? AND `key` = ?"); - query.addBindValue(iServerNum); - query.addBindValue(res); - query.addBindValue(ServerDB::User_Email); - SQLEXEC(); - if (query.next()) { - rows = query.value(0).toInt(); - - if(rows > 0) { - SQLPREP("UPDATE `%1user_info` SET `value` = ? WHERE `server_id` = ? AND `user_id` = ? AND `key` = ?"); - query.addBindValue(emails.at(0)); - query.addBindValue(iServerNum); - query.addBindValue(res); - query.addBindValue(ServerDB::User_Email); - SQLEXEC(); - } else { - SQLPREP("INSERT INTO `%1user_info` (`server_id`, `user_id`, `key`, `value`) VALUES (?, ?, ?, ?)"); - query.addBindValue(iServerNum); - query.addBindValue(res); - query.addBindValue(ServerDB::User_Email); - query.addBindValue(emails.at(0)); - SQLEXEC(); - } + if (Meta::mp.qsDBDriver == "QPSQL") { + query.bindValue(":server_id", iServerNum); + query.bindValue(":user_id", res); + query.bindValue(":key", ServerDB::User_Email); + query.bindValue(":value", emails.at(0)); + query.bindValue(":u_server_id", iServerNum); + query.bindValue(":u_user_id", res); + query.bindValue(":u_key", ServerDB::User_Email); + query.bindValue(":u_value", emails.at(0)); + SQLEXEC(); + } else { + query.addBindValue(iServerNum); + query.addBindValue(res); + query.addBindValue(ServerDB::User_Email); + query.addBindValue(emails.at(0)); + SQLEXEC(); } } } @@ -1302,36 +1273,33 @@ bool Server::setInfo(int id, const QMap &setinfo) { info.remove(ServerDB::User_Name); } if (! info.isEmpty()) { - int rows = 0; QMap::const_iterator i; - - for (i=info.constBegin(); i != info.constEnd(); ++i) { - rows = 0; - - SQLPREP("SELECT COUNT(*) AS rows FROM `%1user_info` WHERE `server_id` = ? AND `user_id` = ? AND `key` = ?"); - query.addBindValue(iServerNum); - query.addBindValue(id); - query.addBindValue(i.key()); - SQLEXEC(); - if (query.next()) { - rows = query.value(0).toInt(); - - if(rows > 0) { - SQLPREP("UPDATE `%1user_info` SET `value` = ? WHERE `server_id` = ? AND `user_id` = ? AND `key` = ?"); - query.addBindValue(i.value()); - query.addBindValue(iServerNum); - query.addBindValue(id); - query.addBindValue(i.key()); - SQLEXEC(); - } else { - SQLPREP("INSERT INTO `%1user_info` (`server_id`, `user_id`, `key`, `value`) VALUES (?,?,?,?)"); - query.addBindValue(iServerNum); - query.addBindValue(id); - query.addBindValue(i.key()); - query.addBindValue(i.value()); - SQLEXEC(); - } - } + QVariantList serverids, userids, keys, values; + + for (i = info.constBegin(); i != info.constEnd(); ++i) { + serverids << iServerNum; + userids << id; + keys << i.key(); + values << i.value(); + } + if (Meta::mp.qsDBDriver == "QPSQL") { + SQLPREP("INSERT INTO `%1user_info` (`server_id`, `user_id`, `key`, `value`) VALUES (:server_id, :user_id, :key, :value) ON CONFLICT (`server_id`, `user_id`, `key`) DO UPDATE SET `value` = :u_value WHERE `%1user_info`.`server_id` = :u_server_id AND `%1user_info`.`user_id` = :u_user_id AND `%1user_info`.`key` = :u_key"); + query.bindValue(":server_id", serverids); + query.bindValue(":user_id", userids); + query.bindValue(":key", keys); + query.bindValue(":value", values); + query.bindValue(":u_server_id", serverids); + query.bindValue(":u_user_id", userids); + query.bindValue(":u_key", keys); + query.bindValue(":u_value", values); + SQLEXECBATCH(); + } else { + SQLPREP("REPLACE INTO `%1user_info` (`server_id`, `user_id`, `key`, `value`) VALUES (?,?,?,?)"); + query.addBindValue(serverids); + query.addBindValue(userids); + query.addBindValue(keys); + query.addBindValue(values); + SQLEXECBATCH(); } } @@ -1378,7 +1346,7 @@ void ServerDB::writeSUPW(int srvnum, const QString &pwHash, const QString &saltH query.addBindValue(srvnum); query.addBindValue(0); SQLEXEC(); - if (!query.next()) { + if (! query.next()) { SQLPREP("INSERT INTO `%1users` (`server_id`, `user_id`, `name`) VALUES (?, ?, ?)"); query.addBindValue(srvnum); query.addBindValue(0); @@ -1627,67 +1595,61 @@ void Server::updateChannel(const Channel *c) { SQLEXEC(); // Update channel description information - int rows = 0; - - SQLPREP("SELECT COUNT(*) AS rows FROM `%1channel_info` WHERE `server_id` = ? AND `channel_id` = ? AND `key` = ?"); - query.addBindValue(iServerNum); - query.addBindValue(c->iId); - query.addBindValue(ServerDB::Channel_Description); - SQLEXEC(); - if (query.next()) { - rows = query.value(0).toInt(); - - if(rows > 0) { - SQLPREP("UPDATE `%1channel_info` SET `value` = ? WHERE `server_id` = ? AND `channel_id` = ? AND `key` = ?"); - query.addBindValue(c->qsDesc); - query.addBindValue(iServerNum); - query.addBindValue(c->iId); - query.addBindValue(ServerDB::Channel_Description); - SQLEXEC(); - } else { - SQLPREP("INSERT INTO `%1channel_info` (`server_id`, `channel_id`, `key`, `value`) VALUES (?,?,?,?)"); - query.addBindValue(iServerNum); - query.addBindValue(c->iId); - query.addBindValue(ServerDB::Channel_Description); - query.addBindValue(c->qsDesc); - SQLEXEC(); - } + if (Meta::mp.qsDBDriver == "QPSQL") { + SQLPREP("INSERT INTO `%1channel_info` (`server_id`, `channel_id`, `key`, `value`) VALUES (:server_id, :channel_id, :key, :value) ON CONFLICT (`server_id`, `channel_id`, `key`) DO UPDATE SET `value` = :u_value WHERE `%1channel_info`.`server_id` = :u_server_id AND `%1channel_info`.`channel_id` = :u_channel_id AND `%1channel_info`.`key` = :u_key"); + query.bindValue(":server_id", iServerNum); + query.bindValue(":channel_id", c->iId); + query.bindValue(":key", ServerDB::Channel_Description); + query.bindValue(":value", c->qsDesc); + query.bindValue(":u_server_id", iServerNum); + query.bindValue(":u_channel_id", c->iId); + query.bindValue(":u_key", ServerDB::Channel_Description); + query.bindValue(":u_value", c->qsDesc); + SQLEXEC(); + } else { + SQLPREP("REPLACE INTO `%1channel_info` (`server_id`, `channel_id`, `key`, `value`) VALUES (?, ?, ?, ?)"); + query.addBindValue(iServerNum); + query.addBindValue(c->iId); + query.addBindValue(ServerDB::Channel_Description); + query.addBindValue(c->qsDesc); + SQLEXEC(); } - // Update channel position information - rows = 0; - - SQLPREP("SELECT COUNT(*) AS rows FROM `%1channel_info` WHERE `server_id` = ? AND `channel_id` = ? AND `key` = ?"); - query.addBindValue(iServerNum); - query.addBindValue(c->iId); - query.addBindValue(ServerDB::Channel_Position); - SQLEXEC(); - if (query.next()) { - rows = query.value(0).toInt(); - - if(rows > 0) { - SQLPREP("UPDATE `%1channel_info` SET `value` = ? WHERE `server_id` = ? AND `channel_id` = ? AND `key` = ?"); - query.addBindValue(QVariant(c->iPosition).toString()); - query.addBindValue(iServerNum); - query.addBindValue(c->iId); - query.addBindValue(ServerDB::Channel_Position); - SQLEXEC(); - } else { - SQLPREP("INSERT INTO `%1channel_info` (`server_id`, `channel_id`, `key`, `value`) VALUES (?,?,?,?)"); - query.addBindValue(iServerNum); - query.addBindValue(c->iId); - query.addBindValue(ServerDB::Channel_Position); - query.addBindValue(QVariant(c->iPosition).toString()); - SQLEXEC(); - } + if (Meta::mp.qsDBDriver == "QPSQL") { + query.bindValue(":server_id", iServerNum); + query.bindValue(":channel_id", c->iId); + query.bindValue(":key", ServerDB::Channel_Position); + query.bindValue(":value", QVariant(c->iPosition).toString()); + query.bindValue(":u_server_id", iServerNum); + query.bindValue(":u_channel_id", c->iId); + query.bindValue(":u_key", ServerDB::Channel_Position); + query.bindValue(":u_value", QVariant(c->iPosition).toString()); + SQLEXEC(); + } else { + query.addBindValue(iServerNum); + query.addBindValue(c->iId); + query.addBindValue(ServerDB::Channel_Position); + query.addBindValue(QVariant(c->iPosition).toString()); + SQLEXEC(); + } + // Update channel maximum channels + if (Meta::mp.qsDBDriver == "QPSQL") { + query.bindValue(":server_id", iServerNum); + query.bindValue(":channel_id", c->iId); + query.bindValue(":key", ServerDB::Channel_Max_Users); + query.bindValue(":value", QVariant(c->uiMaxUsers).toString()); + query.bindValue(":u_server_id", iServerNum); + query.bindValue(":u_channel_id", c->iId); + query.bindValue(":u_key", ServerDB::Channel_Max_Users); + query.bindValue(":u_value", QVariant(c->uiMaxUsers).toString()); + SQLEXEC(); + } else { + query.addBindValue(iServerNum); + query.addBindValue(c->iId); + query.addBindValue(ServerDB::Channel_Max_Users); + query.addBindValue(QVariant(c->uiMaxUsers).toString()); + SQLEXEC(); } - - // Update channel maximum users - query.addBindValue(iServerNum); - query.addBindValue(c->iId); - query.addBindValue(ServerDB::Channel_Max_Users); - query.addBindValue(QVariant(c->uiMaxUsers).toString()); - SQLEXEC(); SQLPREP("DELETE FROM `%1groups` WHERE `server_id` = ? AND `channel_id` = ?"); query.addBindValue(iServerNum); @@ -2133,32 +2095,23 @@ void ServerDB::setConf(int server_id, const QString &k, const QVariant &value) { SQLPREP("DELETE FROM `%1config` WHERE `server_id` = ? AND `key` = ?"); query.addBindValue(server_id); query.addBindValue(key); - SQLEXEC(); } else { - int rows = 0; - - SQLPREP("SELECT COUNT(*) AS rows FROM `%1config` WHERE `server_id` = ? AND `key` = ?"); - query.addBindValue(server_id); - query.addBindValue(key); - SQLEXEC(); - if (query.next()) { - rows = query.value(0).toInt(); - - if(rows > 0) { - SQLPREP("UPDATE `%1config` SET `value` = ? WHERE `server_id` = ? AND `key` = ?"); - query.addBindValue(value.toString()); - query.addBindValue(server_id); - query.addBindValue(key); - SQLEXEC(); - } else { - SQLPREP("INSERT INTO `%1config` (`server_id`, `key`, `value`) VALUES (?,?,?)"); - query.addBindValue(server_id); - query.addBindValue(key); - query.addBindValue(value.toString()); - SQLEXEC(); - } + if (Meta::mp.qsDBDriver == "QPSQL") { + SQLPREP("INSERT INTO `%1config` (`server_id`, `key`, `value`) VALUES (:server_id, :key, :value) ON CONFLICT (`server_id`, `key`) DO UPDATE SET `value` = :u_value WHERE `%1config`.`server_id` = :u_server_id AND `%1config`.`key` = :u_key"); + query.bindValue(":server_id", server_id); + query.bindValue(":key", key); + query.bindValue(":value", value.toString()); + query.bindValue(":u_server_id", server_id); + query.bindValue(":u_key", key); + query.bindValue(":u_value", value.toString()); + } else { + SQLPREP("REPLACE INTO `%1config` (`server_id`, `key`, `value`) VALUES (?,?,?)"); + query.addBindValue(server_id); + query.addBindValue(key); + query.addBindValue(value.toString()); } } + SQLEXEC(); }