]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/modules/sql.h
Update copyright headers.
[user/henk/code/inspircd.git] / include / modules / sql.h
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2015 Daniel Vassdal <shutter@canternet.org>
5  *   Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
6  *   Copyright (C) 2013, 2017-2019, 2021 Sadie Powell <sadie@witchery.services>
7  *   Copyright (C) 2012 Robby <robby@chatbelgie.be>
8  *   Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org>
9  *
10  * This file is part of InspIRCd.  InspIRCd is free software: you can
11  * redistribute it and/or modify it under the terms of the GNU General Public
12  * License as published by the Free Software Foundation, version 2.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23
24 #pragma once
25
26
27 namespace SQL
28 {
29         class Error;
30         class Field;
31         class Provider;
32         class Query;
33         class Result;
34
35         /** A list of parameter replacement values. */
36         typedef std::vector<std::string> ParamList;
37
38         /** A map of parameter replacement values. */
39         typedef std::map<std::string, std::string> ParamMap;
40
41         /** A list of SQL fields from a specific row. */
42         typedef std::vector<Field> Row;
43
44         /** An enumeration of possible error codes. */
45         enum ErrorCode
46         {
47                 /** No error has occurred. */
48                 SUCCESS,
49
50                 /** The database identifier is invalid. */
51                 BAD_DBID,
52
53                 /** The database connection has failed. */
54                 BAD_CONN,
55
56                 /** Executing the query failed. */
57                 QSEND_FAIL,
58
59                 /** Reading the response failed. */
60                 QREPLY_FAIL
61         };
62
63         /** Populates a parameter map with information about a user.
64          * @param user The user to collect information from.
65          * @param userinfo The map to populate.
66          */
67         void PopulateUserInfo(User* user, ParamMap& userinfo);
68 }
69
70 /** Represents a single SQL field. */
71 class SQL::Field
72 {
73  private:
74         /** Whether this SQL field is NULL. */
75         bool null;
76
77         /** The underlying SQL value. */
78         std::string value;
79
80  public:
81         /** Creates a new NULL SQL field. */
82         Field()
83                 : null(true)
84         {
85         }
86
87         /** Creates a new non-NULL SQL field.
88          * @param v The value of the field.
89          */
90         Field(const std::string& v)
91                 : null(false)
92                 , value(v)
93         {
94         }
95
96         /** Determines whether this SQL entry is NULL. */
97         inline bool IsNull() const { return null; }
98
99         /** Retrieves the underlying value. */
100         inline operator const std::string&() const { return value; }
101 };
102
103 /** Represents the result of an SQL query. */
104 class SQL::Result : public classbase
105 {
106  public:
107         /**
108          * Return the number of rows in the result.
109          *
110          * Note that if you have performed an INSERT or UPDATE query or other
111          * query which will not return rows, this will return the number of
112          * affected rows. In this case you SHOULD NEVER access any of the result
113          * set rows, as there aren't any!
114          * @returns Number of rows in the result set.
115          */
116         virtual int Rows() = 0;
117
118         /** Retrieves the next available row from the database.
119          * @param result A list to store the fields from this row in.
120          * @return True if a row could be retrieved; otherwise, false.
121          */
122         virtual bool GetRow(Row& result) = 0;
123
124         /** Retrieves a list of SQL columns in the result.
125          * @param result A reference to the vector to store column names in.
126          */
127         virtual void GetCols(std::vector<std::string>& result) = 0;
128
129         /**
130          * Check if there's a column with the specified name in the result
131          *
132          * @param column The column name.
133          * @param index The place to store the column index if it exists.
134          * @returns If the column exists then true; otherwise, false.
135          */
136         virtual bool HasColumn(const std::string& column, size_t& index) = 0;
137 };
138
139 /** SQL::Error holds the error state of a request.
140  * The error string varies from database software to database software
141  * and should be used to display informational error messages to users.
142  */
143 class SQL::Error
144 {
145  private:
146         /** The custom error message if one has been specified. */
147         const std::string message;
148
149  public:
150         /** The code which represents this error. */
151         const ErrorCode code;
152
153         /** Initialize an SQL::Error from an error code.
154          * @param c A code which represents this error.
155          */
156         Error(ErrorCode c)
157                 : code(c)
158         {
159         }
160
161         /** Initialize an SQL::Error from an error code and a custom error message.
162          * @param c A code which represents this error.
163          * @param m A custom error message.
164          */
165         Error(ErrorCode c, const std::string m)
166                 : message(m)
167                 , code(c)
168         {
169         }
170
171         /** Retrieves the error message. */
172         const char* ToString() const
173         {
174                 if (!message.empty())
175                         return message.c_str();
176
177                 switch (code)
178                 {
179                         case BAD_DBID:
180                                 return "Invalid database identifier";
181                         case BAD_CONN:
182                                 return "Invalid connection";
183                         case QSEND_FAIL:
184                                 return "Sending query failed";
185                         case QREPLY_FAIL:
186                                 return "Getting query result failed";
187                         default:
188                                 return "Unknown error";
189                 }
190         }
191 };
192
193 /**
194  * Object representing an SQL query. This should be allocated on the heap and
195  * passed to an SQL::Provider, which will free it when the query is complete or
196  * when the querying module is unloaded.
197  *
198  * You should store whatever information is needed to have the callbacks work in
199  * this object (UID of user, channel name, etc).
200  */
201 class SQL::Query : public classbase
202 {
203  protected:
204         /** Creates a new SQL query. */
205         Query(Module* Creator)
206                 : creator(Creator)
207         {
208         }
209
210  public:
211         const ModuleRef creator;
212
213         /* Destroys this Query instance. */
214         virtual ~Query()
215         {
216         }
217
218         /** Called when an SQL error happens.
219          * @param error The error that occurred.
220          */
221         virtual void OnError(Error& error) = 0;
222
223         /** Called when a SQL result is received.
224          * @param result The result of the SQL query.
225          */
226         virtual void OnResult(Result& result) = 0;
227 };
228
229 /**
230  * Provider object for SQL servers
231  */
232 class SQL::Provider : public DataProvider
233 {
234  private:
235         /** The name of the database tag in the config. */
236         const std::string dbid;
237
238  public:
239         Provider(Module* Creator, const std::string& Name)
240                 : DataProvider(Creator, "SQL/" + Name)
241         {
242         }
243
244         /** Retrieves the name of the database tag in the config. */
245         const std::string& GetId() const { return dbid; }
246
247         /** Submit an asynchronous SQL query.
248          * @param callback The result reporting point
249          * @param query The hardcoded query string. If you have parameters to substitute, see below.
250          */
251         virtual void Submit(Query* callback, const std::string& query) = 0;
252
253         /** Submit an asynchronous SQL query.
254          * @param callback The result reporting point
255          * @param format The simple parameterized query string ('?' parameters)
256          * @param p Parameters to fill in for the '?' entries
257          */
258         virtual void Submit(Query* callback, const std::string& format, const SQL::ParamList& p) = 0;
259
260         /** Submit an asynchronous SQL query.
261          * @param callback The result reporting point
262          * @param format The parameterized query string ('$name' parameters)
263          * @param p Parameters to fill in for the '$name' entries
264          */
265         virtual void Submit(Query* callback, const std::string& format, const ParamMap& p) = 0;
266 };
267
268 inline void SQL::PopulateUserInfo(User* user, ParamMap& userinfo)
269 {
270         userinfo["nick"] = user->nick;
271         userinfo["host"] = user->GetRealHost();
272         userinfo["ip"] = user->GetIPString();
273         userinfo["real"] = user->GetRealName();
274         userinfo["ident"] = user->ident;
275         userinfo["server"] = user->server->GetName();
276         userinfo["uuid"] = user->uuid;
277 }