diff options
author | Adam <Adam@anope.org> | 2011-09-25 04:19:15 -0400 |
---|---|---|
committer | Adam <Adam@anope.org> | 2011-09-25 04:19:15 -0400 |
commit | 1f2399de364c09adcce4193895cd362d80ffdfc5 (patch) | |
tree | 5f40fc531f22c174b6e10bb7bc12842a4a21d30b /modules/extra | |
parent | 43201ead9575a74e350710bc191f4ac67366aca7 (diff) |
Added a new database format and sqlite support. Also moved db-convert to a module.
Diffstat (limited to 'modules/extra')
-rw-r--r-- | modules/extra/m_dnsbl.cpp | 4 | ||||
-rw-r--r-- | modules/extra/m_ldap_authentication.cpp | 8 | ||||
-rw-r--r-- | modules/extra/m_mysql.cpp | 55 | ||||
-rw-r--r-- | modules/extra/m_sqlite.cpp | 235 | ||||
-rw-r--r-- | modules/extra/sql.h | 2 |
5 files changed, 283 insertions, 21 deletions
diff --git a/modules/extra/m_dnsbl.cpp b/modules/extra/m_dnsbl.cpp index c8f18a34c..894eebb8a 100644 --- a/modules/extra/m_dnsbl.cpp +++ b/modules/extra/m_dnsbl.cpp @@ -30,7 +30,7 @@ class DNSBLResolver : public DNSRequest void OnLookupComplete(const DNSQuery *record) { - if (!user || user->GetExt("m_dnsbl_akilled")) + if (!user || user->HasExt("m_dnsbl_akilled")) return; const ResourceRecord &ans_record = record->answers[0]; @@ -50,7 +50,7 @@ class DNSBLResolver : public DNSRequest record_reason = this->blacklist.replies[result]; } - user->Extend("m_dnsbl_akilled"); + user->Extend("m_dnsbl_akilled", NULL); Anope::string reason = this->blacklist.reason; reason = reason.replace_all_cs("%n", user->nick); diff --git a/modules/extra/m_ldap_authentication.cpp b/modules/extra/m_ldap_authentication.cpp index 8a4ef2702..148ee8250 100644 --- a/modules/extra/m_ldap_authentication.cpp +++ b/modules/extra/m_ldap_authentication.cpp @@ -49,7 +49,7 @@ class IdentifyInterface : public LDAPInterface User *u = ii->user; Command *c = ii->command; - u->Extend("m_ldap_authentication_authenticated"); + u->Extend("m_ldap_authentication_authenticated", NULL); NickAlias *na = findnick(ii->account); if (na == NULL) @@ -87,7 +87,7 @@ class IdentifyInterface : public LDAPInterface User *u = ii->user; Command *c = ii->command; - u->Extend("m_ldap_authentication_error"); + u->Extend("m_ldap_authentication_error", NULL); c->Execute(ii->source, ii->params); @@ -218,12 +218,12 @@ class NSIdentifyLDAP : public Module return EVENT_CONTINUE; User *u = source->u; - if (u->GetExt("m_ldap_authentication_authenticated")) + if (u->HasExt("m_ldap_authentication_authenticated")) { u->Shrink("m_ldap_authentication_authenticated"); return EVENT_ALLOW; } - else if (u->GetExt("m_ldap_authentication_error")) + else if (u->HasExt("m_ldap_authentication_error")) { u->Shrink("m_ldap_authentication_error"); return EVENT_CONTINUE; diff --git a/modules/extra/m_mysql.cpp b/modules/extra/m_mysql.cpp index 05a85b93c..876d2ae4e 100644 --- a/modules/extra/m_mysql.cpp +++ b/modules/extra/m_mysql.cpp @@ -82,8 +82,6 @@ class MySQLResult : public SQLResult MySQLResult(const SQLQuery &q, const Anope::string &fq, const Anope::string &err) : SQLResult(q, fq, err), res(NULL) { - if (this->finished_query.empty()) - this->finished_query = q.query; } ~MySQLResult() @@ -125,6 +123,8 @@ class MySQLService : public SQLProvider SQLResult RunQuery(const SQLQuery &query); + SQLQuery CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data); + void Connect(); bool CheckConnection(); @@ -211,7 +211,7 @@ class ModuleSQL : public Module, public Pipe for (i = 0, num = config.Enumerate("mysql"); i < num; ++i) { - Anope::string connname = config.ReadValue("mysql", "name", "main", i); + Anope::string connname = config.ReadValue("mysql", "name", "mysql/main", i); if (this->MySQLServices.find(connname) == this->MySQLServices.end()) { @@ -284,7 +284,7 @@ class ModuleSQL : public Module, public Pipe }; MySQLService::MySQLService(Module *o, const Anope::string &n, const Anope::string &d, const Anope::string &s, const Anope::string &u, const Anope::string &p, int po) -: SQLProvider(o, "mysql/" + n), database(d), server(s), user(u), password(p), port(po), sql(NULL) +: SQLProvider(o, n), database(d), server(s), user(u), password(p), port(po), sql(NULL) { Connect(); } @@ -323,16 +323,7 @@ SQLResult MySQLService::RunQuery(const SQLQuery &query) { this->Lock.Lock(); - Anope::string real_query; - try - { - real_query = this->BuildQuery(query); - } - catch (const SQLException &ex) - { - this->Lock.Unlock(); - return MySQLResult(query, real_query, ex.GetReason()); - } + Anope::string real_query = this->BuildQuery(query); if (this->CheckConnection() && !mysql_real_query(this->sql, real_query.c_str(), real_query.length())) { @@ -349,6 +340,40 @@ SQLResult MySQLService::RunQuery(const SQLQuery &query) } } +SQLQuery MySQLService::CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data) +{ + Anope::string query_text = "CREATE TABLE `" + table + "` (", key_buf; + for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + { + query_text += "`" + it->first + "` "; + if (it->second.getType() == Serialize::DT_INT) + query_text += "int(11)"; + else if (it->second.getMax() > 0) + query_text += "varchar(" + stringify(it->second.getMax()) + ")"; + else + query_text += "text"; + query_text += ","; + + if (it->second.getKey()) + { + if (key_buf.empty()) + key_buf = "UNIQUE KEY `ukey` ("; + key_buf += "`" + it->first + "`,"; + } + } + if (!key_buf.empty()) + { + key_buf.erase(key_buf.end() - 1); + key_buf += ")"; + query_text += " " + key_buf; + } + else + query_text.erase(query_text.end() - 1); + query_text += ")"; + + return SQLQuery(query_text); +} + void MySQLService::Connect() { this->sql = mysql_init(this->sql); @@ -392,7 +417,7 @@ Anope::string MySQLService::BuildQuery(const SQLQuery &q) Anope::string real_query = q.query; for (std::map<Anope::string, Anope::string>::const_iterator it = q.parameters.begin(), it_end = q.parameters.end(); it != it_end; ++it) - real_query = real_query.replace_all_cs("@" + it->first, "'" + this->Escape(it->second) + "'"); + real_query = real_query.replace_all_cs("@" + it->first + "@", "'" + this->Escape(it->second) + "'"); return real_query; } diff --git a/modules/extra/m_sqlite.cpp b/modules/extra/m_sqlite.cpp new file mode 100644 index 000000000..adf244bbd --- /dev/null +++ b/modules/extra/m_sqlite.cpp @@ -0,0 +1,235 @@ +/* RequiredLibraries: sqlite3 */ + +#include "module.h" +#include <sqlite3.h> +#include "sql.h" + +/* SQLite3 API, based from InspiRCd */ + +/** A SQLite result + */ +class SQLiteResult : public SQLResult +{ + public: + SQLiteResult(const SQLQuery &q, const Anope::string &fq) : SQLResult(q, fq) + { + } + + SQLiteResult(const SQLQuery &q, const Anope::string &fq, const Anope::string &err) : SQLResult(q, fq, err) + { + } + + void addRow(const std::map<Anope::string, Anope::string> &data) + { + this->entries.push_back(data); + } +}; + +/** A SQLite database, there can be multiple + */ +class SQLiteService : public SQLProvider +{ + Anope::string database; + + sqlite3 *sql; + + Anope::string Escape(const Anope::string &query); + + public: + SQLiteService(Module *o, const Anope::string &n, const Anope::string &d); + + ~SQLiteService(); + + void Run(SQLInterface *i, const SQLQuery &query); + + SQLResult RunQuery(const SQLQuery &query); + + SQLQuery CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data); + + Anope::string BuildQuery(const SQLQuery &q); +}; + +class ModuleSQLite : public Module +{ + /* SQL connections */ + std::map<Anope::string, SQLiteService *> SQLiteServices; + public: + ModuleSQLite(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, SUPPORTED) + { + Implementation i[] = { I_OnReload }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + OnReload(); + } + + ~ModuleSQLite() + { + for (std::map<Anope::string, SQLiteService *>::iterator it = this->SQLiteServices.begin(); it != this->SQLiteServices.end(); ++it) + delete it->second; + SQLiteServices.clear(); + } + + void OnReload() + { + ConfigReader config; + int i, num; + + for (std::map<Anope::string, SQLiteService *>::iterator it = this->SQLiteServices.begin(); it != this->SQLiteServices.end();) + { + const Anope::string &cname = it->first; + SQLiteService *s = it->second; + ++it; + + for (i = 0, num = config.Enumerate("sqlite"); i < num; ++i) + if (config.ReadValue("sqlite", "name", "sqlite/main", i) == cname) + break; + + if (i == num) + { + Log(LOG_NORMAL, "sqlite") << "SQLite: Removing server connection " << cname; + + delete s; + this->SQLiteServices.erase(cname); + } + } + + for (i = 0, num = config.Enumerate("sqlite"); i < num; ++i) + { + Anope::string connname = config.ReadValue("sqlite", "name", "sqlite/main", i); + + if (this->SQLiteServices.find(connname) == this->SQLiteServices.end()) + { + Anope::string database = config.ReadValue("sqlite", "database", "anope", i); + + try + { + SQLiteService *ss = new SQLiteService(this, connname, database); + this->SQLiteServices[connname] = ss; + + Log(LOG_NORMAL, "sqlite") << "SQLite: Successfully added database " << database; + } + catch (const SQLException &ex) + { + Log(LOG_NORMAL, "sqlite") << "SQLite: " << ex.GetReason(); + } + } + } + } +}; + +SQLiteService::SQLiteService(Module *o, const Anope::string &n, const Anope::string &d) +: SQLProvider(o, n), database(d), sql(NULL) +{ + int db = sqlite3_open_v2(database.c_str(), &this->sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); + if (db != SQLITE_OK) + throw SQLException("Unable to open SQLite database " + database + ": " + sqlite3_errmsg(this->sql)); +} + +SQLiteService::~SQLiteService() +{ + sqlite3_interrupt(this->sql); + sqlite3_close(this->sql); +} + +void SQLiteService::Run(SQLInterface *i, const SQLQuery &query) +{ + SQLResult res = this->RunQuery(query); + if (!res.GetError().empty()) + i->OnError(res); + else + i->OnResult(res); +} + +SQLResult SQLiteService::RunQuery(const SQLQuery &query) +{ + Anope::string real_query = this->BuildQuery(query); + sqlite3_stmt *stmt; + int err = sqlite3_prepare_v2(this->sql, real_query.c_str(), real_query.length(), &stmt, NULL); + if (err != SQLITE_OK) + return SQLiteResult(query, real_query, sqlite3_errmsg(this->sql)); + + std::vector<Anope::string> columns; + int cols = sqlite3_column_count(stmt); + columns.resize(cols); + for (int i = 0; i < cols; ++i) + columns[i] = sqlite3_column_name(stmt, i); + + SQLiteResult result(query, real_query); + + do + { + err = sqlite3_step(stmt); + if (err == SQLITE_ROW) + { + std::map<Anope::string, Anope::string> items; + for (int i = 0; i < cols; ++i) + { + const char *data = reinterpret_cast<const char *>(sqlite3_column_text(stmt, i)); + if (data && *data) + items[columns[i]] = data; + } + result.addRow(items); + } + } + while (err == SQLITE_ROW); + + if (err != SQLITE_DONE) + return SQLiteResult(query, real_query, sqlite3_errmsg(this->sql)); + + return result; +} + +SQLQuery SQLiteService::CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data) +{ + Anope::string query_text = "CREATE TABLE `" + table + "` (", key_buf; + for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + { + query_text += "`" + it->first + "` "; + if (it->second.getType() == Serialize::DT_INT) + query_text += "int(11)"; + else if (it->second.getMax() > 0) + query_text += "varchar(" + stringify(it->second.getMax()) + ")"; + else + query_text += "text"; + query_text += ","; + + if (it->second.getKey()) + { + if (key_buf.empty()) + key_buf = "UNIQUE ("; + key_buf += "`" + it->first + "`,"; + } + } + if (!key_buf.empty()) + { + key_buf.erase(key_buf.end() - 1); + key_buf += ")"; + query_text += " " + key_buf; + } + else + query_text.erase(query_text.end() - 1); + query_text += ")"; + + return SQLQuery(query_text); +} + +Anope::string SQLiteService::Escape(const Anope::string &query) +{ + char *e = sqlite3_mprintf("%q", query.c_str()); + Anope::string buffer = e; + sqlite3_free(e); + return buffer; +} + +Anope::string SQLiteService::BuildQuery(const SQLQuery &q) +{ + Anope::string real_query = q.query; + + for (std::map<Anope::string, Anope::string>::const_iterator it = q.parameters.begin(), it_end = q.parameters.end(); it != it_end; ++it) + real_query = real_query.replace_all_cs("@" + it->first + "@", "'" + this->Escape(it->second) + "'"); + + return real_query; +} + +MODULE_INIT(ModuleSQLite) + diff --git a/modules/extra/sql.h b/modules/extra/sql.h index 2487b2305..85b3c291a 100644 --- a/modules/extra/sql.h +++ b/modules/extra/sql.h @@ -116,5 +116,7 @@ class SQLProvider : public Service<Base> virtual void Run(SQLInterface *i, const SQLQuery &query) = 0; virtual SQLResult RunQuery(const SQLQuery &query) = 0; + + virtual SQLQuery CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data) = 0; }; |