00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "module.h"
00012 #include "../extra/sql.h"
00013
00014 using namespace SQL;
00015
00016 class SQLSQLInterface : public Interface
00017 {
00018 public:
00019 SQLSQLInterface(Module *o) : Interface(o) { }
00020
00021 void OnResult(const Result &r) anope_override
00022 {
00023 Log(LOG_DEBUG) << "SQL successfully executed query: " << r.finished_query;
00024 }
00025
00026 void OnError(const Result &r) anope_override
00027 {
00028 if (!r.GetQuery().query.empty())
00029 Log(LOG_DEBUG) << "Error executing query " << r.finished_query << ": " << r.GetError();
00030 else
00031 Log(LOG_DEBUG) << "Error executing query: " << r.GetError();
00032 }
00033 };
00034
00035 class ResultSQLSQLInterface : public SQLSQLInterface
00036 {
00037 Reference<Serializable> obj;
00038
00039 public:
00040 ResultSQLSQLInterface(Module *o, Serializable *ob) : SQLSQLInterface(o), obj(ob) { }
00041
00042 void OnResult(const Result &r) anope_override
00043 {
00044 SQLSQLInterface::OnResult(r);
00045 if (r.GetID() > 0 && this->obj)
00046 this->obj->id = r.GetID();
00047 delete this;
00048 }
00049
00050 void OnError(const Result &r) anope_override
00051 {
00052 SQLSQLInterface::OnError(r);
00053 delete this;
00054 }
00055 };
00056
00057 class DBSQL : public Module, public Pipe
00058 {
00059 ServiceReference<Provider> sql;
00060 SQLSQLInterface sqlinterface;
00061 Anope::string prefix;
00062 std::set<Serializable *> updated_items;
00063 bool shutting_down;
00064 bool loading_databases;
00065 bool loaded;
00066 bool imported;
00067
00068 void RunBackground(const Query &q, Interface *iface = NULL)
00069 {
00070 if (!this->sql)
00071 {
00072 static time_t last_warn = 0;
00073 if (last_warn + 300 < Anope::CurTime)
00074 {
00075 last_warn = Anope::CurTime;
00076 Log(this) << "db_sql: Unable to execute query, is SQL configured correctly?";
00077 }
00078 }
00079 else if (!Anope::Quitting)
00080 {
00081 if (iface == NULL)
00082 iface = &this->sqlinterface;
00083 this->sql->Run(iface, q);
00084 }
00085 else
00086 this->sql->RunQuery(q);
00087 }
00088
00089 public:
00090 DBSQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE), sql("", ""), sqlinterface(this), shutting_down(false), loading_databases(false), loaded(false), imported(false)
00091 {
00092 this->SetAuthor("Anope");
00093
00094 Implementation i[] = { I_OnReload, I_OnShutdown, I_OnRestart, I_OnLoadDatabase, I_OnSerializableConstruct, I_OnSerializableDestruct, I_OnSerializableUpdate, I_OnSerializeTypeCreate };
00095 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00096
00097 this->OnReload();
00098 }
00099
00100 void OnNotify() anope_override
00101 {
00102 for (std::set<Serializable *>::iterator it = this->updated_items.begin(), it_end = this->updated_items.end(); it != it_end; ++it)
00103 {
00104 Serializable *obj = *it;
00105
00106 if (this->sql)
00107 {
00108 Data data;
00109 obj->Serialize(data);
00110
00111 if (obj->IsCached(data))
00112 continue;
00113
00114 obj->UpdateCache(data);
00115
00116 Serialize::Type *s_type = obj->GetSerializableType();
00117 if (!s_type)
00118 continue;
00119
00120 std::vector<Query> create = this->sql->CreateTable(this->prefix + s_type->GetName(), data);
00121 for (unsigned i = 0; i < create.size(); ++i)
00122 this->RunBackground(create[i]);
00123
00124 Query insert = this->sql->BuildInsert(this->prefix + s_type->GetName(), obj->id, data);
00125 if (this->imported)
00126 this->RunBackground(insert, new ResultSQLSQLInterface(this, obj));
00127 else
00128 {
00129
00130
00131
00132 Result r = this->sql->RunQuery(insert);
00133 if (r.GetID() > 0)
00134 obj->id = r.GetID();
00135 }
00136 }
00137 }
00138
00139 this->updated_items.clear();
00140 this->imported = true;
00141 }
00142
00143 void OnReload() anope_override
00144 {
00145 ConfigReader config;
00146 Anope::string engine = config.ReadValue("db_sql", "engine", "", 0);
00147 this->sql = ServiceReference<Provider>("SQL::Provider", engine);
00148 this->prefix = config.ReadValue("db_sql", "prefix", "anope_db_", 0);
00149 }
00150
00151 void OnShutdown() anope_override
00152 {
00153 this->shutting_down = true;
00154 this->OnNotify();
00155 }
00156
00157 void OnRestart() anope_override
00158 {
00159 this->OnShutdown();
00160 }
00161
00162 EventReturn OnLoadDatabase() anope_override
00163 {
00164 if (!this->sql)
00165 {
00166 Log(this) << "Unable to load databases, is SQL configured correctly?";
00167 return EVENT_CONTINUE;
00168 }
00169
00170 this->loading_databases = true;
00171
00172 const std::vector<Anope::string> type_order = Serialize::Type::GetTypeOrder();
00173 for (unsigned i = 0; i < type_order.size(); ++i)
00174 {
00175 Serialize::Type *sb = Serialize::Type::Find(type_order[i]);
00176 this->OnSerializeTypeCreate(sb);
00177 }
00178
00179 this->loading_databases = false;
00180 this->loaded = true;
00181
00182 return EVENT_STOP;
00183 }
00184
00185 void OnSerializableConstruct(Serializable *obj) anope_override
00186 {
00187 if (this->shutting_down || this->loading_databases)
00188 return;
00189 obj->UpdateTS();
00190 this->updated_items.insert(obj);
00191 this->Notify();
00192 }
00193
00194 void OnSerializableDestruct(Serializable *obj) anope_override
00195 {
00196 Serialize::Type *s_type = obj->GetSerializableType();
00197 if (s_type && obj->id > 0)
00198 this->RunBackground("DELETE FROM `" + this->prefix + s_type->GetName() + "` WHERE `id` = " + stringify(obj->id));
00199 this->updated_items.erase(obj);
00200 }
00201
00202 void OnSerializableUpdate(Serializable *obj) anope_override
00203 {
00204 if (this->shutting_down || obj->IsTSCached())
00205 return;
00206 obj->UpdateTS();
00207 this->updated_items.insert(obj);
00208 this->Notify();
00209 }
00210
00211 void OnSerializeTypeCreate(Serialize::Type *sb) anope_override
00212 {
00213 if (!this->loading_databases && !this->loaded)
00214 return;
00215
00216 Query query("SELECT * FROM `" + this->prefix + sb->GetName() + "`");
00217 Result res = this->sql->RunQuery(query);
00218
00219 for (int j = 0; j < res.Rows(); ++j)
00220 {
00221 Data data;
00222
00223 const std::map<Anope::string, Anope::string> &row = res.Row(j);
00224 for (std::map<Anope::string, Anope::string>::const_iterator rit = row.begin(), rit_end = row.end(); rit != rit_end; ++rit)
00225 data[rit->first] << rit->second;
00226
00227 Serializable *obj = sb->Unserialize(NULL, data);
00228 try
00229 {
00230 if (obj)
00231 obj->id = convertTo<unsigned int>(res.Get(j, "id"));
00232 }
00233 catch (const ConvertException &)
00234 {
00235 Log(this) << "Unable to convert id for object #" << j << " of type " << sb->GetName();
00236 }
00237
00238 if (obj)
00239 {
00240 Data data2;
00241
00242 for (std::map<Anope::string, Anope::string>::const_iterator rit = row.begin(), rit_end = row.end(); rit != rit_end; ++rit)
00243 if (rit->first != "id" && rit->first != "timestamp")
00244 data2[rit->first] << rit->second;
00245 obj->UpdateCache(data2);
00246 }
00247 }
00248 }
00249 };
00250
00251 MODULE_INIT(DBSQL)
00252