1
0
mirror of https://github.com/anope/anope.git synced 2026-06-12 15:44:46 +02:00
Files
anope/include/modules/sql.h
T
2026-01-01 18:07:12 +00:00

208 lines
4.6 KiB
C++

// Anope IRC Services <https://www.anope.org/>
//
// Copyright (C) 2003-2026 Anope Contributors
//
// Anope is free software. You can use, modify, and/or distribute it under the
// terms of version 2 of the GNU General Public License. See docs/LICENSE.txt
// for the complete terms of this license and docs/AUTHORS.txt for a list of
// contributors.
//
// Based on the original code of Epona by Lara
// Based on the original code of Services by Andy Church
//
// SPDX-License-Identifier: GPL-2.0-only
#pragma once
#include <stdexcept>
namespace SQL
{
class Data final
: public Serialize::Data
{
public:
typedef std::map<Anope::string, std::stringstream *> Map;
Map data;
~Data()
{
Clear();
}
std::iostream &operator[](const Anope::string &key) override
{
std::stringstream *&ss = data[key];
if (!ss)
ss = new std::stringstream();
return *ss;
}
size_t Hash() const override
{
size_t hash = 0;
for (const auto &[_, value] : this->data)
{
if (!value->str().empty())
hash ^= Anope::hash_cs()(value->str());
}
return hash;
}
std::map<Anope::string, std::iostream *> GetData() const
{
std::map<Anope::string, std::iostream *> d;
for (const auto &[key, value] : this->data)
d[key] = value;
return d;
}
void Clear()
{
for (const auto &[_, value] : this->data)
delete value;
this->data.clear();
}
};
/** A SQL exception, can be thrown at various points
*/
class DllExport Exception : public ModuleException
{
public:
Exception(const Anope::string &reason) : ModuleException(reason) { }
virtual ~Exception() noexcept = default;
};
/** A SQL query
*/
struct QueryData final
{
Anope::string data;
bool escape;
};
struct Query final
{
Anope::string query;
std::map<Anope::string, QueryData> parameters;
Query() { }
Query(const Anope::string &q) : query(q) { }
Query &operator=(const Anope::string &q)
{
this->query = q;
this->parameters.clear();
return *this;
}
bool operator==(const Query &other) const
{
return this->query == other.query;
}
inline bool operator!=(const Query &other) const
{
return !(*this == other);
}
template<typename T> void SetValue(const Anope::string &key, const T &value, bool escape = true)
{
auto str = Anope::TryString(value);
if (!str.has_value())
return;
this->parameters[key].data = str.value();
this->parameters[key].escape = escape;
}
};
/** A result from a SQL query
*/
class Result
{
protected:
/* Rows, column, item */
std::vector<std::map<Anope::string, Anope::string> > entries;
Query query;
Anope::string error;
public:
unsigned int id = 0;
Anope::string finished_query;
Result() = default;
Result(unsigned int i, const Query &q, const Anope::string &fq, const Anope::string &err = "") : query(q), error(err), id(i), finished_query(fq) { }
inline operator bool() const { return this->error.empty(); }
inline unsigned int GetID() const { return this->id; }
inline const Query &GetQuery() const { return this->query; }
inline const Anope::string &GetError() const { return this->error; }
int Rows() const { return this->entries.size(); }
const std::map<Anope::string, Anope::string> &Row(size_t index) const
{
try
{
return this->entries.at(index);
}
catch (const std::out_of_range &)
{
throw Exception("Out of bounds access to SQLResult");
}
}
Anope::string Get(size_t index, const Anope::string &col) const
{
const std::map<Anope::string, Anope::string> rows = this->Row(index);
std::map<Anope::string, Anope::string>::const_iterator it = rows.find(col);
if (it == rows.end())
throw Exception("Unknown column name in SQLResult: " + col);
return it->second;
}
};
/* An interface used by modules to retrieve the results
*/
class Interface
{
public:
Module *owner;
Interface(Module *m) : owner(m) { }
virtual ~Interface() = default;
virtual void OnResult(const Result &r) = 0;
virtual void OnError(const Result &r) = 0;
};
/** Class providing the SQL service, modules call this to execute queries
*/
class Provider
: public Service
{
public:
Provider(Module *c, const Anope::string &n) : Service(c, "SQL::Provider", n) { }
virtual void Run(Interface *i, const Query &query) = 0;
virtual Result RunQuery(const Query &query) = 0;
virtual std::vector<Query> CreateTable(const Anope::string &table, const Data &data) = 0;
virtual Query BuildInsert(const Anope::string &table, Serializable::Id id, Data &data) = 0;
virtual Query GetTables(const Anope::string &prefix) = 0;
virtual Anope::string FromUnixtime(time_t) = 0;
};
}