1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2007 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
14 #ifndef INSPIRCD_SQLAPI_2
15 #define INSPIRCD_SQLAPI_2
23 * This is the voodoo magic which lets us pass multiple
24 * parameters to the SQLrequest constructor... voodoo...
26 #define SQLreq(a, b, c, d, e...) SQLrequest(a, b, c, (SQLquery(d), ##e))
28 /** Identifiers used to identify Request types
30 #define SQLREQID "SQLv2 Request"
31 #define SQLRESID "SQLv2 Result"
32 #define SQLSUCCESS "You shouldn't be reading this (success)"
34 /** Defines the error types which SQLerror may be set to
36 enum SQLerrorNum { NO_ERROR, BAD_DBID, BAD_CONN, QSEND_FAIL, QREPLY_FAIL };
38 /** A list of format parameters for an SQLquery object.
40 typedef std::deque<std::string> ParamL;
42 /** The base class of SQL exceptions
44 class SQLexception : public ModuleException
47 SQLexception(const std::string &reason) : ModuleException(reason)
51 SQLexception() : ModuleException("SQLv2: Undefined exception")
56 /** An exception thrown when a bad column or row name or id is requested
58 class SQLbadColName : public SQLexception
61 SQLbadColName() : SQLexception("SQLv2: Bad column name")
66 /** SQLerror holds the error state of any SQLrequest or SQLresult.
67 * The error string varies from database software to database software
68 * and should be used to display informational error messages to users.
70 class SQLerror : public classbase
79 /** Initialize an SQLerror
80 * @param i The error ID to set
81 * @param s The (optional) error string to set
83 SQLerror(SQLerrorNum i = NO_ERROR, const std::string &s = "")
88 /** Return the ID of the error
95 /** Set the ID of an error
96 * @param i The new error ID to set
97 * @return the ID which was set
99 SQLerrorNum Id(SQLerrorNum i)
105 /** Set the error string for an error
106 * @param s The new error string to set
108 void Str(const std::string &s)
113 /** Return the error string for an error
125 return "Invalid database ID";
127 return "Invalid connection";
129 return "Sending query failed";
131 return "Getting query result failed";
133 return "Unknown error";
138 /** SQLquery provides a way to represent a query string, and its parameters in a type-safe way.
139 * C++ has no native type-safe way of having a variable number of arguments to a function,
140 * the workaround for this isn't easy to describe simply, but in a nutshell what's really
141 * happening when - from the above example - you do this:
143 * SQLrequest foo = SQLreq(this, target, "databaseid", "SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?", "Hello", "42");
145 * what's actually happening is functionally this:
147 * SQLrequest foo = SQLreq(this, target, "databaseid", query("SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?").addparam("Hello").addparam("42"));
149 * with 'query()' returning a reference to an object with a 'addparam()' member function which
150 * in turn returns a reference to that object. There are actually four ways you can create a
151 * SQLrequest..all have their disadvantages and advantages. In the real implementations the
152 * 'query()' function is replaced by the constructor of another class 'SQLquery' which holds
153 * the query string and a ParamL (std::deque<std::string>) of query parameters.
154 * This is essentially the same as the above example except 'addparam()' is replaced by operator,(). The full syntax for this method is:
156 * SQLrequest foo = SQLrequest(this, target, "databaseid", (SQLquery("SELECT.. ?"), parameter, parameter));
161 /** The query 'format string'
164 /** The query parameter list
165 * There should be one parameter for every ? character
166 * within the format string shown above.
170 /** Initialize an SQLquery with a given format string only
172 SQLquery(const std::string &query)
177 /** Initialize an SQLquery with a format string and parameters.
178 * If you provide parameters, you must initialize the list yourself
179 * if you choose to do it via this method, using std::deque::push_back().
181 SQLquery(const std::string &query, const ParamL ¶ms)
182 : q(query), p(params)
186 /** An overloaded operator for pushing parameters onto the parameter list
188 SQLquery& operator,(const std::string &foo)
194 /** An overloaded operator for pushing parameters onto the parameter list.
195 * This has higher precedence than 'operator,' and can save on parenthesis.
197 SQLquery& operator%(const std::string &foo)
204 /** SQLrequest is sent to the SQL API to command it to run a query and return the result.
205 * You must instantiate this object with a valid SQLquery object and its parameters, then
206 * send it using its Send() method to the module providing the 'SQL' feature. To find this
207 * module, use Server::FindFeature().
209 class SQLrequest : public Request
212 /** The fully parsed and expanded query string
213 * This is initialized from the SQLquery parameter given in the constructor.
216 /** The database ID to apply the request to
219 /** True if this is a priority query.
220 * Priority queries may 'queue jump' in the request queue.
223 /** The query ID, assigned by the SQL api.
224 * After your request is processed, this will
225 * be initialized for you by the API to a valid request ID,
226 * except in the case of an error.
229 /** If an error occured, error.id will be any other value than NO_ERROR.
233 /** Initialize an SQLrequest.
236 * SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors VALUES('','?')", nick);
238 * @param s A pointer to the sending module, where the result should be routed
239 * @param d A pointer to the receiving module, identified as implementing the 'SQL' feature
240 * @param databaseid The database ID to perform the query on. This must match a valid
241 * database ID from the configuration of the SQL module.
242 * @param q A properly initialized SQLquery object.
244 SQLrequest(Module* s, Module* d, const std::string &databaseid, const SQLquery &q)
245 : Request(s, d, SQLREQID), query(q), dbid(databaseid), pri(false), id(0)
249 /** Set the priority of a request.
251 void Priority(bool p = true)
256 /** Set the source of a request. You should not need to use this method.
258 void SetSource(Module* mod)
265 * This class contains a field's data plus a way to determine if the field
266 * is NULL or not without having to mess around with NULL pointers.
277 * If the field was null
281 /** Initialize an SQLfield
283 SQLfield(const std::string &data = "", bool n = false)
290 /** A list of items which make up a row of a result or table (tuple)
291 * This does not include field names.
293 typedef std::vector<SQLfield> SQLfieldList;
294 /** A list of items which make up a row of a result or table (tuple)
295 * This also includes the field names.
297 typedef std::map<std::string, SQLfield> SQLfieldMap;
299 /** SQLresult is a reply to a previous query.
300 * If you send a query to the SQL api, the response will arrive at your
301 * OnRequest method of your module at some later time, depending on the
302 * congestion of the SQL server and complexity of the query. The ID of
303 * this result will match the ID assigned to your original request.
304 * SQLresult contains its own internal cursor (row counter) which is
305 * incremented with each method call which retrieves a single row.
307 class SQLresult : public Request
310 /** The original query string passed initially to the SQL API
313 /** The database ID the query was executed on
317 * The error (if any) which occured.
318 * If an error occured the value of error.id will be any
319 * other value than NO_ERROR.
323 * This will match query ID you were given when sending
324 * the request at an earlier time.
328 /** Used by the SQL API to instantiate an SQLrequest
330 SQLresult(Module* s, Module* d, unsigned long i)
331 : Request(s, d, SQLRESID), id(i)
336 * Return the number of rows in the result
337 * Note that if you have perfomed an INSERT
338 * or UPDATE query or other query which will
339 * not return rows, this will return the
340 * number of affected rows, and SQLresult::Cols()
341 * will contain 0. In this case you SHOULD NEVER
342 * access any of the result set rows, as there arent any!
343 * @returns Number of rows in the result set.
345 virtual int Rows() = 0;
348 * Return the number of columns in the result.
349 * If you performed an UPDATE or INSERT which
350 * does not return a dataset, this value will
352 * @returns Number of columns in the result set.
354 virtual int Cols() = 0;
357 * Get a string name of the column by an index number
358 * @param column The id number of a column
359 * @returns The column name associated with the given ID
361 virtual std::string ColName(int column) = 0;
364 * Get an index number for a column from a string name.
365 * An exception of type SQLbadColName will be thrown if
366 * the name given is invalid.
367 * @param column The column name to get the ID of
368 * @returns The ID number of the column provided
370 virtual int ColNum(const std::string &column) = 0;
373 * Get a string value in a given row and column
374 * This does not effect the internal cursor.
375 * @returns The value stored at [row,column] in the table
377 virtual SQLfield GetValue(int row, int column) = 0;
380 * Return a list of values in a row, this should
381 * increment an internal counter so you can repeatedly
382 * call it until it returns an empty vector.
383 * This returns a reference to an internal object,
384 * the same object is used for all calls to this function
385 * and therefore the return value is only valid until
386 * you call this function again. It is also invalid if
387 * the SQLresult object is destroyed.
388 * The internal cursor (row counter) is incremented by one.
389 * @returns A reference to the current row's SQLfieldList
391 virtual SQLfieldList& GetRow() = 0;
394 * As above, but return a map indexed by key name.
395 * The internal cursor (row counter) is incremented by one.
396 * @returns A reference to the current row's SQLfieldMap
398 virtual SQLfieldMap& GetRowMap() = 0;
401 * Like GetRow(), but returns a pointer to a dynamically
402 * allocated object which must be explicitly freed. For
403 * portability reasons this must be freed with SQLresult::Free()
404 * The internal cursor (row counter) is incremented by one.
405 * @returns A newly-allocated SQLfieldList
407 virtual SQLfieldList* GetRowPtr() = 0;
410 * As above, but return a map indexed by key name
411 * The internal cursor (row counter) is incremented by one.
412 * @returns A newly-allocated SQLfieldMap
414 virtual SQLfieldMap* GetRowMapPtr() = 0;
417 * Overloaded function for freeing the lists and maps
418 * returned by GetRowPtr or GetRowMapPtr.
419 * @param fm The SQLfieldMap to free
421 virtual void Free(SQLfieldMap* fm) = 0;
424 * Overloaded function for freeing the lists and maps
425 * returned by GetRowPtr or GetRowMapPtr.
426 * @param fl The SQLfieldList to free
428 virtual void Free(SQLfieldList* fl) = 0;