]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/extra/m_pgsql.cpp
Change modules to use the MODNAME constant when logging.
[user/henk/code/inspircd.git] / src / modules / extra / m_pgsql.cpp
index 735ca2f5aedced6f1d0b5d5535f2964c4381504a..f8889ed634c5bdd45cdf2dcdc05426ed95bdc921 100644 (file)
@@ -1,26 +1,35 @@
-/*       +------------------------------------+
- *       | Inspire Internet Relay Chat Daemon |
- *       +------------------------------------+
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
  *
- *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
- * See: http://wiki.inspircd.org/Credits
+ *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ *   Copyright (C) 2006-2007, 2009 Dennis Friis <peavey@inspircd.org>
+ *   Copyright (C) 2006-2007, 2009 Craig Edwards <craigedwards@brainbox.cc>
+ *   Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
+ *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
+ *   Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com>
  *
- * This program is free but copyrighted software; see
- *            the file COPYING for details.
+ * This file is part of InspIRCd.  InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
  *
- * ---------------------------------------------------
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+
 #include "inspircd.h"
 #include <cstdlib>
 #include <sstream>
 #include <libpq-fe.h>
-#include "sql.h"
+#include "modules/sql.h"
 
-/* $ModDesc: PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API */
 /* $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 */
-/* $ModDep: m_sqlv2.h */
 
 /* SQLConn rewritten by peavey to
  * use EventHandler instead of
@@ -52,9 +61,15 @@ class ReconnectTimer : public Timer
        ReconnectTimer(ModulePgSQL* m) : Timer(5, ServerInstance->Time(), false), mod(m)
        {
        }
-       virtual void Tick(time_t TIME);
+       bool Tick(time_t TIME);
 };
 
+struct QueueItem
+{
+       SQLQuery* c;
+       std::string q;
+       QueueItem(SQLQuery* C, const std::string& Q) : c(C), q(Q) {}
+};
 
 /** PgSQLresult is a subclass of the mostly-pure-virtual class SQLresult.
  * All SQL providers must create their own subclass and define it's methods using that
@@ -81,12 +96,12 @@ class PgSQLresult : public SQLResult
                PQclear(res);
        }
 
-       virtual int Rows()
+       int Rows()
        {
                return rows;
        }
 
-       virtual void GetCols(std::vector<std::string>& result)
+       void GetCols(std::vector<std::string>& result)
        {
                result.resize(PQnfields(res));
                for(unsigned int i=0; i < result.size(); i++)
@@ -95,7 +110,7 @@ class PgSQLresult : public SQLResult
                }
        }
 
-       virtual SQLEntry GetValue(int row, int column)
+       SQLEntry GetValue(int row, int column)
        {
                char* v = PQgetvalue(res, row, column);
                if (!v || PQgetisnull(res, row, column))
@@ -104,7 +119,7 @@ class PgSQLresult : public SQLResult
                return SQLEntry(std::string(v, PQgetlength(res, row, column)));
        }
 
-       virtual bool GetRow(SQLEntries& result)
+       bool GetRow(SQLEntries& result)
        {
                if (currentrow >= PQntuples(res))
                        return false;
@@ -126,17 +141,17 @@ class SQLConn : public SQLProvider, public EventHandler
 {
  public:
        reference<ConfigTag> conf;      /* The <database> entry */
-       std::deque<SQLQuery*> queue;
+       std::deque<QueueItem> queue;
        PGconn*                 sql;            /* PgSQL database connection handle */
        SQLstatus               status;         /* PgSQL database connection status */
-       SQLQuery*               qinprog;        /* If there is currently a query in progress */
+       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)
+       : SQLProvider(Creator, "SQL/" + tag->getString("id")), conf(tag), sql(NULL), status(CWRITE), qinprog(NULL, "")
        {
                if (!DoConnect())
                {
-                       ServerInstance->Logs->Log("m_pgsql",DEFAULT, "WARNING: Could not connect to database " + tag->getString("id")); 
+                       ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not connect to database " + tag->getString("id"));
                        DelayReconnect();
                }
        }
@@ -151,20 +166,20 @@ class SQLConn : public SQLProvider, public EventHandler
        ~SQLConn()
        {
                SQLerror err(SQL_BAD_DBID);
-               if (qinprog)
+               if (qinprog.c)
                {
-                       qinprog->OnError(err);
-                       delete qinprog;
+                       qinprog.c->OnError(err);
+                       delete qinprog.c;
                }
-               for(std::deque<SQLQuery*>::iterator i = queue.begin(); i != queue.end(); i++)
+               for(std::deque<QueueItem>::iterator i = queue.begin(); i != queue.end(); i++)
                {
-                       SQLQuery* q = *i;
+                       SQLQuery* q = i->c;
                        q->OnError(err);
                        delete q;
                }
        }
 
