]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/extra/m_mysql.cpp
Merge pull request #1337 from SaberUK/master+merge
[user/henk/code/inspircd.git] / src / modules / extra / m_mysql.cpp
index 08ec93cf2b324313f7fc2b13ee44bef8cb7770fe..39b0c369d797e0baa9982a3cefdc5676f62f0d97 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+/// $CompilerFlags: execute("mysql_config --include" "MYSQL_CXXFLAGS")
+/// $LinkerFlags: execute("mysql_config --libs_r" "MYSQL_LDFLAGS" "-lmysqlclient")
 
-/* Stop mysql wanting to use long long */
-#define NO_CLIENT_LONG_LONG
+/// $PackageInfo: require_system("centos" "6.0" "6.99") mysql-devel
+/// $PackageInfo: require_system("centos" "7.0") mariadb-devel
+/// $PackageInfo: require_system("darwin") mysql-connector-c
+/// $PackageInfo: require_system("ubuntu") libmysqlclient-dev
+
+
+// Fix warnings about the use of `long long` on C++03.
+#if defined __clang__
+# pragma clang diagnostic ignored "-Wc++11-long-long"
+#elif defined __GNUC__
+# pragma GCC diagnostic ignored "-Wlong-long"
+#endif
 
 #include "inspircd.h"
 #include <mysql.h>
-#include "sql.h"
+#include "modules/sql.h"
 
 #ifdef _WIN32
-# pragma comment(lib, "mysqlclient.lib")
-# pragma comment(lib, "advapi32.lib")
-# pragma comment(linker, "/NODEFAULTLIB:LIBCMT")
+# pragma comment(lib, "libmysql.lib")
 #endif
 
 /* VERSION 3 API: With nonblocking (threaded) requests */
 
