]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/extra/m_pgsql.cpp
Merge tag 'v2.0.27' into master.
[user/henk/code/inspircd.git] / src / modules / extra / m_pgsql.cpp
index 1ed5be6f0dfbc776e9be72ebb740e7a2f5e1916d..bb727b623ea504dd4d3dbd4a874fd59e61531702 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+/// $CompilerFlags: -Iexecute("pg_config --includedir" "POSTGRESQL_INCLUDE_DIR")
+/// $LinkerFlags: -Lexecute("pg_config --libdir" "POSTGRESQL_LIBRARY_DIR") -lpq
+
+/// $PackageInfo: require_system("centos") postgresql-devel
+/// $PackageInfo: require_system("darwin") postgresql
+/// $PackageInfo: require_system("debian") libpq-dev
+/// $PackageInfo: require_system("ubuntu") libpq-dev
+
 
 #include "inspircd.h"
 #include <cstdlib>
-#include <sstream>
 #include <libpq-fe.h>
 #include "modules/sql.h"
 
-/* $CompileFlags: -Iexec("pg_config --includedir") eval("my $s = `pg_config --version`;$s =~ /^.*?(\d+)\.(\d+)\.(\d+).*?$/;my $v = hex(sprintf("0x%02x%02x%02x", $1, $2, $3));print "-DPGSQL_HAS_ESCAPECONN" if(($v >= 0x080104) || ($v >= 0x07030F && $v < 0x070400) || ($v >= 0x07040D && $v < 0x080000) || ($v >= 0x080008 && $v < 0x080100));") */
-/* $LinkerFlags: -Lexec("pg_config --libdir") -lpq */
-
 /* SQLConn rewritten by peavey to
  * use EventHandler instead of
  * BufferedSocket. This is much neater
@@ -42,7 +46,7 @@
 class SQLConn;
 class ModulePgSQL;
 
-typedef std::map<std::string, SQLConn*> ConnMap;
+typedef insp::flat_map<std::string, SQLConn*> ConnMap;
 
 /* CREAD,      Connecting and wants read event
  * CWRITE,     Connecting and wants write event
@@ -58,17 +62,17 @@ class ReconnectTimer : public Timer
  private:
        ModulePgSQL* mod;
  public:
-       ReconnectTimer(ModulePgSQL* m) : Timer(5, ServerInstance->Time(), false), mod(m)
+       ReconnectTimer(ModulePgSQL* m) : Timer(5, false), mod(m)
        {
        }
-       bool Tick(time_t TIME);
+       bool Tick(time_t TIME) CXX11_OVERRIDE;
 };
 
 struct QueueItem
 {
-       SQLQuery* c;
+       SQL::Query* c;
        std::string q;
-       QueueItem(SQLQuery* C, const std::string& Q) : c(C), q(Q) {}
+       QueueItem(SQL::Query* C, const std::string& Q) : c(C), q(Q) {}
 };
 
 /** PgSQLresult is a subclass of the mostly-pure-virtual class SQLresult.
@@ -78,11 +82,21 @@ struct QueueItem
  * data is passes to the module nearly as directly as if it was using the API directly itself.
  */
 
