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