X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fextra%2Fm_sqlv2.h;h=2e0ab2a1931eaa60777a6026f184667da382a26a;hb=b07868e77c0527642ed72bce84bf5895bf921e87;hp=9c7d1750a718ef667301a40adb53a605a22d698f;hpb=6fd3920871a0cd07dff12c727c94782e7b4aa3be;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/extra/m_sqlv2.h b/src/modules/extra/m_sqlv2.h index 9c7d1750a..2e0ab2a19 100644 --- a/src/modules/extra/m_sqlv2.h +++ b/src/modules/extra/m_sqlv2.h @@ -1,3 +1,16 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2008 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 @@ -6,12 +19,6 @@ #include #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" @@ -30,6 +37,14 @@ typedef std::deque ParamL; */ 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 @@ -37,7 +52,9 @@ class SQLexception : public ModuleException class SQLbadColName : public SQLexception { public: - SQLbadColName() { } + SQLbadColName() : SQLexception("SQLv2: Bad column name") + { + } }; /** SQLerror holds the error state of any SQLrequest or SQLresult. @@ -59,16 +76,16 @@ public: */ 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 @@ -78,7 +95,7 @@ public: id = i; return id; } - + /** Set the error string for an error * @param s The new error string to set */ @@ -86,14 +103,14 @@ public: { str = s; } - + /** Return the error string for an error */ const char* Str() { if(str.length()) return str.c_str(); - + switch(id) { case NO_ERROR: @@ -107,7 +124,7 @@ public: case QREPLY_FAIL: return "Getting query result failed"; default: - return "Unknown error"; + return "Unknown error"; } } }; @@ -117,11 +134,11 @@ public: * 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"); + * SQLrequest foo = SQLrequest(this, target, "databaseid", SQLquery("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")); + * SQLrequest foo = SQLrequest(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 @@ -132,7 +149,7 @@ public: * * SQLrequest foo = SQLrequest(this, target, "databaseid", (SQLquery("SELECT.. ?"), parameter, parameter)); */ -class SQLquery +class SQLquery : public classbase { public: /** The query 'format string' @@ -149,7 +166,6 @@ public: SQLquery(const std::string &query) : q(query) { - log(DEBUG, "SQLquery constructor: %s", q.c_str()); } /** Initialize an SQLquery with a format string and parameters. @@ -159,23 +175,22 @@ public: SQLquery(const std::string &query, const ParamL ¶ms) : q(query), p(params) { - log(DEBUG, "SQLquery constructor with %d params: %s", p.size(), q.c_str()); - } - + } + /** An overloaded operator for pushing parameters onto the parameter list */ - SQLquery& operator,(const std::string &foo) + template SQLquery& operator,(const T &foo) { - p.push_back(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. */ - SQLquery& operator%(const std::string &foo) + template SQLquery& operator%(const T &foo) { - p.push_back(foo); + p.push_back(ConvToStr(foo)); return *this; } }; @@ -208,11 +223,11 @@ public: /** 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); + * SQLrequest req = SQLrequest(MyMod, SQLModule, dbid, SQLquery("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 @@ -221,17 +236,17 @@ public: * @param q A properly initialized SQLquery object. */ SQLrequest(Module* s, Module* d, const std::string &databaseid, const SQLquery &q) - : Request(SQLREQID, s, d), query(q), dbid(databaseid), pri(false), id(0) + : 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) @@ -262,7 +277,7 @@ public: SQLfield(const std::string &data = "", bool n = false) : d(data), null(n) { - + } }; @@ -297,7 +312,7 @@ public: * If an error occured the value of error.id will be any * other value than NO_ERROR. */ - SQLerror error; + SQLerror error; /** * This will match query ID you were given when sending * the request at an earlier time. @@ -307,10 +322,10 @@ public: /** Used by the SQL API to instantiate an SQLrequest */ SQLresult(Module* s, Module* d, unsigned long i) - : Request(SQLRESID, s, d), id(i) + : Request(s, d, SQLRESID), id(i) { } - + /** * Return the number of rows in the result * Note that if you have perfomed an INSERT @@ -322,7 +337,7 @@ public: * @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 @@ -331,14 +346,14 @@ public: * @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 @@ -347,14 +362,14 @@ public: * @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 @@ -368,14 +383,14 @@ public: * @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 @@ -384,14 +399,14 @@ public: * @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. @@ -407,4 +422,178 @@ public: virtual void Free(SQLfieldList* fl) = 0; }; + +/** SQLHost represents a config line and is useful + * for storing in a map and iterating on rehash to see which + * 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 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 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