-class PgSQLresult : public SQLResult
+class PgSQLresult : public SQL::Result
 {
        PGresult* res;
        int currentrow;
        int rows;
+       std::vector<std::string> colnames;
+
+       void getColNames()
+       {
+               colnames.resize(PQnfields(res));
+               for(unsigned int i=0; i < colnames.size(); i++)
+               {
+                       colnames[i] = PQfname(res, i);
+               }
+       }
  public:
        PgSQLresult(PGresult* result) : res(result), currentrow(0)
        {
@@ -96,30 +110,44 @@ class PgSQLresult : public SQLResult
                PQclear(res);
        }
 
-       int Rows()
+       int Rows() CXX11_OVERRIDE
        {
                return rows;
        }
 
-       void GetCols(std::vector<std::string>& result)
+       void GetCols(std::vector<std::string>& result) CXX11_OVERRIDE
+       {
+               if (colnames.empty())
+                       getColNames();
+               result = colnames;
+       }
+
+       bool HasColumn(const std::string& column, size_t& index) CXX11_OVERRIDE
        {
-               result.resize(PQnfields(res));
-               for(unsigned int i=0; i < result.size(); i++)
+               if (colnames.empty())
+                       getColNames();
+
+               for (size_t i = 0; i < colnames.size(); ++i)
                {
-                       result[i] = PQfname(res, i);
+                       if (colnames[i] == column)
+                       {
+                               index = i;
+                               return true;
+                       }
                }
+               return false;
        }
 
-       SQLEntry GetValue(int row, int column)
+       SQL::Field GetValue(int row, int column)
        {
                char* v = PQgetvalue(res, row, column);
                if (!v || PQgetisnull(res, row, column))
-                       return SQLEntry();
+                       return SQL::Field();
 
-               return SQLEntry(std::string(v, PQgetlength(res, row, column)));
+               return SQL::Field(std::string(v, PQgetlength(res, row, column)));
        }
 
-       bool GetRow(SQLEntries& result)
+       bool GetRow(SQL::Row& result) CXX11_OVERRIDE
        {
                if (currentrow >= PQntuples(res))
                        return false;
@@ -137,7 +165,7 @@ class PgSQLresult : public SQLResult
 
 /** SQLConn represents one SQL session.
  */
-class SQLConn : public SQLProvider, public EventHandler
+class SQLConn : public SQL::Provider, public EventHandler
 {
  public:
        reference<ConfigTag> conf;      /* The <database> entry */
@@ -147,7 +175,7 @@ class SQLConn : public SQLProvider, public EventHandler
        QueueItem               qinprog;        /* If there is currently a query in progress */
 
        SQLConn(Module* Creator, ConfigTag* tag)
-       : SQLProvider(Creator, "SQL/" + tag->getString("id")), conf(tag), sql(NULL), status(CWRITE), qinprog(NULL, "")
+       : SQL::Provider(Creator, "SQL/" + tag->getString("id")), conf(tag), sql(NULL), status(CWRITE), qinprog(NULL, "")
        {
                if (!DoConnect())
                {
@@ -156,16 +184,16 @@ class SQLConn : public SQLProvider, public EventHandler
                }
        }
 
-       CullResult cull()
+       CullResult cull() CXX11_OVERRIDE
        {
-               this->SQLProvider::cull();
+               this->SQL::Provider::cull();
                ServerInstance->Modules->DelService(*this);
                return this->EventHandler::cull();
        }
 
        ~SQLConn()
        {
-               SQLerror err(SQL_BAD_DBID);
+               SQL::Error err(SQL::BAD_DBID);
                if (qinprog.c)
                {
                        qinprog.c->OnError(err);
@@ -173,24 +201,25 @@ class SQLConn : public SQLProvider, public EventHandler
                }
                for(std::deque<QueueItem>::iterator i = queue.begin(); i != queue.end(); i++)
                {
-                       SQLQuery* q = i->c;
+                       SQL::Query* q = i->c;
                        q->OnError(err);
                        delete q;
                }
        }
 
-       void HandleEvent(EventType et, int errornum)
+       void OnEventHandlerRead() CXX11_OVERRIDE
        {
-               switch (et)
-               {
-                       case EVENT_READ:
-                       case EVENT_WRITE:
-                               DoEvent();
-                       break;
+               DoEvent();
+       }
 
-                       case EVENT_ERROR:
-                               DelayReconnect();
-               }
+       void OnEventHandlerWrite() CXX11_OVERRIDE
+       {
+               DoEvent();
+       }
+
+       void OnEventHandlerError(int errornum) CXX11_OVERRIDE
+       {
+               DelayReconnect();
        }
 
        std::string GetDSN()
@@ -241,7 +270,7 @@ class SQLConn : public SQLProvider, public EventHandler
                if(this->fd <= -1)
                        return false;
 
-               if (!ServerInstance->SE->AddFd(this, FD_WANT_NO_WRITE | FD_WANT_NO_READ))
+               if (!SocketEngine::AddFd(this, FD_WANT_NO_WRITE | FD_WANT_NO_READ))
                {
                        ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Couldn't add pgsql socket to socket engine");
                        return false;
@@ -256,17 +285,17 @@ class SQLConn : public SQLProvider, public EventHandler
                switch(PQconnectPoll(sql))
                {
                        case PGRES_POLLING_WRITING:
-                               ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_WRITE | FD_WANT_NO_READ);
+                               SocketEngine::ChangeEventMask(this, FD_WANT_POLL_WRITE | FD_WANT_NO_READ);
                                status = CWRITE;
                                return true;
                        case PGRES_POLLING_READING:
-                               ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+                               SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
                                status = CREAD;
                                return true;
                        case PGRES_POLLING_FAILED:
                                return false;
                        case PGRES_POLLING_OK:
-                               ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+                               SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
                                status = WWRITE;
                                DoConnectedPoll();
                        default:
@@ -315,7 +344,7 @@ restart:
                                        case PGRES_BAD_RESPONSE:
                                        case PGRES_FATAL_ERROR:
                                        {
-                                               SQLerror err(SQL_QREPLY_FAIL, PQresultErrorMessage(result));
+                                               SQL::Error err(SQL::QREPLY_FAIL, PQresultErrorMessage(result));
                                                qinprog.c->OnError(err);
                                                break;
                                        }
@@ -349,17 +378,17 @@ restart:
                switch(PQresetPoll(sql))
                {
                        case PGRES_POLLING_WRITING:
-                               ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_WRITE | FD_WANT_NO_READ);
+                               SocketEngine::ChangeEventMask(this, FD_WANT_POLL_WRITE | FD_WANT_NO_READ);
                                status = CWRITE;
                                return DoPoll();
                        case PGRES_POLLING_READING:
-                               ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+                               SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
                                status = CREAD;
                                return true;
                        case PGRES_POLLING_FAILED:
                                return false;
                        case PGRES_POLLING_OK:
-                               ServerInstance->SE->ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
+                               SocketEngine::ChangeEventMask(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE);
                                status = WWRITE;
                                DoConnectedPoll();
                        default:
@@ -385,7 +414,7 @@ restart:
                }
        }
 
-       void submit(SQLQuery *req, const std::string& q)
+       void Submit(SQL::Query *req, const std::string& q) CXX11_OVERRIDE
        {
                if (qinprog.q.empty())
                {
@@ -398,7 +427,7 @@ restart:
                }
        }
 
-       void submit(SQLQuery *req, const std::string& q, const ParamL& p)
+       void Submit(SQL::Query *req, const std::string& q, const SQL::ParamList& p) CXX11_OVERRIDE
        {
                std::string res;
                unsigned int param = 0;
@@ -412,22 +441,18 @@ restart:
                                {
                                        std::string parm = p[param++];
                                        std::vector<char> buffer(parm.length() * 2 + 1);
-#ifdef PGSQL_HAS_ESCAPECONN
                                        int error;
                                        size_t escapedsize = PQescapeStringConn(sql, &buffer[0], parm.data(), parm.length(), &error);
                                        if (error)
                                                ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Apparently PQescapeStringConn() failed");
-#else
-                                       size_t escapedsize = PQescapeString(&buffer[0], parm.data(), parm.length());
-#endif
                                        res.append(&buffer[0], escapedsize);
                                }
                        }
                }
-               submit(req, res);
+               Submit(req, res);
        }
 
