summaryrefslogtreecommitdiff
path: root/src/modules/extra/m_mysql.cpp
diff options
context:
space:
mode:
authorbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2006-07-21 17:48:46 +0000
committerbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2006-07-21 17:48:46 +0000
commit2010b514a638f43d515e9539ef21015f733ec279 (patch)
treed12e05189ce1dcff675122a59ef0d1a9a2fbf22c /src/modules/extra/m_mysql.cpp
parent6016b09a4ace340e6c1411308ff7135f4ba7e3d1 (diff)
Move this to m_mysql.cpp - dont even bother reading this yet its unchanged from m_sql
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@4476 e03df62e-2008-0410-955e-edbf42e46eb7
Diffstat (limited to 'src/modules/extra/m_mysql.cpp')
-rw-r--r--src/modules/extra/m_mysql.cpp400
1 files changed, 400 insertions, 0 deletions
diff --git a/src/modules/extra/m_mysql.cpp b/src/modules/extra/m_mysql.cpp
new file mode 100644
index 000000000..654d84191
--- /dev/null
+++ b/src/modules/extra/m_mysql.cpp
@@ -0,0 +1,400 @@
+/* +------------------------------------+
+ * | Inspire Internet Relay Chat Daemon |
+ * +------------------------------------+
+ *
+ * InspIRCd is copyright (C) 2002-2004 ChatSpike-Dev.
+ * E-mail:
+ * <brain@chatspike.net>
+ * <Craig@chatspike.net>
+ *
+ * Written by Craig Edwards, Craig McLure, and others.
+ * This program is free but copyrighted software; see
+ * the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+using namespace std;
+
+#include <stdio.h>
+#include <string>
+#include <mysql.h>
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "helperfuncs.h"
+#include "m_sql.h"
+
+/* $ModDesc: SQL Service Provider module for all other m_sql* modules */
+/* $CompileFlags: `mysql_config --include` */
+/* $LinkerFlags: `mysql_config --libs` `perl ../mysql_rpath.pl` */
+
+/** SQLConnection represents one mysql session.
+ * Each session has its own persistent connection to the database.
+ */
+
+#if !defined(MYSQL_VERSION_ID) || MYSQL_VERSION_ID<32224
+#define mysql_field_count mysql_num_fields
+#endif
+
+class SQLConnection : public classbase
+{
+ protected:
+
+ MYSQL connection;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ std::string host;
+ std::string user;
+ std::string pass;
+ std::string db;
+ std::map<std::string,std::string> thisrow;
+ bool Enabled;
+ long id;
+
+ public:
+
+ // This constructor creates an SQLConnection object with the given credentials, and creates the underlying
+ // MYSQL struct, but does not connect yet.
+ SQLConnection(std::string thishost, std::string thisuser, std::string thispass, std::string thisdb, long myid)
+ {
+ this->Enabled = true;
+ this->host = thishost;
+ this->user = thisuser;
+ this->pass = thispass;
+ this->db = thisdb;
+ this->id = myid;
+ }
+
+ // This method connects to the database using the credentials supplied to the constructor, and returns
+ // true upon success.
+ bool Connect()
+ {
+ unsigned int timeout = 1;
+ mysql_init(&connection);
+ mysql_options(&connection,MYSQL_OPT_CONNECT_TIMEOUT,(char*)&timeout);
+ return mysql_real_connect(&connection, host.c_str(), user.c_str(), pass.c_str(), db.c_str(), 0, NULL, 0);
+ }
+
+ // This method issues a query that expects multiple rows of results. Use GetRow() and QueryDone() to retrieve
+ // multiple rows.
+ bool QueryResult(std::string query)
+ {
+ if (!CheckConnection()) return false;
+
+ int r = mysql_query(&connection, query.c_str());
+ if (!r)
+ {
+ res = mysql_use_result(&connection);
+ }
+ return (!r);
+ }
+
+ // This method issues a query that just expects a number of 'effected' rows (e.g. UPDATE or DELETE FROM).
+ // the number of effected rows is returned in the return value.
+ long QueryCount(std::string query)
+ {
+ /* If the connection is down, we return a negative value - New to 1.1 */
+ if (!CheckConnection()) return -1;
+
+ int r = mysql_query(&connection, query.c_str());
+ if (!r)
+ {
+ res = mysql_store_result(&connection);
+ unsigned long rows = mysql_affected_rows(&connection);
+ mysql_free_result(res);
+ return rows;
+ }
+ return 0;
+ }
+
+ // This method fetches a row, if available from the database. You must issue a query
+ // using QueryResult() first! The row's values are returned as a map of std::string
+ // where each item is keyed by the column name.
+ std::map<std::string,std::string> GetRow()
+ {
+ thisrow.clear();
+ if (res)
+ {
+ row = mysql_fetch_row(res);
+ if (row)
+ {
+ unsigned int field_count = 0;
+ MYSQL_FIELD *fields = mysql_fetch_fields(res);
+ if(mysql_field_count(&connection) == 0)
+ return thisrow;
+ if (fields && mysql_field_count(&connection))
+ {
+ while (field_count < mysql_field_count(&connection))
+ {
+ std::string a = (fields[field_count].name ? fields[field_count].name : "");
+ std::string b = (row[field_count] ? row[field_count] : "");
+ thisrow[a] = b;
+ field_count++;
+ }
+ return thisrow;
+ }
+ }
+ }
+ return thisrow;
+ }
+
+ bool QueryDone()
+ {
+ if (res)
+ {
+ mysql_free_result(res);
+ res = NULL;
+ return true;
+ }
+ else return false;
+ }
+
+ bool ConnectionLost()
+ {
+ if (&connection) {
+ return (mysql_ping(&connection) != 0);
+ }
+ else return false;
+ }
+
+ bool CheckConnection()
+ {
+ if (ConnectionLost()) {
+ return Connect();
+ }
+ else return true;
+ }
+
+ std::string GetError()
+ {
+ return mysql_error(&connection);
+ }
+
+ long GetID()
+ {
+ return id;
+ }
+
+ std::string GetHost()
+ {
+ return host;
+ }
+
+ void Enable()
+ {
+ Enabled = true;
+ }
+
+ void Disable()
+ {
+ Enabled = false;
+ }
+
+ bool IsEnabled()
+ {
+ return Enabled;
+ }
+
+};
+
+typedef std::vector<SQLConnection> ConnectionList;
+
+class ModuleSQL : public Module
+{
+ Server *Srv;
+ ConfigReader *Conf;
+ ConnectionList Connections;
+
+ public:
+ void ConnectDatabases()
+ {
+ for (ConnectionList::iterator i = Connections.begin(); i != Connections.end(); i++)
+ {
+ i->Enable();
+ if (i->Connect())
+ {
+ Srv->Log(DEFAULT,"SQL: Successfully connected database "+i->GetHost());
+ }
+ else
+ {
+ Srv->Log(DEFAULT,"SQL: Failed to connect database "+i->GetHost()+": Error: "+i->GetError());
+ i->Disable();
+ }
+ }
+ }
+
+ void LoadDatabases(ConfigReader* ThisConf)
+ {
+ Srv->Log(DEFAULT,"SQL: Loading database settings");
+ Connections.clear();
+ Srv->Log(DEBUG,"Cleared connections");
+ for (int j =0; j < ThisConf->Enumerate("database"); j++)
+ {
+ std::string db = ThisConf->ReadValue("database","name",j);
+ std::string user = ThisConf->ReadValue("database","username",j);
+ std::string pass = ThisConf->ReadValue("database","password",j);
+ std::string host = ThisConf->ReadValue("database","hostname",j);
+ std::string id = ThisConf->ReadValue("database","id",j);
+ Srv->Log(DEBUG,"Read database settings");
+ if ((db != "") && (host != "") && (user != "") && (id != "") && (pass != ""))
+ {
+ SQLConnection ThisSQL(host,user,pass,db,atoi(id.c_str()));
+ Srv->Log(DEFAULT,"Loaded database: "+ThisSQL.GetHost());
+ Connections.push_back(ThisSQL);
+ Srv->Log(DEBUG,"Pushed back connection");
+ }
+ }
+ ConnectDatabases();
+ }
+
+ void ResultType(SQLRequest *r, SQLResult *res)
+ {
+ for (ConnectionList::iterator i = Connections.begin(); i != Connections.end(); i++)
+ {
+ if ((i->GetID() == r->GetConnID()) && (i->IsEnabled()))
+ {
+ bool xr = i->QueryResult(r->GetQuery());
+ if (!xr)
+ {
+ res->SetType(SQL_ERROR);
+ res->SetError(i->GetError());
+ return;
+ }
+ res->SetType(SQL_OK);
+ return;
+ }
+ }
+ }
+
+ void CountType(SQLRequest *r, SQLResult* res)
+ {
+ for (ConnectionList::iterator i = Connections.begin(); i != Connections.end(); i++)
+ {
+ if ((i->GetID() == r->GetConnID()) && (i->IsEnabled()))
+ {
+ res->SetType(SQL_COUNT);
+ res->SetCount(i->QueryCount(r->GetQuery()));
+ return;
+ }
+ }
+ }
+
+ void DoneType(SQLRequest *r, SQLResult* res)
+ {
+ for (ConnectionList::iterator i = Connections.begin(); i != Connections.end(); i++)
+ {
+ if ((i->GetID() == r->GetConnID()) && (i->IsEnabled()))
+ {
+ res->SetType(SQL_DONE);
+ if (!i->QueryDone())
+ res->SetType(SQL_ERROR);
+ }
+ }
+ }
+
+ void RowType(SQLRequest *r, SQLResult* res)
+ {
+ for (ConnectionList::iterator i = Connections.begin(); i != Connections.end(); i++)
+ {
+ if ((i->GetID() == r->GetConnID()) && (i->IsEnabled()))
+ {
+ log(DEBUG,"*** FOUND MATCHING ROW");
+ std::map<std::string,std::string> row = i->GetRow();
+ res->SetRow(row);
+ res->SetType(SQL_ROW);
+ if (!row.size())
+ {
+ log(DEBUG,"ROW SIZE IS 0");
+ res->SetType(SQL_END);
+ }
+ return;
+ }
+ }
+ }
+
+ void Implements(char* List)
+ {
+ List[I_OnRehash] = List[I_OnRequest] = 1;
+ }
+
+ char* OnRequest(Request* request)
+ {
+ if (request)
+ {
+ SQLResult* Result = new SQLResult();
+ SQLRequest *r = (SQLRequest*)request->GetData();
+ switch (r->GetQueryType())
+ {
+ case SQL_RESULT:
+ ResultType(r,Result);
+ break;
+ case SQL_COUNT:
+ CountType(r,Result);
+ break;
+ case SQL_ROW:
+ RowType(r,Result);
+ break;
+ case SQL_DONE:
+ DoneType(r,Result);
+ break;
+ }
+ return (char*)Result;
+ }
+ return NULL;
+ }
+
+ ModuleSQL(Server* Me)
+ : Module::Module(Me)
+ {
+ Srv = Me;
+ Conf = new ConfigReader();
+ LoadDatabases(Conf);
+ }
+
+ virtual ~ModuleSQL()
+ {
+ Connections.clear();
+ DELETE(Conf);
+ }
+
+ virtual void OnRehash(const std::string &parameter)
+ {
+ DELETE(Conf);
+ Conf = new ConfigReader();
+ LoadDatabases(Conf);
+ }
+
+ virtual Version GetVersion()
+ {
+ return Version(1,0,0,0,VF_VENDOR|VF_SERVICEPROVIDER);
+ }
+
+};
+
+// stuff down here is the module-factory stuff. For basic modules you can ignore this.
+
+class ModuleSQLFactory : public ModuleFactory
+{
+ public:
+ ModuleSQLFactory()
+ {
+ }
+
+ ~ModuleSQLFactory()
+ {
+ }
+
+ virtual Module * CreateModule(Server* Me)
+ {
+ return new ModuleSQL(Me);
+ }
+
+};
+
+
+extern "C" void * init_module( void )
+{
+ return new ModuleSQLFactory;
+}
+