-       virtual void HandleEvent(EventType et, int errornum)
+       void HandleEvent(EventType et, int errornum)
        {
                switch (et)
                {
@@ -228,7 +243,7 @@ class SQLConn : public SQLProvider, public EventHandler
 
                if (!ServerInstance->SE->AddFd(this, FD_WANT_NO_WRITE | FD_WANT_NO_READ))
                {
-                       ServerInstance->Logs->Log("m_pgsql",DEBUG, "BUG: Couldn't add pgsql socket to socket engine");
+                       ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Couldn't add pgsql socket to socket engine");
                        return false;
                }
 
@@ -262,7 +277,7 @@ class SQLConn : public SQLProvider, public EventHandler
        void DoConnectedPoll()
        {
 restart:
-               while (!qinprog && !queue.empty())
+               while (qinprog.q.empty() && !queue.empty())
                {
                        /* There's no query currently in progress, and there's queries in the queue. */
                        DoQuery(queue.front());
@@ -275,7 +290,7 @@ restart:
                        {
                                /* Nothing happens here */
                        }
-                       else if (qinprog)
+                       else if (qinprog.c)
                        {
                                /* Fetch the result.. */
                                PGresult* result = PQgetResult(sql);
@@ -301,18 +316,22 @@ restart:
                                        case PGRES_FATAL_ERROR:
                                        {
                                                SQLerror err(SQL_QREPLY_FAIL, PQresultErrorMessage(result));
-                                               qinprog->OnError(err);
+                                               qinprog.c->OnError(err);
                                                break;
                                        }
                                        default:
                                                /* Other values are not errors */
-                                               qinprog->OnResult(reply);
+                                               qinprog.c->OnResult(reply);
                                }
 
-                               delete qinprog;
-                               qinprog = NULL;
+                               delete qinprog.c;
+                               qinprog = QueueItem(NULL, "");
                                goto restart;
                        }
+                       else
+                       {
+                               qinprog.q.clear();
+                       }
                }
                else
                {
@@ -366,7 +385,20 @@ restart:
                }
        }
 
-       virtual std::string FormatQuery(const std::string& q, const ParamL& p)
+       void submit(SQLQuery *req, const std::string& q)
+       {
+               if (qinprog.q.empty())
+               {
+                       DoQuery(QueueItem(req,q));
+               }
+               else
+               {
+                       // wait your turn.
+                       queue.push_back(QueueItem(req,q));
+               }
+       }
+
+       void submit(SQLQuery *req, const std::string& q, const ParamL& p)
        {
                std::string res;
                unsigned int param = 0;
@@ -376,27 +408,26 @@ restart:
                                res.push_back(q[i]);
                        else
                        {
-                               // TODO numbered parameter support ('?1')
                                if (param < p.size())
                                {
                                        std::string parm = p[param++];
-                                       char buffer[MAXBUF];
+                                       std::vector<char> buffer(parm.length() * 2 + 1);
 #ifdef PGSQL_HAS_ESCAPECONN
                                        int error;
-                                       PQescapeStringConn(sql, buffer, parm.c_str(), parm.length(), &error);
+                                       size_t escapedsize = PQescapeStringConn(sql, &buffer[0], parm.data(), parm.length(), &error);
                                        if (error)
-                                               ServerInstance->Logs->Log("m_pgsql", DEBUG, "BUG: Apparently PQescapeStringConn() failed");
+                                               ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Apparently PQescapeStringConn() failed");
 #else
-                                       PQescapeString         (buffer, parm.c_str(), parm.length());
+                                       size_t escapedsize = PQescapeString(&buffer[0], parm.data(), parm.length());
 #endif
-                                       res.append(buffer);
+                                       res.append(&buffer[0], escapedsize);
                                }
                        }
                }
-               return res;
+               submit(req, res);
        }
 
-       std::string FormatQuery(const std::string& q, const ParamM& p)
+       void submit(SQLQuery *req, const std::string& q, const ParamM& p)
        {
                std::string res;
                for(std::string::size_type i = 0; i < q.length(); i++)
@@ -407,7 +438,7 @@ restart:
                        {
                                std::string field;
                                i++;
-                               while (i < q.length() && isalpha(q[i]))
+                               while (i < q.length() && isalnum(q[i]))
                                        field.push_back(q[i++]);
                                i--;
 
@@ -415,55 +446,42 @@ restart:
                                if (it != p.end())
                                {
                                        std::string parm = it->second;
-                                       char buffer[MAXBUF];
+                                       std::vector<char> buffer(parm.length() * 2 + 1);
 #ifdef PGSQL_HAS_ESCAPECONN
                                        int error;
-                                       PQescapeStringConn(sql, buffer, parm.c_str(), parm.length(), &error);
+                                       size_t escapedsize = PQescapeStringConn(sql, &buffer[0], parm.data(), parm.length(), &error);
                                        if (error)
-                                               ServerInstance->Logs->Log("m_pgsql", DEBUG, "BUG: Apparently PQescapeStringConn() failed");
+                                               ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Apparently PQescapeStringConn() failed");
 #else
-                                       PQescapeString         (buffer, parm.c_str(), parm.length());
+                                       size_t escapedsize = PQescapeString(&buffer[0], parm.data(), parm.length());
 #endif
-                                       res.append(buffer);
+                                       res.append(&buffer[0], escapedsize);
                                }
                        }
                }