-       void submit(SQLQuery *req, const std::string& q, const ParamM& p)
+       void Submit(SQL::Query *req, const std::string& q, const SQL::ParamMap& p) CXX11_OVERRIDE
        {
                std::string res;
                for(std::string::size_type i = 0; i < q.length(); i++)
@@ -442,24 +467,20 @@ restart:
                                        field.push_back(q[i++]);
                                i--;
 
-                               ParamM::const_iterator it = p.find(field);
+                               SQL::ParamMap::const_iterator it = p.find(field);
                                if (it != p.end())
                                {
                                        std::string parm = it->second;
                                        std::vector<char> buffer(parm.length() * 2 + 1);
-#ifdef PGSQL_HAS_ESCAPECONN
                                        int error;
                                        size_t escapedsize = PQescapeStringConn(sql, &buffer[0], parm.data(), parm.length(), &error);
                                        if (error)
                                                ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Apparently PQescapeStringConn() failed");
-#else
-                                       size_t escapedsize = PQescapeString(&buffer[0], parm.data(), parm.length());
-#endif
                                        res.append(&buffer[0], escapedsize);
                                }
                        }
                }
-               submit(req, res);
+               Submit(req, res);
        }
 
        void DoQuery(const QueueItem& req)
@@ -467,7 +488,7 @@ restart:
                if (status != WREAD && status != WWRITE)
                {
                        // whoops, not connected...
-                       SQLerror err(SQL_BAD_CONN);
+                       SQL::Error err(SQL::BAD_CONN);
                        req.c->OnError(err);
                        delete req.c;
                        return;
@@ -479,7 +500,7 @@ restart:
                }
                else
                {
-                       SQLerror err(SQL_QSEND_FAIL, PQerrorMessage(sql));
+                       SQL::Error err(SQL::QSEND_FAIL, PQerrorMessage(sql));
                        req.c->OnError(err);
                        delete req.c;
                }
