]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_sqlv2.h
Add extra parameter to OnUserPreNotice and OnUserPrePrivmsg, CUList &exempt_list...
[user/henk/code/inspircd.git] / src / modules / extra / m_sqlv2.h
1 #ifndef INSPIRCD_SQLAPI_2
2 #define INSPIRCD_SQLAPI_2
3
4 #include <string>
5 #include <deque>
6 #include <map>
7 #include "modules.h"
8
9 /** SQLreq define.
10  * This is the voodoo magic which lets us pass multiple
11  * parameters to the SQLrequest constructor... voodoo...
12  */
13 #define SQLreq(a, b, c, d, e...) SQLrequest(a, b, c, (SQLquery(d), ##e))
14
15 /** Identifiers used to identify Request types
16  */
17 #define SQLREQID "SQLv2 Request"
18 #define SQLRESID "SQLv2 Result"
19 #define SQLSUCCESS "You shouldn't be reading this (success)"
20
21 /** Defines the error types which SQLerror may be set to
22  */
23 enum SQLerrorNum { NO_ERROR, BAD_DBID, BAD_CONN, QSEND_FAIL, QREPLY_FAIL };
24
25 /** A list of format parameters for an SQLquery object.
26  */
27 typedef std::deque<std::string> ParamL;
28
29 /** The base class of SQL exceptions
30  */
31 class SQLexception : public ModuleException
32 {
33  public:
34         SQLexception(const std::string &reason) : ModuleException(reason)
35         {
36         }
37
38         SQLexception() : ModuleException("SQLv2: Undefined exception")
39         {
40         }
41 };
42
43 /** An exception thrown when a bad column or row name or id is requested
44  */
45 class SQLbadColName : public SQLexception
46 {
47 public:
48         SQLbadColName() : SQLexception("SQLv2: Bad column name")
49         {
50         }
51 };
52
53 /** SQLerror holds the error state of any SQLrequest or SQLresult.
54  * The error string varies from database software to database software
55  * and should be used to display informational error messages to users.
56  */
57 class SQLerror : public classbase
58 {
59         /** The error id
60          */
61         SQLerrorNum id;
62         /** The error string
63          */
64         std::string str;
65 public:
66         /** Initialize an SQLerror
67          * @param i The error ID to set
68          * @param s The (optional) error string to set
69          */
70         SQLerror(SQLerrorNum i = NO_ERROR, const std::string &s = "")
71         : id(i), str(s)
72         {       
73         }
74         
75         /** Return the ID of the error
76          */
77         SQLerrorNum Id()
78         {
79                 return id;
80         }
81         
82         /** Set the ID of an error
83          * @param i The new error ID to set
84          * @return the ID which was set
85          */
86         SQLerrorNum Id(SQLerrorNum i)
87         {
88                 id = i;
89                 return id;
90         }
91         
92         /** Set the error string for an error
93          * @param s The new error string to set
94          */
95         void Str(const std::string &s)
96         {
97                 str = s;
98         }
99         
100         /** Return the error string for an error
101          */
102         const char* Str()
103         {
104                 if(str.length())
105                         return str.c_str();
106                 
107                 switch(id)
108                 {
109                         case NO_ERROR:
110                                 return "No error";
111                         case BAD_DBID:
112                                 return "Invalid database ID";
113                         case BAD_CONN:
114                                 return "Invalid connection";
115                         case QSEND_FAIL:
116                                 return "Sending query failed";
117                         case QREPLY_FAIL:
118                                 return "Getting query result failed";
119                         default:
120                                 return "Unknown error";                         
121                 }
122         }
123 };
124
125 /** SQLquery provides a way to represent a query string, and its parameters in a type-safe way.
126  * C++ has no native type-safe way of having a variable number of arguments to a function,
127  * the workaround for this isn't easy to describe simply, but in a nutshell what's really
128  * happening when - from the above example - you do this:
129  *
130  * SQLrequest foo = SQLreq(this, target, "databaseid", "SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?", "Hello", "42");
131  *
132  * what's actually happening is functionally this:
133  *
134  * SQLrequest foo = SQLreq(this, target, "databaseid", query("SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?").addparam("Hello").addparam("42"));
135  *
136  * with 'query()' returning a reference to an object with a 'addparam()' member function which
137  * in turn returns a reference to that object. There are actually four ways you can create a
138  * SQLrequest..all have their disadvantages and advantages. In the real implementations the
139  * 'query()' function is replaced by the constructor of another class 'SQLquery' which holds
140  * the query string and a ParamL (std::deque<std::string>) of query parameters.
141  * This is essentially the same as the above example except 'addparam()' is replaced by operator,(). The full syntax for this method is:
142  *
143  * SQLrequest foo = SQLrequest(this, target, "databaseid", (SQLquery("SELECT.. ?"), parameter, parameter));
144  */
145 class SQLquery
146 {
147 public:
148         /** The query 'format string'
149          */
150         std::string q;
151         /** The query parameter list
152          * There should be one parameter for every ? character
153          * within the format string shown above.
154          */
155         ParamL p;
156
157         /** Initialize an SQLquery with a given format string only
158          */
159         SQLquery(const std::string &query)
160         : q(query)
161         {
162         }
163
164         /** Initialize an SQLquery with a format string and parameters.
165          * If you provide parameters, you must initialize the list yourself
166          * if you choose to do it via this method, using std::deque::push_back().
167          */
168         SQLquery(const std::string &query, const ParamL &params)
169         : q(query), p(params)
170         {
171         }       
172         
173         /** An overloaded operator for pushing parameters onto the parameter list
174          */
175         SQLquery& operator,(const std::string &foo)
176         {
177                 p.push_back(foo);
178                 return *this;
179         }
180         
181         /** An overloaded operator for pushing parameters onto the parameter list.
182          * This has higher precedence than 'operator,' and can save on parenthesis.
183          */
184         SQLquery& operator%(const std::string &foo)
185         {
186                 p.push_back(foo);
187                 return *this;
188         }
189 };
190
191 /** SQLrequest is sent to the SQL API to command it to run a query and return the result.
192  * You must instantiate this object with a valid SQLquery object and its parameters, then
193  * send it using its Send() method to the module providing the 'SQL' feature. To find this
194  * module, use Server::FindFeature().
195  */
196 class SQLrequest : public Request
197 {
198 public:
199         /** The fully parsed and expanded query string
200          * This is initialized from the SQLquery parameter given in the constructor.
201          */
202         SQLquery query;
203         /** The database ID to apply the request to
204          */
205         std::string dbid;
206         /** True if this is a priority query.
207          * Priority queries may 'queue jump' in the request queue.
208          */
209         bool pri;
210         /** The query ID, assigned by the SQL api.
211          * After your request is processed, this will
212          * be initialized for you by the API to a valid request ID,
213          * except in the case of an error.
214          */
215         unsigned long id;
216         /** If an error occured, error.id will be any other value than NO_ERROR.
217          */
218         SQLerror error;
219         
220         /** Initialize an SQLrequest.
221          * For example:
222          *
223          * SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors VALUES('','?')", nick);
224          *
225          * @param s A pointer to the sending module, where the result should be routed
226          * @param d A pointer to the receiving module, identified as implementing the 'SQL' feature
227          * @param databaseid The database ID to perform the query on. This must match a valid
228          * database ID from the configuration of the SQL module.
229          * @param q A properly initialized SQLquery object.
230          */
231         SQLrequest(Module* s, Module* d, const std::string &databaseid, const SQLquery &q)
232         : Request(s, d, SQLREQID), query(q), dbid(databaseid), pri(false), id(0)
233         {
234         }
235         
236         /** Set the priority of a request.
237          */
238         void Priority(bool p = true)
239         {
240                 pri = p;
241         }
242         
243         /** Set the source of a request. You should not need to use this method.
244          */
245         void SetSource(Module* mod)
246         {
247                 source = mod;
248         }
249 };
250
251 /**
252  * This class contains a field's data plus a way to determine if the field
253  * is NULL or not without having to mess around with NULL pointers.
254  */
255 class SQLfield
256 {
257 public:
258         /**
259          * The data itself
260          */
261         std::string d;
262
263         /**
264          * If the field was null
265          */
266         bool null;
267
268         /** Initialize an SQLfield
269          */
270         SQLfield(const std::string &data = "", bool n = false)
271         : d(data), null(n)
272         {
273                 
274         }
275 };
276
277 /** A list of items which make up a row of a result or table (tuple)
278  * This does not include field names.
279  */
280 typedef std::vector<SQLfield> SQLfieldList;
281 /** A list of items which make up a row of a result or table (tuple)
282  * This also includes the field names.
283  */
284 typedef std::map<std::string, SQLfield> SQLfieldMap;
285
286 /** SQLresult is a reply to a previous query.
287  * If you send a query to the SQL api, the response will arrive at your
288  * OnRequest method of your module at some later time, depending on the
289  * congestion of the SQL server and complexity of the query. The ID of
290  * this result will match the ID assigned to your original request.
291  * SQLresult contains its own internal cursor (row counter) which is
292  * incremented with each method call which retrieves a single row.
293  */
294 class SQLresult : public Request
295 {
296 public:
297         /** The original query string passed initially to the SQL API
298          */
299         std::string query;
300         /** The database ID the query was executed on
301          */
302         std::string dbid;
303         /**
304          * The error (if any) which occured.
305          * If an error occured the value of error.id will be any
306          * other value than NO_ERROR.
307          */
308         SQLerror error; 
309         /**
310          * This will match  query ID you were given when sending
311          * the request at an earlier time.
312          */
313         unsigned long id;
314
315         /** Used by the SQL API to instantiate an SQLrequest
316          */
317         SQLresult(Module* s, Module* d, unsigned long i)
318         : Request(s, d, SQLRESID), id(i)
319         {
320         }
321         
322         /**
323          * Return the number of rows in the result
324          * Note that if you have perfomed an INSERT
325          * or UPDATE query or other query which will
326          * not return rows, this will return the
327          * number of affected rows, and SQLresult::Cols()
328          * will contain 0. In this case you SHOULD NEVER
329          * access any of the result set rows, as there arent any!
330          * @returns Number of rows in the result set.
331          */
332         virtual int Rows() = 0;
333         
334         /**
335          * Return the number of columns in the result.
336          * If you performed an UPDATE or INSERT which
337          * does not return a dataset, this value will
338          * be 0.
339          * @returns Number of columns in the result set.
340          */
341         virtual int Cols() = 0;
342         
343         /**
344          * Get a string name of the column by an index number
345          * @param column The id number of a column
346          * @returns The column name associated with the given ID
347          */
348         virtual std::string ColName(int column) = 0;
349         
350         /**
351          * Get an index number for a column from a string name.
352          * An exception of type SQLbadColName will be thrown if
353          * the name given is invalid.
354          * @param column The column name to get the ID of
355          * @returns The ID number of the column provided
356          */
357         virtual int ColNum(const std::string &column) = 0;
358         
359         /**
360          * Get a string value in a given row and column
361          * This does not effect the internal cursor.
362          * @returns The value stored at [row,column] in the table
363          */
364         virtual SQLfield GetValue(int row, int column) = 0;
365         
366         /**
367          * Return a list of values in a row, this should
368          * increment an internal counter so you can repeatedly
369          * call it until it returns an empty vector.
370          * This returns a reference to an internal object,
371          * the same object is used for all calls to this function
372          * and therefore the return value is only valid until
373          * you call this function again. It is also invalid if
374          * the SQLresult object is destroyed.
375          * The internal cursor (row counter) is incremented by one.
376          * @returns A reference to the current row's SQLfieldList
377          */
378         virtual SQLfieldList& GetRow() = 0;
379         
380         /**
381          * As above, but return a map indexed by key name.
382          * The internal cursor (row counter) is incremented by one.
383          * @returns A reference to the current row's SQLfieldMap
384          */
385         virtual SQLfieldMap& GetRowMap() = 0;
386         
387         /**
388          * Like GetRow(), but returns a pointer to a dynamically
389          * allocated object which must be explicitly freed. For
390          * portability reasons this must be freed with SQLresult::Free()
391          * The internal cursor (row counter) is incremented by one.
392          * @returns A newly-allocated SQLfieldList
393          */
394         virtual SQLfieldList* GetRowPtr() = 0;
395         
396         /**
397          * As above, but return a map indexed by key name
398          * The internal cursor (row counter) is incremented by one.
399          * @returns A newly-allocated SQLfieldMap
400          */
401         virtual SQLfieldMap* GetRowMapPtr() = 0;
402         
403         /**
404          * Overloaded function for freeing the lists and maps
405          * returned by GetRowPtr or GetRowMapPtr.
406          * @param fm The SQLfieldMap to free
407          */
408         virtual void Free(SQLfieldMap* fm) = 0;
409
410         /**
411          * Overloaded function for freeing the lists and maps
412          * returned by GetRowPtr or GetRowMapPtr.
413          * @param fl The SQLfieldList to free
414          */
415         virtual void Free(SQLfieldList* fl) = 0;
416 };
417
418 #endif