summaryrefslogtreecommitdiff
path: root/src/modules/extra/m_sqlv2.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/extra/m_sqlv2.h')
-rw-r--r--src/modules/extra/m_sqlv2.h606
1 files changed, 1 insertions, 605 deletions
diff --git a/src/modules/extra/m_sqlv2.h b/src/modules/extra/m_sqlv2.h
index c7f6edbb9..decac4b57 100644
--- a/src/modules/extra/m_sqlv2.h
+++ b/src/modules/extra/m_sqlv2.h
@@ -1,605 +1 @@
-/* +------------------------------------+
- * | Inspire Internet Relay Chat Daemon |
- * +------------------------------------+
- *
- * InspIRCd: (C) 2002-2007 InspIRCd Development Team
- * See: http://www.inspircd.org/wiki/index.php/Credits
- *
- * This program is free but copyrighted software; see
- * the file COPYING for details.
- *
- * ---------------------------------------------------
- */
-
-#ifndef INSPIRCD_SQLAPI_2
-#define INSPIRCD_SQLAPI_2
-
-#include <string>
-#include <deque>
-#include <map>
-#include "modules.h"
-
-/** SQLreq define.
- * This is the voodoo magic which lets us pass multiple
- * parameters to the SQLrequest constructor... voodoo...
- */
-#define SQLreq(a, b, c, d, e...) SQLrequest(a, b, c, (SQLquery(d), ##e))
-
-/** Identifiers used to identify Request types
- */
-#define SQLREQID "SQLv2 Request"
-#define SQLRESID "SQLv2 Result"
-#define SQLSUCCESS "You shouldn't be reading this (success)"
-
-/** Defines the error types which SQLerror may be set to
- */
-enum SQLerrorNum { NO_ERROR, BAD_DBID, BAD_CONN, QSEND_FAIL, QREPLY_FAIL };
-
-/** A list of format parameters for an SQLquery object.
- */
-typedef std::deque<std::string> ParamL;
-
-/** The base class of SQL exceptions
- */
-class SQLexception : public ModuleException
-{
- public:
- SQLexception(const std::string &reason) : ModuleException(reason)
- {
- }
-
- SQLexception() : ModuleException("SQLv2: Undefined exception")
- {
- }
-};
-
-/** An exception thrown when a bad column or row name or id is requested
- */
-class SQLbadColName : public SQLexception
-{
-public:
- SQLbadColName() : SQLexception("SQLv2: Bad column name")
- {
- }
-};
-
-/** SQLerror holds the error state of any SQLrequest or SQLresult.
- * The error string varies from database software to database software
- * and should be used to display informational error messages to users.
- */
-class SQLerror : public classbase
-{
- /** The error id
- */
- SQLerrorNum id;
- /** The error string
- */
- std::string str;
-public:
- /** Initialize an SQLerror
- * @param i The error ID to set
- * @param s The (optional) error string to set
- */
- SQLerror(SQLerrorNum i = NO_ERROR, const std::string &s = "")
- : id(i), str(s)
- {
- }
-
- /** Return the ID of the error
- */
- SQLerrorNum Id()
- {
- return id;
- }
-
- /** Set the ID of an error
- * @param i The new error ID to set
- * @return the ID which was set
- */
- SQLerrorNum Id(SQLerrorNum i)
- {
- id = i;
- return id;
- }
-
- /** Set the error string for an error
- * @param s The new error string to set
- */
- void Str(const std::string &s)
- {
- str = s;
- }
-
- /** Return the error string for an error
- */
- const char* Str()
- {
- if(str.length())
- return str.c_str();
-
- switch(id)
- {
- case NO_ERROR:
- return "No error";
- case BAD_DBID:
- return "Invalid database ID";
- case BAD_CONN:
- return "Invalid connection";
- case QSEND_FAIL:
- return "Sending query failed";
- case QREPLY_FAIL:
- return "Getting query result failed";
- default:
- return "Unknown error";
- }
- }
-};
-
-/** SQLquery provides a way to represent a query string, and its parameters in a type-safe way.
- * C++ has no native type-safe way of having a variable number of arguments to a function,
- * the workaround for this isn't easy to describe simply, but in a nutshell what's really
- * happening when - from the above example - you do this:
- *
- * SQLrequest foo = SQLreq(this, target, "databaseid", "SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?", "Hello", "42");
- *
- * what's actually happening is functionally this:
- *
- * SQLrequest foo = SQLreq(this, target, "databaseid", query("SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?").addparam("Hello").addparam("42"));
- *
- * with 'query()' returning a reference to an object with a 'addparam()' member function which
- * in turn returns a reference to that object. There are actually four ways you can create a
- * SQLrequest..all have their disadvantages and advantages. In the real implementations the
- * 'query()' function is replaced by the constructor of another class 'SQLquery' which holds
- * the query string and a ParamL (std::deque<std::string>) of query parameters.
- * This is essentially the same as the above example except 'addparam()' is replaced by operator,(). The full syntax for this method is:
- *
- * SQLrequest foo = SQLrequest(this, target, "databaseid", (SQLquery("SELECT.. ?"), parameter, parameter));
- */
-class SQLquery : public classbase
-{
-public:
- /** The query 'format string'
- */
- std::string q;
- /** The query parameter list
- * There should be one parameter for every ? character
- * within the format string shown above.
- */
- ParamL p;
-
- /** Initialize an SQLquery with a given format string only
- */
- SQLquery(const std::string &query)
- : q(query)
- {
- }
-
- /** Initialize an SQLquery with a format string and parameters.
- * If you provide parameters, you must initialize the list yourself
- * if you choose to do it via this method, using std::deque::push_back().
- */
- SQLquery(const std::string &query, const ParamL &params)
- : q(query), p(params)
- {
- }
-
- /** An overloaded operator for pushing parameters onto the parameter list
- */
- template<typename T> SQLquery& operator,(const T &foo)
- {
- p.push_back(ConvToStr(foo));
- return *this;
- }
-
- /** An overloaded operator for pushing parameters onto the parameter list.
- * This has higher precedence than 'operator,' and can save on parenthesis.
- */
- template<typename T> SQLquery& operator%(const T &foo)
- {
- p.push_back(ConvToStr(foo));
- return *this;
- }
-};
-
-/** SQLrequest is sent to the SQL API to command it to run a query and return the result.
- * You must instantiate this object with a valid SQLquery object and its parameters, then
- * send it using its Send() method to the module providing the 'SQL' feature. To find this
- * module, use Server::FindFeature().
- */
-class SQLrequest : public Request
-{
-public:
- /** The fully parsed and expanded query string
- * This is initialized from the SQLquery parameter given in the constructor.
- */
- SQLquery query;
- /** The database ID to apply the request to
- */
- std::string dbid;
- /** True if this is a priority query.
- * Priority queries may 'queue jump' in the request queue.
- */
- bool pri;
- /** The query ID, assigned by the SQL api.
- * After your request is processed, this will
- * be initialized for you by the API to a valid request ID,
- * except in the case of an error.
- */
- unsigned long id;
- /** If an error occured, error.id will be any other value than NO_ERROR.
- */
- SQLerror error;
-
- /** Initialize an SQLrequest.
- * For example:
- *
- * SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors VALUES('','?')", nick);
- *
- * @param s A pointer to the sending module, where the result should be routed
- * @param d A pointer to the receiving module, identified as implementing the 'SQL' feature
- * @param databaseid The database ID to perform the query on. This must match a valid
- * database ID from the configuration of the SQL module.
- * @param q A properly initialized SQLquery object.
- */
- SQLrequest(Module* s, Module* d, const std::string &databaseid, const SQLquery &q)
- : Request(s, d, SQLREQID), query(q), dbid(databaseid), pri(false), id(0)
- {
- }
-
- /** Set the priority of a request.
- */
- void Priority(bool p = true)
- {
- pri = p;
- }
-
- /** Set the source of a request. You should not need to use this method.
- */
- void SetSource(Module* mod)
- {
- source = mod;
- }
-};
-
-/**
- * This class contains a field's data plus a way to determine if the field
- * is NULL or not without having to mess around with NULL pointers.
- */
-class SQLfield
-{
-public:
- /**
- * The data itself
- */
- std::string d;
-
- /**
- * If the field was null
- */
- bool null;
-
- /** Initialize an SQLfield
- */
- SQLfield(const std::string &data = "", bool n = false)
- : d(data), null(n)
- {
-
- }
-};
-
-/** A list of items which make up a row of a result or table (tuple)
- * This does not include field names.
- */
-typedef std::vector<SQLfield> SQLfieldList;
-/** A list of items which make up a row of a result or table (tuple)
- * This also includes the field names.
- */
-typedef std::map<std::string, SQLfield> SQLfieldMap;
-
-/** SQLresult is a reply to a previous query.
- * If you send a query to the SQL api, the response will arrive at your
- * OnRequest method of your module at some later time, depending on the
- * congestion of the SQL server and complexity of the query. The ID of
- * this result will match the ID assigned to your original request.
- * SQLresult contains its own internal cursor (row counter) which is
- * incremented with each method call which retrieves a single row.
- */
-class SQLresult : public Request
-{
-public:
- /** The original query string passed initially to the SQL API
- */
- std::string query;
- /** The database ID the query was executed on
- */
- std::string dbid;
- /**
- * The error (if any) which occured.
- * If an error occured the value of error.id will be any
- * other value than NO_ERROR.
- */
- SQLerror error;
- /**
- * This will match query ID you were given when sending
- * the request at an earlier time.
- */
- unsigned long id;
-
- /** Used by the SQL API to instantiate an SQLrequest
- */
- SQLresult(Module* s, Module* d, unsigned long i)
- : Request(s, d, SQLRESID), id(i)
- {
- }
-
- /**
- * Return the number of rows in the result
- * Note that if you have perfomed an INSERT
- * or UPDATE query or other query which will
- * not return rows, this will return the
- * number of affected rows, and SQLresult::Cols()
- * will contain 0. In this case you SHOULD NEVER
- * access any of the result set rows, as there arent any!
- * @returns Number of rows in the result set.
- */
- virtual int Rows() = 0;
-
- /**
- * Return the number of columns in the result.
- * If you performed an UPDATE or INSERT which
- * does not return a dataset, this value will
- * be 0.
- * @returns Number of columns in the result set.
- */
- virtual int Cols() = 0;
-
- /**
- * Get a string name of the column by an index number
- * @param column The id number of a column
- * @returns The column name associated with the given ID
- */
- virtual std::string ColName(int column) = 0;
-
- /**
- * Get an index number for a column from a string name.
- * An exception of type SQLbadColName will be thrown if
- * the name given is invalid.
- * @param column The column name to get the ID of
- * @returns The ID number of the column provided
- */
- virtual int ColNum(const std::string &column) = 0;
-
- /**
- * Get a string value in a given row and column
- * This does not effect the internal cursor.
- * @returns The value stored at [row,column] in the table
- */
- virtual SQLfield GetValue(int row, int column) = 0;
-
- /**
- * Return a list of values in a row, this should
- * increment an internal counter so you can repeatedly
- * call it until it returns an empty vector.
- * This returns a reference to an internal object,
- * the same object is used for all calls to this function
- * and therefore the return value is only valid until
- * you call this function again. It is also invalid if
- * the SQLresult object is destroyed.
- * The internal cursor (row counter) is incremented by one.
- * @returns A reference to the current row's SQLfieldList
- */
- virtual SQLfieldList& GetRow() = 0;
-
- /**
- * As above, but return a map indexed by key name.
- * The internal cursor (row counter) is incremented by one.
- * @returns A reference to the current row's SQLfieldMap
- */
- virtual SQLfieldMap& GetRowMap() = 0;
-
- /**
- * Like GetRow(), but returns a pointer to a dynamically
- * allocated object which must be explicitly freed. For
- * portability reasons this must be freed with SQLresult::Free()
- * The internal cursor (row counter) is incremented by one.
- * @returns A newly-allocated SQLfieldList
- */
- virtual SQLfieldList* GetRowPtr() = 0;
-
- /**
- * As above, but return a map indexed by key name
- * The internal cursor (row counter) is incremented by one.
- * @returns A newly-allocated SQLfieldMap
- */
- virtual SQLfieldMap* GetRowMapPtr() = 0;
-
- /**
- * Overloaded function for freeing the lists and maps
- * returned by GetRowPtr or GetRowMapPtr.
- * @param fm The SQLfieldMap to free
- */
- virtual void Free(SQLfieldMap* fm) = 0;
-
- /**
- * Overloaded function for freeing the lists and maps
- * returned by GetRowPtr or GetRowMapPtr.
- * @param fl The SQLfieldList to free
- */
- virtual void Free(SQLfieldList* fl) = 0;
-};
-
-
-/** SQLHost represents a <database> config line and is useful
- * for storing in a map and iterating on rehash to see which
- * <database> tags was added/removed/unchanged.
- */
-class SQLhost
-{
- public:
- std::string id; /* Database handle id */
- std::string host; /* Database server hostname */
- std::string ip; /* resolved IP, needed for at least pgsql.so */
- unsigned int port; /* Database server port */
- std::string name; /* Database name */
- std::string user; /* Database username */
- std::string pass; /* Database password */
- bool ssl; /* If we should require SSL */
-
- SQLhost()
- {
- }
-
- SQLhost(const std::string& i, const std::string& h, unsigned int p, const std::string& n, const std::string& u, const std::string& pa, bool s)
- : id(i), host(h), port(p), name(n), user(u), pass(pa), ssl(s)
- {
- }
-
- /** Overload this to return a correct Data source Name (DSN) for
- * the current SQL module.
- */
- std::string GetDSN();
-};
-
-/** Overload operator== for two SQLhost objects for easy comparison.
- */
-bool operator== (const SQLhost& l, const SQLhost& r)
-{
- return (l.id == r.id && l.host == r.host && l.port == r.port && l.name == r.name && l.user == l.user && l.pass == r.pass && l.ssl == r.ssl);
-}
-
-
-/** QueryQueue, a queue of queries waiting to be executed.
- * This maintains two queues internally, one for 'priority'
- * queries and one for less important ones. Each queue has
- * new queries appended to it and ones to execute are popped
- * off the front. This keeps them flowing round nicely and no
- * query should ever get 'stuck' for too long. If there are
- * queries in the priority queue they will be executed first,
- * 'unimportant' queries will only be executed when the
- * priority queue is empty.
- *
- * We store lists of SQLrequest's here, by value as we want to avoid storing
- * any data allocated inside the client module (in case that module is unloaded
- * while the query is in progress).
- *
- * Because we want to work on the current SQLrequest in-situ, we need a way
- * of accessing the request we are currently processing, QueryQueue::front(),
- * but that call needs to always return the same request until that request
- * is removed from the queue, this is what the 'which' variable is. New queries are
- * always added to the back of one of the two queues, but if when front()
- * is first called then the priority queue is empty then front() will return
- * a query from the normal queue, but if a query is then added to the priority
- * queue then front() must continue to return the front of the *normal* queue
- * until pop() is called.
- */
-
-class QueryQueue : public classbase
-{
-private:
- typedef std::deque<SQLrequest> ReqDeque;
-
- ReqDeque priority; /* The priority queue */
- ReqDeque normal; /* The 'normal' queue */
- enum { PRI, NOR, NON } which; /* Which queue the currently active element is at the front of */
-
-public:
- QueryQueue()
- : which(NON)
- {
- }
-
- void push(const SQLrequest &q)
- {
- if(q.pri)
- priority.push_back(q);
- else
- normal.push_back(q);
- }
-
- void pop()
- {
- if((which == PRI) && priority.size())
- {
- priority.pop_front();
- }
- else if((which == NOR) && normal.size())
- {
- normal.pop_front();
- }
-
- /* Reset this */
- which = NON;
-
- /* Silently do nothing if there was no element to pop() */
- }
-
- SQLrequest& front()
- {
- switch(which)
- {
- case PRI:
- return priority.front();
- case NOR:
- return normal.front();
- default:
- if(priority.size())
- {
- which = PRI;
- return priority.front();
- }
-
- if(normal.size())
- {
- which = NOR;
- return normal.front();
- }
-
- /* This will probably result in a segfault,
- * but the caller should have checked totalsize()
- * first so..meh - moron :p
- */
-
- return priority.front();
- }
- }
-
- std::pair<int, int> size()
- {
- return std::make_pair(priority.size(), normal.size());
- }
-
- int totalsize()
- {
- return priority.size() + normal.size();
- }
-
- void PurgeModule(Module* mod)
- {
- DoPurgeModule(mod, priority);
- DoPurgeModule(mod, normal);
- }
-
-private:
- void DoPurgeModule(Module* mod, ReqDeque& q)
- {
- for(ReqDeque::iterator iter = q.begin(); iter != q.end(); iter++)
- {
- if(iter->GetSource() == mod)
- {
- if(iter->id == front().id)
- {
- /* It's the currently active query.. :x */
- iter->SetSource(NULL);
- }
- else
- {
- /* It hasn't been executed yet..just remove it */
- iter = q.erase(iter);
- }
- }
- }
- }
-};
-
-
-#endif
+/* +------------------------------------+ * | Inspire Internet Relay Chat Daemon | * +------------------------------------+ * * InspIRCd: (C) 2002-2007 InspIRCd Development Team * See: http://www.inspircd.org/wiki/index.php/Credits * * This program is free but copyrighted software; see * the file COPYING for details. * * --------------------------------------------------- */ #ifndef INSPIRCD_SQLAPI_2 #define INSPIRCD_SQLAPI_2 #include <string> #include <deque> #include <map> #include "modules.h" /** SQLreq define. * This is the voodoo magic which lets us pass multiple * parameters to the SQLrequest constructor... voodoo... */ #define SQLreq(a, b, c, d, e...) SQLrequest(a, b, c, (SQLquery(d), ##e)) /** Identifiers used to identify Request types */ #define SQLREQID "SQLv2 Request" #define SQLRESID "SQLv2 Result" #define SQLSUCCESS "You shouldn't be reading this (success)" /** Defines the error types which SQLerror may be set to */ enum SQLerrorNum { NO_ERROR, BAD_DBID, BAD_CONN, QSEND_FAIL, QREPLY_FAIL }; /** A list of format parameters for an SQLquery object. */ typedef std::deque<std::string> ParamL; /** The base class of SQL exceptions */ class SQLexception : public ModuleException { public: SQLexception(const std::string &reason) : ModuleException(reason) { } SQLexception() : ModuleException("SQLv2: Undefined exception") { } }; /** An exception thrown when a bad column or row name or id is requested */ class SQLbadColName : public SQLexception { public: SQLbadColName() : SQLexception("SQLv2: Bad column name") { } }; /** SQLerror holds the error state of any SQLrequest or SQLresult. * The error string varies from database software to database software * and should be used to display informational error messages to users. */ class SQLerror : public classbase { /** The error id */ SQLerrorNum id; /** The error string */ std::string str; public: /** Initialize an SQLerror * @param i The error ID to set * @param s The (optional) error string to set */ SQLerror(SQLerrorNum i = NO_ERROR, const std::string &s = "") : id(i), str(s) { } /** Return the ID of the error */ SQLerrorNum Id() { return id; } /** Set the ID of an error * @param i The new error ID to set * @return the ID which was set */ SQLerrorNum Id(SQLerrorNum i) { id = i; return id; } /** Set the error string for an error * @param s The new error string to set */ void Str(const std::string &s) { str = s; } /** Return the error string for an error */ const char* Str() { if(str.length()) return str.c_str(); switch(id) { case NO_ERROR: return "No error"; case BAD_DBID: return "Invalid database ID"; case BAD_CONN: return "Invalid connection"; case QSEND_FAIL: return "Sending query failed"; case QREPLY_FAIL: return "Getting query result failed"; default: return "Unknown error"; } } }; /** SQLquery provides a way to represent a query string, and its parameters in a type-safe way. * C++ has no native type-safe way of having a variable number of arguments to a function, * the workaround for this isn't easy to describe simply, but in a nutshell what's really * happening when - from the above example - you do this: * * SQLrequest foo = SQLreq(this, target, "databaseid", "SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?", "Hello", "42"); * * what's actually happening is functionally this: * * SQLrequest foo = SQLreq(this, target, "databaseid", query("SELECT (foo, bar) FROM rawr WHERE foo = '?' AND bar = ?").addparam("Hello").addparam("42")); * * with 'query()' returning a reference to an object with a 'addparam()' member function which * in turn returns a reference to that object. There are actually four ways you can create a * SQLrequest..all have their disadvantages and advantages. In the real implementations the * 'query()' function is replaced by the constructor of another class 'SQLquery' which holds * the query string and a ParamL (std::deque<std::string>) of query parameters. * This is essentially the same as the above example except 'addparam()' is replaced by operator,(). The full syntax for this method is: * * SQLrequest foo = SQLrequest(this, target, "databaseid", (SQLquery("SELECT.. ?"), parameter, parameter)); */ class SQLquery : public classbase { public: /** The query 'format string' */ std::string q; /** The query parameter list * There should be one parameter for every ? character * within the format string shown above. */ ParamL p; /** Initialize an SQLquery with a given format string only */ SQLquery(const std::string &query) : q(query) { } /** Initialize an SQLquery with a format string and parameters. * If you provide parameters, you must initialize the list yourself * if you choose to do it via this method, using std::deque::push_back(). */ SQLquery(const std::string &query, const ParamL &params) : q(query), p(params) { } /** An overloaded operator for pushing parameters onto the parameter list */ template<typename T> SQLquery& operator,(const T &foo) { p.push_back(ConvToStr(foo)); return *this; } /** An overloaded operator for pushing parameters onto the parameter list. * This has higher precedence than 'operator,' and can save on parenthesis. */ template<typename T> SQLquery& operator%(const T &foo) { p.push_back(ConvToStr(foo)); return *this; } }; /** SQLrequest is sent to the SQL API to command it to run a query and return the result. * You must instantiate this object with a valid SQLquery object and its parameters, then * send it using its Send() method to the module providing the 'SQL' feature. To find this * module, use Server::FindFeature(). */ class SQLrequest : public Request { public: /** The fully parsed and expanded query string * This is initialized from the SQLquery parameter given in the constructor. */ SQLquery query; /** The database ID to apply the request to */ std::string dbid; /** True if this is a priority query. * Priority queries may 'queue jump' in the request queue. */ bool pri; /** The query ID, assigned by the SQL api. * After your request is processed, this will * be initialized for you by the API to a valid request ID, * except in the case of an error. */ unsigned long id; /** If an error occured, error.id will be any other value than NO_ERROR. */ SQLerror error; /** Initialize an SQLrequest. * For example: * * SQLrequest req = SQLreq(MyMod, SQLModule, dbid, "INSERT INTO ircd_log_actors VALUES('','?')", nick); * * @param s A pointer to the sending module, where the result should be routed * @param d A pointer to the receiving module, identified as implementing the 'SQL' feature * @param databaseid The database ID to perform the query on. This must match a valid * database ID from the configuration of the SQL module. * @param q A properly initialized SQLquery object. */ SQLrequest(Module* s, Module* d, const std::string &databaseid, const SQLquery &q) : Request(s, d, SQLREQID), query(q), dbid(databaseid), pri(false), id(0) { } /** Set the priority of a request. */ void Priority(bool p = true) { pri = p; } /** Set the source of a request. You should not need to use this method. */ void SetSource(Module* mod) { source = mod; } }; /** * This class contains a field's data plus a way to determine if the field * is NULL or not without having to mess around with NULL pointers. */ class SQLfield { public: /** * The data itself */ std::string d; /** * If the field was null */ bool null; /** Initialize an SQLfield */ SQLfield(const std::string &data = "", bool n = false) : d(data), null(n) { } }; /** A list of items which make up a row of a result or table (tuple) * This does not include field names. */ typedef std::vector<SQLfield> SQLfieldList; /** A list of items which make up a row of a result or table (tuple) * This also includes the field names. */ typedef std::map<std::string, SQLfield> SQLfieldMap; /** SQLresult is a reply to a previous query. * If you send a query to the SQL api, the response will arrive at your * OnRequest method of your module at some later time, depending on the * congestion of the SQL server and complexity of the query. The ID of * this result will match the ID assigned to your original request. * SQLresult contains its own internal cursor (row counter) which is * incremented with each method call which retrieves a single row. */ class SQLresult : public Request { public: /** The original query string passed initially to the SQL API */ std::string query; /** The database ID the query was executed on */ std::string dbid; /** * The error (if any) which occured. * If an error occured the value of error.id will be any * other value than NO_ERROR. */ SQLerror error; /** * This will match query ID you were given when sending * the request at an earlier time. */ unsigned long id; /** Used by the SQL API to instantiate an SQLrequest */ SQLresult(Module* s, Module* d, unsigned long i) : Request(s, d, SQLRESID), id(i) { } /** * Return the number of rows in the result * Note that if you have perfomed an INSERT * or UPDATE query or other query which will * not return rows, this will return the * number of affected rows, and SQLresult::Cols() * will contain 0. In this case you SHOULD NEVER * access any of the result set rows, as there arent any! * @returns Number of rows in the result set. */ virtual int Rows() = 0; /** * Return the number of columns in the result. * If you performed an UPDATE or INSERT which * does not return a dataset, this value will * be 0. * @returns Number of columns in the result set. */ virtual int Cols() = 0; /** * Get a string name of the column by an index number * @param column The id number of a column * @returns The column name associated with the given ID */ virtual std::string ColName(int column) = 0; /** * Get an index number for a column from a string name. * An exception of type SQLbadColName will be thrown if * the name given is invalid. * @param column The column name to get the ID of * @returns The ID number of the column provided */ virtual int ColNum(const std::string &column) = 0; /** * Get a string value in a given row and column * This does not effect the internal cursor. * @returns The value stored at [row,column] in the table */ virtual SQLfield GetValue(int row, int column) = 0; /** * Return a list of values in a row, this should * increment an internal counter so you can repeatedly * call it until it returns an empty vector. * This returns a reference to an internal object, * the same object is used for all calls to this function * and therefore the return value is only valid until * you call this function again. It is also invalid if * the SQLresult object is destroyed. * The internal cursor (row counter) is incremented by one. * @returns A reference to the current row's SQLfieldList */ virtual SQLfieldList& GetRow() = 0; /** * As above, but return a map indexed by key name. * The internal cursor (row counter) is incremented by one. * @returns A reference to the current row's SQLfieldMap */ virtual SQLfieldMap& GetRowMap() = 0; /** * Like GetRow(), but returns a pointer to a dynamically * allocated object which must be explicitly freed. For * portability reasons this must be freed with SQLresult::Free() * The internal cursor (row counter) is incremented by one. * @returns A newly-allocated SQLfieldList */ virtual SQLfieldList* GetRowPtr() = 0; /** * As above, but return a map indexed by key name * The internal cursor (row counter) is incremented by one. * @returns A newly-allocated SQLfieldMap */ virtual SQLfieldMap* GetRowMapPtr() = 0; /** * Overloaded function for freeing the lists and maps * returned by GetRowPtr or GetRowMapPtr. * @param fm The SQLfieldMap to free */ virtual void Free(SQLfieldMap* fm) = 0; /** * Overloaded function for freeing the lists and maps * returned by GetRowPtr or GetRowMapPtr. * @param fl The SQLfieldList to free */ virtual void Free(SQLfieldList* fl) = 0; }; /** SQLHost represents a <database> config line and is useful * for storing in a map and iterating on rehash to see which * <database> tags was added/removed/unchanged. */ class SQLhost { public: std::string id; /* Database handle id */ std::string host; /* Database server hostname */ std::string ip; /* resolved IP, needed for at least pgsql.so */ unsigned int port; /* Database server port */ std::string name; /* Database name */ std::string user; /* Database username */ std::string pass; /* Database password */ bool ssl; /* If we should require SSL */ SQLhost() { } SQLhost(const std::string& i, const std::string& h, unsigned int p, const std::string& n, const std::string& u, const std::string& pa, bool s) : id(i), host(h), port(p), name(n), user(u), pass(pa), ssl(s) { } /** Overload this to return a correct Data source Name (DSN) for * the current SQL module. */ std::string GetDSN(); }; /** Overload operator== for two SQLhost objects for easy comparison. */ bool operator== (const SQLhost& l, const SQLhost& r) { return (l.id == r.id && l.host == r.host && l.port == r.port && l.name == r.name && l.user == l.user && l.pass == r.pass && l.ssl == r.ssl); } /** QueryQueue, a queue of queries waiting to be executed. * This maintains two queues internally, one for 'priority' * queries and one for less important ones. Each queue has * new queries appended to it and ones to execute are popped * off the front. This keeps them flowing round nicely and no * query should ever get 'stuck' for too long. If there are * queries in the priority queue they will be executed first, * 'unimportant' queries will only be executed when the * priority queue is empty. * * We store lists of SQLrequest's here, by value as we want to avoid storing * any data allocated inside the client module (in case that module is unloaded * while the query is in progress). * * Because we want to work on the current SQLrequest in-situ, we need a way * of accessing the request we are currently processing, QueryQueue::front(), * but that call needs to always return the same request until that request * is removed from the queue, this is what the 'which' variable is. New queries are * always added to the back of one of the two queues, but if when front() * is first called then the priority queue is empty then front() will return * a query from the normal queue, but if a query is then added to the priority * queue then front() must continue to return the front of the *normal* queue * until pop() is called. */ class QueryQueue : public classbase { private: typedef std::deque<SQLrequest> ReqDeque; ReqDeque priority; /* The priority queue */ ReqDeque normal; /* The 'normal' queue */ enum { PRI, NOR, NON } which; /* Which queue the currently active element is at the front of */ public: QueryQueue() : which(NON) { } void push(const SQLrequest &q) { if(q.pri) priority.push_back(q); else normal.push_back(q); } void pop() { if((which == PRI) && priority.size()) { priority.pop_front(); } else if((which == NOR) && normal.size()) { normal.pop_front(); } /* Reset this */ which = NON; /* Silently do nothing if there was no element to pop() */ } SQLrequest& front() { switch(which) { case PRI: return priority.front(); case NOR: return normal.front(); default: if(priority.size()) { which = PRI; return priority.front(); } if(normal.size()) { which = NOR; return normal.front(); } /* This will probably result in a segfault, * but the caller should have checked totalsize() * first so..meh - moron :p */ return priority.front(); } } std::pair<int, int> size() { return std::make_pair(priority.size(), normal.size()); } int totalsize() { return priority.size() + normal.size(); } void PurgeModule(Module* mod) { DoPurgeModule(mod, priority); DoPurgeModule(mod, normal); } private: void DoPurgeModule(Module* mod, ReqDeque& q) { for(ReqDeque::iterator iter = q.begin(); iter != q.end(); iter++) { if(iter->GetSource() == mod) { if(iter->id == front().id) { /* It's the currently active query.. :x */ iter->SetSource(NULL); } else { /* It hasn't been executed yet..just remove it */ iter = q.erase(iter); } } } } }; #endif \ No newline at end of file