1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-07-02 16:38:41 +00:00

Add mod storage PostgreSQL backend

This commit is contained in:
Jude Melton-Houghton 2022-10-19 14:16:57 -04:00 committed by Loïc Blot
parent 9dbac989bd
commit aaa05f901a
4 changed files with 315 additions and 0 deletions

View file

@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "remoteplayer.h"
#include "server/player_sao.h"
#include <cstdlib>
Database_PostgreSQL::Database_PostgreSQL(const std::string &connect_string,
const char *type) :
@ -812,5 +813,211 @@ void AuthDatabasePostgreSQL::writePrivileges(const AuthEntry &authEntry)
}
}
ModMetadataDatabasePostgreSQL::ModMetadataDatabasePostgreSQL(const std::string &connect_string):
Database_PostgreSQL(connect_string, "_mod_storage"),
ModMetadataDatabase()
{
connectToDatabase();
}
void ModMetadataDatabasePostgreSQL::createDatabase()
{
createTableIfNotExists("mod_storage",
"CREATE TABLE mod_storage ("
"modname TEXT NOT NULL,"
"key BYTEA NOT NULL,"
"value BYTEA NOT NULL,"
"PRIMARY KEY (modname, key)"
");");
infostream << "PostgreSQL: Mod Storage Database was initialized." << std::endl;
}
void ModMetadataDatabasePostgreSQL::initStatements()
{
prepareStatement("get_all",
"SELECT key, value FROM mod_storage WHERE modname = $1");
prepareStatement("get_all_keys",
"SELECT key FROM mod_storage WHERE modname = $1");
prepareStatement("get",
"SELECT value FROM mod_storage WHERE modname = $1 AND key = $2::bytea");
prepareStatement("has",
"SELECT true FROM mod_storage WHERE modname = $1 AND key = $2::bytea");
if (getPGVersion() < 90500) {
prepareStatement("set_insert",
"INSERT INTO mod_storage (modname, key, value) "
"SELECT $1, $2::bytea, $3::bytea "
"WHERE NOT EXISTS ("
"SELECT true FROM mod_storage WHERE modname = $1 AND key = $2::bytea"
")");
prepareStatement("set_update",
"UPDATE mod_storage SET value = $3::bytea WHERE modname = $1 AND key = $2::bytea");
} else {
prepareStatement("set",
"INSERT INTO mod_storage (modname, key, value) VALUES ($1, $2::bytea, $3::bytea) "
"ON CONFLICT ON CONSTRAINT mod_storage_pkey DO "
"UPDATE SET value = $3::bytea");
}
prepareStatement("remove",
"DELETE FROM mod_storage WHERE modname = $1 AND key = $2::bytea");
prepareStatement("remove_all",
"DELETE FROM mod_storage WHERE modname = $1");
prepareStatement("list",
"SELECT DISTINCT modname FROM mod_storage");
}
bool ModMetadataDatabasePostgreSQL::getModEntries(const std::string &modname, StringMap *storage)
{
verifyDatabase();
const void *args[] = { modname.c_str() };
const int argLen[] = { -1 };
const int argFmt[] = { 0 };
PGresult *results = execPrepared("get_all", ARRLEN(args),
args, argLen, argFmt, false);
int numrows = PQntuples(results);
for (int row = 0; row < numrows; ++row) {
std::string key(PQgetvalue(results, row, 0), PQgetlength(results, row, 0));
std::string value(PQgetvalue(results, row, 1), PQgetlength(results, row, 1));
storage->emplace(std::move(key), std::move(value));
}
PQclear(results);
return true;
}
bool ModMetadataDatabasePostgreSQL::getModKeys(const std::string &modname,
std::vector<std::string> *storage)
{
verifyDatabase();
const void *args[] = { modname.c_str() };
const int argLen[] = { -1 };
const int argFmt[] = { 0 };
PGresult *results = execPrepared("get_all_keys", ARRLEN(args),
args, argLen, argFmt, false);
int numrows = PQntuples(results);
storage->reserve(storage->size() + numrows);
for (int row = 0; row < numrows; ++row)
storage->emplace_back(PQgetvalue(results, row, 0), PQgetlength(results, row, 0));
PQclear(results);
return true;
}
bool ModMetadataDatabasePostgreSQL::getModEntry(const std::string &modname,
const std::string &key, std::string *value)
{
verifyDatabase();
const void *args[] = { modname.c_str(), key.c_str() };
const int argLen[] = { -1, (int)MYMIN(key.size(), INT_MAX) };
const int argFmt[] = { 0, 1 };
PGresult *results = execPrepared("get", ARRLEN(args), args, argLen, argFmt, false);
int numrows = PQntuples(results);
bool found = numrows > 0;
if (found)
value->assign(PQgetvalue(results, 0, 0), PQgetlength(results, 0, 0));
PQclear(results);
return found;
}
bool ModMetadataDatabasePostgreSQL::hasModEntry(const std::string &modname,
const std::string &key)
{
verifyDatabase();
const void *args[] = { modname.c_str(), key.c_str() };
const int argLen[] = { -1, (int)MYMIN(key.size(), INT_MAX) };
const int argFmt[] = { 0, 1 };
PGresult *results = execPrepared("has", ARRLEN(args), args, argLen, argFmt, false);
int numrows = PQntuples(results);
bool found = numrows > 0;
PQclear(results);
return found;
}
bool ModMetadataDatabasePostgreSQL::setModEntry(const std::string &modname,
const std::string &key, const std::string &value)
{
verifyDatabase();
const void *args[] = { modname.c_str(), key.c_str(), value.c_str() };
const int argLen[] = {
-1,
(int)MYMIN(key.size(), INT_MAX),
(int)MYMIN(value.size(), INT_MAX),
};
const int argFmt[] = { 0, 1, 1 };
if (getPGVersion() < 90500) {
execPrepared("set_insert", ARRLEN(args), args, argLen, argFmt);
execPrepared("set_update", ARRLEN(args), args, argLen, argFmt);
} else {
execPrepared("set", ARRLEN(args), args, argLen, argFmt);
}
return true;
}
bool ModMetadataDatabasePostgreSQL::removeModEntry(const std::string &modname,
const std::string &key)
{
verifyDatabase();
const void *args[] = { modname.c_str(), key.c_str() };
const int argLen[] = { -1, (int)MYMIN(key.size(), INT_MAX) };
const int argFmt[] = { 0, 1 };
PGresult *results = execPrepared("remove", ARRLEN(args), args, argLen, argFmt, false);
int affected = atoi(PQcmdTuples(results));
PQclear(results);
return affected > 0;
}
bool ModMetadataDatabasePostgreSQL::removeModEntries(const std::string &modname)
{
verifyDatabase();
const void *args[] = { modname.c_str() };
const int argLen[] = { -1 };
const int argFmt[] = { 0 };
PGresult *results = execPrepared("remove_all", ARRLEN(args), args, argLen, argFmt, false);
int affected = atoi(PQcmdTuples(results));
PQclear(results);
return affected > 0;
}
void ModMetadataDatabasePostgreSQL::listMods(std::vector<std::string> *res)
{
verifyDatabase();
PGresult *results = execPrepared("list", 0, NULL, false);
int numrows = PQntuples(results);
for (int row = 0; row < numrows; ++row)
res->emplace_back(PQgetvalue(results, row, 0), PQgetlength(results, row, 0));
PQclear(results);
}
#endif // USE_POSTGRESQL

View file

@ -169,3 +169,27 @@ protected:
private:
virtual void writePrivileges(const AuthEntry &authEntry);
};
class ModMetadataDatabasePostgreSQL : private Database_PostgreSQL, public ModMetadataDatabase
{
public:
ModMetadataDatabasePostgreSQL(const std::string &connect_string);
~ModMetadataDatabasePostgreSQL() = default;
bool getModEntries(const std::string &modname, StringMap *storage);
bool getModKeys(const std::string &modname, std::vector<std::string> *storage);
bool getModEntry(const std::string &modname, const std::string &key, std::string *value);
bool hasModEntry(const std::string &modname, const std::string &key);
bool setModEntry(const std::string &modname,
const std::string &key, const std::string &value);
bool removeModEntry(const std::string &modname, const std::string &key);
bool removeModEntries(const std::string &modname);
void listMods(std::vector<std::string> *res);
void beginSave() { Database_PostgreSQL::beginSave(); }
void endSave() { Database_PostgreSQL::endSave(); }
protected:
virtual void createDatabase();
virtual void initStatements();
};