-               return res;
-       }
-
-       virtual void submit(SQLQuery *req)
-       {
-               if (qinprog)
-               {
-                       // wait your turn.
-                       queue.push_back(req);
-               }
-               else
-               {
-                       DoQuery(req);
-               }
+               submit(req, res);
        }
 
-       void DoQuery(SQLQuery* req)
+       void DoQuery(const QueueItem& req)
        {
                if (status != WREAD && status != WWRITE)
                {
                        // whoops, not connected...
                        SQLerror err(SQL_BAD_CONN);
-                       req->OnError(err);
-                       delete req;
+                       req.c->OnError(err);
+                       delete req.c;
                        return;
                }
 
-               if(PQsendQuery(sql, req->query.c_str()))
+               if(PQsendQuery(sql, req.q.c_str()))
                {
                        qinprog = req;
                }
                else
                {
                        SQLerror err(SQL_QSEND_FAIL, PQerrorMessage(sql));
-                       req->OnError(err);
-                       delete req;
+                       req.c->OnError(err);
+                       delete req.c;
                }
        }
 
@@ -479,13 +497,6 @@ restart:
        }
 };
 
-class DummyQuery : public SQLQuery
-{
- public:
-       DummyQuery(Module* me) : SQLQuery(me, "") {}
-       void OnResult(SQLResult& result) {}
-};
-
 class ModulePgSQL : public Module
 {
  public:
@@ -493,25 +504,25 @@ class ModulePgSQL : public Module
        ReconnectTimer* retimer;
 
        ModulePgSQL()
+               : retimer(NULL)
        {
        }
 
-       void init()
+       void init() CXX11_OVERRIDE
        {
                ReadConf();
 
                Implementation eventlist[] = { I_OnUnloadModule, I_OnRehash };
-               ServerInstance->Modules->Attach(eventlist, this, 2);
+               ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
        }
 
-       virtual ~ModulePgSQL()
+       ~ModulePgSQL()
        {
-               if (retimer)
-                       ServerInstance->Timers->DelTimer(retimer);
+               delete retimer;
                ClearAllConnections();
        }
 
-       virtual void OnRehash(User* user)
+       void OnRehash(User* user) CXX11_OVERRIDE
        {
                ReadConf();
        }
@@ -552,22 +563,22 @@ class ModulePgSQL : public Module
                connections.clear();
        }
 
-       void OnUnloadModule(Module* mod)
+       void OnUnloadModule(Module* mod) CXX11_OVERRIDE
        {
                SQLerror err(SQL_BAD_DBID);
                for(ConnMap::iterator i = connections.begin(); i != connections.end(); i++)
                {
                        SQLConn* conn = i->second;
-                       if (conn->qinprog && conn->qinprog->creator == mod)
+                       if (conn->qinprog.c && conn->qinprog.c->creator == mod)
                        {
-                               conn->qinprog->OnError(err);
-                               delete conn->qinprog;
-                               conn->qinprog = new DummyQuery(this);
+                               conn->qinprog.c->OnError(err);
+                               delete conn->qinprog.c;
+                               conn->qinprog.c = NULL;
                        }
-                       std::deque<SQLQuery*>::iterator j = conn->queue.begin();
+                       std::deque<QueueItem>::iterator j = conn->queue.begin();
                        while (j != conn->queue.end())
                        {
-                               SQLQuery* q = *j;
+                               SQLQuery* q = j->c;
                                if (q->creator == mod)
                                {
                                        q->OnError(err);
@@ -580,16 +591,17 @@ class ModulePgSQL : public Module
                }
        }
 
-       Version GetVersion()
+       Version GetVersion() CXX11_OVERRIDE
        {
                return Version("PostgreSQL Service Provider module for all other m_sql* modules, uses v2 of the SQL API", VF_VENDOR);
        }
 };
 
-void ReconnectTimer::Tick(time_t time)
+bool ReconnectTimer::Tick(time_t time)
 {
        mod->retimer = NULL;
        mod->ReadConf();
+       return false;
 }
 
 void SQLConn::DelayReconnect()