@@ -487,7 +508,7 @@ restart:
 
        void Close()
        {
-               ServerInstance->SE->DelFd(this);
+               SocketEngine::DelFd(this);
 
                if(sql)
                {
@@ -525,7 +546,7 @@ class ModulePgSQL : public Module
                ConfigTagList tags = ServerInstance->Config->ConfTags("database");
                for(ConfigIter i = tags.first; i != tags.second; i++)
                {
-                       if (i->second->getString("module", "pgsql") != "pgsql")
+                       if (!stdalgo::string::equalsci(i->second->getString("module"), "pgsql"))
                                continue;
                        std::string id = i->second->getString("id");
                        ConnMap::iterator curr = connections.find(id);
@@ -557,7 +578,7 @@ class ModulePgSQL : public Module
 
        void OnUnloadModule(Module* mod) CXX11_OVERRIDE
        {
-               SQLerror err(SQL_BAD_DBID);
+               SQL::Error err(SQL::BAD_DBID);
                for(ConnMap::iterator i = connections.begin(); i != connections.end(); i++)
                {
                        SQLConn* conn = i->second;
@@ -570,7 +591,7 @@ class ModulePgSQL : public Module
                        std::deque<QueueItem>::iterator j = conn->queue.begin();
                        while (j != conn->queue.end())
                        {
-                               SQLQuery* q = j->c;
+                               SQL::Query* q = j->c;
                                if (q->creator == mod)
                                {
                                        q->OnError(err);
@@ -593,6 +614,7 @@ bool ReconnectTimer::Tick(time_t time)
 {
        mod->retimer = NULL;
        mod->ReadConf();
+       delete this;
        return false;
 }
 
@@ -607,7 +629,7 @@ void SQLConn::DelayReconnect()
                if (!mod->retimer)
                {
                        mod->retimer = new ReconnectTimer(mod);
-                       ServerInstance->Timers->AddTimer(mod->retimer);
+                       ServerInstance->Timers.AddTimer(mod->retimer);
                }
        }
 }