summaryrefslogtreecommitdiff
path: root/modules/extra/sql.h
blob: 62d7b73c0cf033a25cf8f6ac0659f30c3fa8a0c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

/** A SQL exception, can be thrown at various points
 */
class SQLException : public ModuleException
{
 public:
	SQLException(const Anope::string &reason) : ModuleException(reason) { }

	virtual ~SQLException() throw() { }
};

/** A SQL query
 */

struct QueryData
{
	Anope::string data;
	bool escape;
};

struct SQLQuery
{
	Anope::string query;
	std::map<Anope::string, QueryData> parameters;

	SQLQuery() { }
	SQLQuery(const Anope::string &q) : query(q) { }

	SQLQuery& operator=(const Anope::string &q)
	{
		this->query = q;
		this->parameters.clear();
		return *this;
	}
	
	bool operator==(const SQLQuery &other) const
	{
		return this->query == other.query;
	}

	inline bool operator!=(const SQLQuery &other) const
	{
		return !(*this == other);
	}

	template<typename T> void setValue(const Anope::string &key, const T& value, bool escape = true)
	{
		try
		{
			Anope::string string_value = stringify(value);
			this->parameters[key].data = string_value;
			this->parameters[key].escape = escape;
		}
		catch (const ConvertException &ex) { }
	}
};

/** A result from a SQL query
 */
class SQLResult
{
 protected:
	/* Rows, column, item */
	std::vector<std::map<Anope::string, Anope::string> > entries;
	SQLQuery query;
	Anope::string error;
 public:
	unsigned int id;
 	Anope::string finished_query;

	SQLResult() : id(0) { }
	SQLResult(unsigned int i, const SQLQuery &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 const unsigned int GetID() const { return this->id; }
	inline const SQLQuery &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 SQLException("Out of bounds access to SQLResult");
		}
	}

	const 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 SQLException("Unknown column name in SQLResult: " + col);
	
		return it->second;
	}
};

/* An interface used by modules to retrieve the results
 */
class SQLInterface
{
 public:
	Module *owner;

	SQLInterface(Module *m) : owner(m) { }

	virtual void OnResult(const SQLResult &r) = 0;
	virtual void OnError(const SQLResult &r) = 0;
};

/** Class providing the SQL service, modules call this to execute queries
 */
class SQLProvider : public Service
{
 public:
	SQLProvider(Module *c, const Anope::string &n) : Service(c, "SQLProvider", n) { }

	virtual void Run(SQLInterface *i, const SQLQuery &query) = 0;

	virtual SQLResult RunQuery(const SQLQuery &query) = 0;

	virtual std::vector<SQLQuery> CreateTable(const Anope::string &table, const Serialize::Data &data) = 0;

	virtual SQLQuery BuildInsert(const Anope::string &table, unsigned int id, const Serialize::Data &data) = 0;

	virtual SQLQuery GetTables(const Anope::string &prefix) = 0;

	virtual Anope::string FromUnixtime(time_t) = 0;
};