diff options
author | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2006-07-21 17:48:46 +0000 |
---|---|---|
committer | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2006-07-21 17:48:46 +0000 |
commit | 2010b514a638f43d515e9539ef21015f733ec279 (patch) | |
tree | d12e05189ce1dcff675122a59ef0d1a9a2fbf22c /src/modules/extra/m_mysql.cpp | |
parent | 6016b09a4ace340e6c1411308ff7135f4ba7e3d1 (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.cpp | 400 |
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 ¶meter) + { + 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; +} + |