-/* $ModDesc: SQL Service Provider module for all other m_sql* modules */
-/* $CompileFlags: exec("mysql_config --include") */
-/* $LinkerFlags: exec("mysql_config --libs_r") rpath("mysql_config --libs_r") */
-
 /* THE NONBLOCKING MYSQL API!
  *
  * MySQL provides no nonblocking (asyncronous) API of its own, and its developers recommend
@@ -92,7 +98,7 @@ struct RQueueItem
        RQueueItem(SQLQuery* Q, MySQLresult* R) : q(Q), r(R) {}
 };
 
-typedef std::map<std::string, SQLConnection*> ConnMap;
+typedef insp::flat_map<std::string, SQLConnection*> ConnMap;
 typedef std::deque<QQueueItem> QueryQueue;
 typedef std::deque<RQueueItem> ResultQueue;
 
@@ -107,11 +113,11 @@ class ModuleSQL : public Module
        ConnMap connections; // main thread only
 
        ModuleSQL();
-       void init();
+       void init() CXX11_OVERRIDE;
        ~ModuleSQL();
-       void OnRehash(User* user);
-       void OnUnloadModule(Module* mod);
-       Version GetVersion();
+       void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE;
+       void OnUnloadModule(Module* mod) CXX11_OVERRIDE;
+       Version GetVersion() CXX11_OVERRIDE;
 };
 
 class DispatcherThread : public SocketThread
@@ -121,8 +127,8 @@ class DispatcherThread : public SocketThread
  public:
        DispatcherThread(ModuleSQL* CreatorModule) : Parent(CreatorModule) { }
        ~DispatcherThread() { }
-       virtual void Run();
-       virtual void OnNotify();
+       void Run();
+       void OnNotify();
 };
 
 #if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID<32224
@@ -180,7 +186,6 @@ class MySQLresult : public SQLResult
                                rows++;
                        }
                        mysql_free_result(res);
-                       res = NULL;
                }
        }
 
@@ -189,21 +194,17 @@ class MySQLresult : public SQLResult
 
        }
 
-       ~MySQLresult()
-       {
-       }
-
-       virtual int Rows()
+       int Rows()
        {
                return rows;
        }
 
-       virtual void GetCols(std::vector<std::string>& result)
+       void GetCols(std::vector<std::string>& result)
        {
                result.assign(colnames.begin(), colnames.end());
        }
 
-       virtual SQLEntry GetValue(int row, int column)
+       SQLEntry GetValue(int row, int column)
        {
                if ((row >= 0) && (row < rows) && (column >= 0) && (column < (int)fieldlists[row].size()))
                {
@@ -212,7 +213,7 @@ class MySQLresult : public SQLResult
                return SQLEntry();
        }
 
-       virtual bool GetRow(SQLEntries& result)
+       bool GetRow(SQLEntries& result)
        {
                if (currentrow < rows)
                {
@@ -263,6 +264,12 @@ class SQLConnection : public SQLProvider
                bool rv = mysql_real_connect(connection, host.c_str(), user.c_str(), pass.c_str(), dbname.c_str(), port, NULL, 0);
                if (!rv)
                        return rv;
+
+               // Enable character set settings
+               std::string charset = config->getString("charset");
+               if ((!charset.empty()) && (mysql_set_character_set(connection, charset.c_str())))
+                       ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "WARNING: Could not set character set to \"%s\"", charset.c_str());
+
                std::string initquery;
                if (config->readString("initialquery", initquery))
                {
@@ -333,10 +340,15 @@ class SQLConnection : public SQLProvider
                                if (param < p.size())
                                {
                                        std::string parm = p[param++];
-                                       char buffer[MAXBUF];
-                                       mysql_escape_string(buffer, parm.c_str(), parm.length());
+                                       // In the worst case, each character may need to be encoded as using two bytes,
+                                       // and one byte is the terminating null
+                                       std::vector<char> buffer(parm.length() * 2 + 1);
+
+                                       // The return value of mysql_escape_string() is the length of the encoded string,
+                                       // not including the terminating null
+                                       unsigned long escapedsize = mysql_escape_string(&buffer[0], parm.c_str(), parm.length());
 //                                     mysql_real_escape_string(connection, queryend, paramscopy[paramnum].c_str(), paramscopy[paramnum].length());
-                                       res.append(buffer);
+                                       res.append(&buffer[0], escapedsize);
                                }
                        }
                }
@@ -362,9 +374,10 @@ class SQLConnection : public SQLProvider
                                if (it != p.end())
                                {
                                        std::string parm = it->second;
-                                       char buffer[MAXBUF];
-                                       mysql_escape_string(buffer, parm.c_str(), parm.length());
-                                       res.append(buffer);
+                                       // NOTE: See above
+                                       std::vector<char> buffer(parm.length() * 2 + 1);
+                                       unsigned long escapedsize = mysql_escape_string(&buffer[0], parm.c_str(), parm.length());
+                                       res.append(&buffer[0], escapedsize);
                                }
                        }
                }
@@ -380,12 +393,7 @@ ModuleSQL::ModuleSQL()
 void ModuleSQL::init()
 {
        Dispatcher = new DispatcherThread(this);
-       ServerInstance->Threads->Start(Dispatcher);
-
-       Implementation eventlist[] = { I_OnRehash, I_OnUnloadModule };
-       ServerInstance->Modules->Attach(eventlist, this, 2);
-
-       OnRehash(NULL);
+       ServerInstance->Threads.Start(Dispatcher);
 }
 
 ModuleSQL::~ModuleSQL()
@@ -402,7 +410,7 @@ ModuleSQL::~ModuleSQL()
        }
 }
 
-void ModuleSQL::OnRehash(User* user)
+void ModuleSQL::ReadConfig(ConfigStatus& status)
 {
        ConnMap conns;
        ConfigTagList tags = ServerInstance->Config->ConfTags("database");
@@ -435,13 +443,14 @@ void ModuleSQL::OnRehash(User* user)
                i->second->lock.Lock();
                i->second->lock.Unlock();
                // now remove all active queries to this DB
-               for(unsigned int j = qq.size() - 1; j >= 0; j--)
+               for (size_t j = qq.size(); j > 0; j--)
                {
-                       if (qq[j].c == i->second)
+                       size_t k = j - 1;
+                       if (qq[k].c == i->second)
                        {
-                               qq[j].q->OnError(err);
-                               delete qq[j].q;
-                               qq.erase(qq.begin() + j);
+                               qq[k].q->OnError(err);
+                               delete qq[k].q;
+                               qq.erase(qq.begin() + k);
                        }
                }
                // finally, nuke the connection