diff options
| author | Adam <Adam@anope.org> | 2016-10-15 16:25:57 -0400 |
|---|---|---|
| committer | Adam <Adam@anope.org> | 2016-10-15 16:25:57 -0400 |
| commit | 1ba242179fee46583098f48421af39ce9a8985a1 (patch) | |
| tree | a276cd7bd53e7270c86ab3744bd6a568a016501b /modules | |
| parent | 696239e93391f3dfd6459857fb02a6006048093a (diff) | |
Various improvements/bugfixes to extdb stuff
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/botserv/assign.cpp | 4 | ||||
| -rw-r--r-- | modules/botserv/bot.cpp | 26 | ||||
| -rw-r--r-- | modules/botserv/info.cpp | 7 | ||||
| -rw-r--r-- | modules/botserv/set.cpp | 2 | ||||
| -rw-r--r-- | modules/chanserv/main/channeltype.cpp | 8 | ||||
| -rw-r--r-- | modules/chanserv/main/channeltype.h | 2 | ||||
| -rw-r--r-- | modules/chanserv/main/chanserv.cpp | 16 | ||||
| -rw-r--r-- | modules/database/old.cpp | 4 | ||||
| -rw-r--r-- | modules/database/sql.cpp | 184 | ||||
| -rw-r--r-- | modules/extra/mysql.cpp | 82 | ||||
| -rw-r--r-- | modules/extra/sqlite.cpp | 124 | ||||
| -rw-r--r-- | modules/nickserv/cert.cpp | 19 | ||||
| -rw-r--r-- | modules/nickserv/main/accounttype.cpp | 13 | ||||
| -rw-r--r-- | modules/nickserv/main/accounttype.h | 2 | ||||
| -rw-r--r-- | modules/nickserv/main/nickserv.cpp | 9 | ||||
| -rw-r--r-- | modules/nickserv/main/nicktype.cpp | 9 | ||||
| -rw-r--r-- | modules/nickserv/main/nicktype.h | 2 |
17 files changed, 248 insertions, 265 deletions
diff --git a/modules/botserv/assign.cpp b/modules/botserv/assign.cpp index eb6b8da10..a26b869fe 100644 --- a/modules/botserv/assign.cpp +++ b/modules/botserv/assign.cpp @@ -67,7 +67,7 @@ class CommandBSAssign : public Command return; } - if (bi->bi->GetOperOnly() && !source.HasPriv("botserv/administration")) + if (bi->bi && bi->bi->GetOperOnly() && !source.HasPriv("botserv/administration")) { source.Reply(_("Access denied. Bot \002{0}\002 is for operators only."), bi->nick); return; @@ -265,7 +265,7 @@ class BSAssign : public Module return; } - if (bi->bi->GetOperOnly() && !source->HasPriv("botserv/administration")) + if (bi->bi && bi->bi->GetOperOnly() && !source->HasPriv("botserv/administration")) { targ->SendMessage(bi, _("Access denied. Bot \002{0}\002 is for operators only."), bi->nick); return; diff --git a/modules/botserv/bot.cpp b/modules/botserv/bot.cpp index c93c4cf50..2e33b7ccb 100644 --- a/modules/botserv/bot.cpp +++ b/modules/botserv/bot.cpp @@ -93,6 +93,16 @@ class CommandBSBot : public Command ServiceBot *bi = new ServiceBot(nick, user, host, real); + BotInfo *botinfo = Serialize::New<BotInfo *>(); + botinfo->SetNick(nick); + botinfo->SetUser(user); + botinfo->SetHost(host); + botinfo->SetRealName(real); + botinfo->SetCreated(Anope::CurTime); + + bi->bi = botinfo; + botinfo->bot = bi; + Log(LOG_ADMIN, source, this) << "ADD " << bi->GetMask() << " " << bi->realname; source.Reply(_("\002{0}!{1}@{2}\002 (\002{3}\002) added to the bot list."), bi->nick, bi->GetIdent(), bi->host, bi->realname); @@ -121,7 +131,7 @@ class CommandBSBot : public Command return; } - if (bi->bi->conf) + if (bi->bi && bi->bi->conf) { source.Reply(_("Bot \002{0}\002 is not changeable because it is configured in services configuration."), bi->nick.c_str()); return; @@ -226,23 +236,27 @@ class CommandBSBot : public Command if (!nick.equals_cs(bi->nick)) { bi->SetNewNick(nick); - bi->bi->SetNick(nick); + if (bi->bi != nullptr) + bi->bi->SetNick(nick); } if (!user.equals_cs(bi->GetIdent())) { bi->SetIdent(user); - bi->bi->SetUser(user); + if (bi->bi != nullptr) + bi->bi->SetUser(user); } if (!host.equals_cs(bi->host)) { bi->host = host; - bi->bi->SetHost(host); + if (bi->bi != nullptr) + bi->bi->SetHost(host); } if (real.equals_cs(bi->realname)) { bi->realname = real; - bi->bi->SetRealName(real); + if (bi->bi != nullptr) + bi->bi->SetRealName(real); } if (!user.empty()) @@ -271,7 +285,7 @@ class CommandBSBot : public Command return; } - if (bi->bi->conf) + if (bi->bi && bi->bi->conf) { source.Reply(_("Bot \002{0}\002 is can not be deleted because it is configured in services configuration."), bi->nick); return; diff --git a/modules/botserv/info.cpp b/modules/botserv/info.cpp index 94b1bbbd7..4de86643f 100644 --- a/modules/botserv/info.cpp +++ b/modules/botserv/info.cpp @@ -41,8 +41,11 @@ class CommandBSInfo : public Command source.Reply(_("Information for bot \002%s\002:"), bi->nick.c_str()); info[_("Mask")] = bi->GetIdent() + "@" + bi->host; info[_("Real name")] = bi->realname; - info[_("Created")] = Anope::strftime(bi->bi->GetCreated(), source.GetAccount()); - info[_("Options")] = bi->bi->GetOperOnly() ? _("Private") : _("None"); + if (bi->bi) + { + info[_("Created")] = Anope::strftime(bi->bi->GetCreated(), source.GetAccount()); + info[_("Options")] = bi->bi->GetOperOnly() ? _("Private") : _("None"); + } info[_("Used on")] = stringify(bi->GetChannelCount()) + " channel(s)"; EventManager::Get()->Dispatch(&Event::ServiceBotEvent::OnServiceBot, source, bi, ci, info); diff --git a/modules/botserv/set.cpp b/modules/botserv/set.cpp index 47c5337d2..bb432e3f0 100644 --- a/modules/botserv/set.cpp +++ b/modules/botserv/set.cpp @@ -174,7 +174,7 @@ class CommandBSSetPrivate : public Command source.Reply(_("Services are in read-only mode. Any changes made may not persist.")); ServiceBot *bi = ServiceBot::Find(nick, true); - if (bi == NULL) + if (bi == NULL || !bi->bi) { source.Reply(_("Bot \002{0}\002 does not exist."), nick); return; diff --git a/modules/chanserv/main/channeltype.cpp b/modules/chanserv/main/channeltype.cpp index fa5e03e4c..37c290ef1 100644 --- a/modules/chanserv/main/channeltype.cpp +++ b/modules/chanserv/main/channeltype.cpp @@ -37,12 +37,12 @@ ChannelType::ChannelType(Module *me) : Serialize::Type<ChannelImpl>(me) } -void ChannelType::Name::SetField(ChannelImpl *c, const Anope::string &value) +void ChannelType::Name::OnSet(ChannelImpl *c, const Anope::string &value) { ChanServ::registered_channel_map& map = ChanServ::service->GetChannels(); - map.erase(GetField(c)); - - Serialize::Field<ChannelImpl, Anope::string>::SetField(c, value); + Anope::string *old = this->Get_(c); + if (old != nullptr) + map.erase(*old); map[value] = c; } diff --git a/modules/chanserv/main/channeltype.h b/modules/chanserv/main/channeltype.h index 95158427a..1f1c92201 100644 --- a/modules/chanserv/main/channeltype.h +++ b/modules/chanserv/main/channeltype.h @@ -27,7 +27,7 @@ class ChannelType : public Serialize::Type<ChannelImpl> { using Serialize::Field<ChannelImpl, Anope::string>::Field; - void SetField(ChannelImpl *c, const Anope::string &value) override; + void OnSet(ChannelImpl *c, const Anope::string &value) override; } name; Serialize::Field<ChannelImpl, Anope::string> desc; Serialize::Field<ChannelImpl, time_t> time_registered; diff --git a/modules/chanserv/main/chanserv.cpp b/modules/chanserv/main/chanserv.cpp index ec2e8a623..dc44173a0 100644 --- a/modules/chanserv/main/chanserv.cpp +++ b/modules/chanserv/main/chanserv.cpp @@ -322,7 +322,7 @@ class ChanServCore : public Module { ::Log(LOG_NORMAL, "chanserv/drop", ChanServ) << "Deleting channel " << ci->GetName() << " owned by deleted nick " << nc->GetDisplay(); - delete ci; + ci->Delete(); continue; } } @@ -330,6 +330,7 @@ class ChanServCore : public Module if (ci->GetSuccessor() == nc) ci->SetSuccessor(NULL); +#warning "these arent necessary?" /* are these necessary? */ for (unsigned j = 0; j < ci->GetAccessCount(); ++j) { @@ -338,7 +339,7 @@ class ChanServCore : public Module if (anc && anc == nc) { - delete ca; + ca->Delete(); break; } } @@ -348,7 +349,7 @@ class ChanServCore : public Module AutoKick *ak = ci->GetAkick(j); if (ak->GetAccount() == nc) { - delete ak; + ak->Delete(); break; } } @@ -359,6 +360,7 @@ class ChanServCore : public Module { /* remove access entries that are this channel */ +#warning "also not necessary?" for (ChanServ::Channel *c : ci->GetRefs<ChanServ::Channel *>()) { for (unsigned j = 0; j < c->GetAccessCount(); ++j) @@ -367,7 +369,7 @@ class ChanServCore : public Module if (a->Mask().equals_ci(ci->GetName())) { - delete a; + a->Delete(); break; } } @@ -465,7 +467,7 @@ class ChanServCore : public Module if (!chanserv_expire || Anope::NoExpire || Anope::ReadOnly) return; - for (ChanServ::Channel *ci : channel_type.List<ChanServ::Channel *>()) + for (ChanServ::Channel *ci : Serialize::GetObjects<ChanServ::Channel *>()) { bool expire = false; @@ -488,7 +490,7 @@ class ChanServCore : public Module { ::Log(LOG_NORMAL, "chanserv/expire", ChanServ) << "Expiring channel " << ci->GetName() << " (founder: " << (ci->GetFounder() ? ci->GetFounder()->GetDisplay() : "(none)") << ")"; EventManager::Get()->Dispatch(&ChanServ::Event::ChanExpire::OnChanExpire, ci); - delete ci; + ci->Delete(); } } } @@ -505,7 +507,7 @@ class ChanServCore : public Module void OnPreUplinkSync(Server *serv) override { /* Find all persistent channels and create them, as we are about to finish burst to our uplink */ - for (ChanServ::Channel *ci : channel_type.List<ChanServ::Channel *>()) + for (ChanServ::Channel *ci : Serialize::GetObjects<ChanServ::Channel *>()) { if (ci->HasFieldS("PERSIST")) { diff --git a/modules/database/old.cpp b/modules/database/old.cpp index d63b2c4d8..61be22e9d 100644 --- a/modules/database/old.cpp +++ b/modules/database/old.cpp @@ -777,6 +777,10 @@ static void LoadBots() ServiceBot *bi = ServiceBot::Find(nick, true); if (!bi) bi = new ServiceBot(nick, user, host, real); + + if (bi->bi == nullptr) + bi->bi = Serialize::New<BotInfo *>(); + bi->bi->SetCreated(created); if (flags & OLD_BI_PRIVATE) diff --git a/modules/database/sql.cpp b/modules/database/sql.cpp index d7ed1963a..aa1c94bc0 100644 --- a/modules/database/sql.cpp +++ b/modules/database/sql.cpp @@ -22,7 +22,7 @@ using namespace SQL; -class DBMySQL : public Module, public Pipe +class DBSQL : public Module, public Pipe , public EventHook<Event::SerializeEvents> { private: @@ -58,8 +58,6 @@ class DBMySQL : public Module, public Pipe SQL->RunQuery(q); } - Log(LOG_DEBUG_2) << query.Unsafe(); - return SQL->RunQuery(query); } @@ -85,7 +83,7 @@ class DBMySQL : public Module, public Pipe } public: - DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR) + DBSQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR) , EventHook<Event::SerializeEvents>(this) { } @@ -129,10 +127,10 @@ class DBMySQL : public Module, public Pipe StartTransaction(); - for (Query &q : SQL->CreateTable(prefix, type->GetName())) + for (Query &q : SQL->CreateTable(prefix, type)) Run(q); - for (Query &q : SQL->AlterTable(prefix, type->GetName(), field->serialize_name, false)) + for (Query &q : SQL->AlterTable(prefix, type, field)) Run(q); for (const Query &q : SQL->CreateIndex(prefix + type->GetName(), field->serialize_name)) @@ -150,6 +148,7 @@ class DBMySQL : public Module, public Pipe catch (const ConvertException &) { } + return EVENT_CONTINUE; } @@ -159,7 +158,7 @@ class DBMySQL : public Module, public Pipe StartTransaction(); Query query = "SELECT `" + field->serialize_name + "` FROM `" + prefix + object->GetSerializableType()->GetName() + "` WHERE `id` = @id@"; - query.SetValue("id", object->id); + query.SetValue("id", object->id, false); Result res = Run(query); if (res.Rows() == 0) @@ -169,6 +168,40 @@ class DBMySQL : public Module, public Pipe return true; } + void GetRefs(Serialize::Object *object, Serialize::TypeBase *type, std::vector<Serialize::Edge> &edges) + { + for (Serialize::FieldBase *field : type->GetFields()) + { + if (field->object) + { + Anope::string table = prefix + type->GetName(); + + Query query = "SELECT " + table + ".id FROM " + table + + " INNER JOIN " + prefix + "objects AS o ON " + + table + "." + field->serialize_name + " = o.id " + "WHERE o.id = @id@"; + + query.SetValue("id", object->id, false); + + Result res = Run(query); + for (int i = 0; i < res.Rows(); ++i) + { + Serialize::ID id = convertTo<Serialize::ID>(res.Get(i, "id")); + + Serialize::Object *other = type->Require(id); + if (other == nullptr) + { + Log(LOG_DEBUG) << "Unable to require id " << id << " type " << type->GetName(); + continue; + } + + // other type, other field, direction + edges.emplace_back(other, field, false); + } + } + } + } + public: EventReturn OnSerializeGet(Serialize::Object *object, Serialize::FieldBase *field, Anope::string &value) override { @@ -193,93 +226,16 @@ class DBMySQL : public Module, public Pipe edges.clear(); - Query query; - if (type) - query = "SELECT field," + prefix + "edges.id,other_id,j1.type,j2.type AS other_type FROM `" + prefix + "edges` " - "JOIN `" + prefix + "objects` AS j1 ON " + prefix + "edges.id = j1.id " - "JOIN `" + prefix + "objects` AS j2 ON " + prefix + "edges.other_id = j2.id " - "WHERE " - " (" + prefix + "edges.id = @id@ AND j2.type = @other_type@) " - "OR" - " (other_id = @id@ AND j1.type = @other_type@)"; + if (type == nullptr) + { + for (Serialize::TypeBase *type : Serialize::TypeBase::GetTypes()) + GetRefs(object, type, edges); + } else - query = "SELECT field," + prefix + "edges.id,other_id,j1.type,j2.type AS other_type FROM `" + prefix + "edges` " - "JOIN `" + prefix + "objects` AS j1 ON " + prefix + "edges.id = j1.id " - "JOIN `" + prefix + "objects` AS j2 ON " + prefix + "edges.other_id = j2.id " - "WHERE " + prefix + "edges.id = @id@ OR other_id = @id@"; - - query.SetValue("type", object->GetSerializableType()->GetName()); - query.SetValue("id", object->id); - if (type) - query.SetValue("other_type", type->GetName()); - - Result res = Run(query); - for (int i = 0; i < res.Rows(); ++i) { - Serialize::ID id = convertTo<Serialize::ID>(res.Get(i, "id")); // object edge is on - - if (id == object->id) - { - // we want other type, this is my edge - Anope::string t = res.Get(i, "other_type"); - Anope::string f = res.Get(i, "field"); - id = convertTo<Serialize::ID>(res.Get(i, "other_id")); - - Serialize::FieldBase *obj_field = object->GetSerializableType()->GetField(f); - if (obj_field == nullptr) - { - Log(LOG_DEBUG) << "Unable to find field " << f << " on " << object->GetSerializableType()->GetName(); - continue; - } - - Serialize::TypeBase *obj_type = Serialize::TypeBase::Find(t); - if (obj_type == nullptr) - { - Log(LOG_DEBUG) << "Unable to find type " << t; - continue; - } - - Serialize::Object *other = obj_type->Require(id); - if (other == nullptr) - { - Log(LOG_DEBUG) << "Unable to require id " << id << " type " << obj_type->GetName(); - continue; - } - - edges.emplace_back(other, obj_field, true); - } - else - { - // edge to me - Anope::string t = res.Get(i, "type"); - Anope::string f = res.Get(i, "field"); - - Serialize::TypeBase *obj_type = Serialize::TypeBase::Find(t); - if (obj_type == nullptr) - { - Log(LOG_DEBUG) << "Unable to find type " << t; - continue; - } - - Serialize::FieldBase *obj_field = obj_type->GetField(f); - if (obj_field == nullptr) - { - Log(LOG_DEBUG) << "Unable to find field " << f << " on " << obj_type->GetName(); - continue; - } - - Serialize::Object *other = obj_type->Require(id); - if (other == nullptr) - { - Log(LOG_DEBUG) << "Unable to require id " << id << " type " << obj_type->GetName(); - continue; - } - - // other type, other field, - edges.emplace_back(other, obj_field, false); - } + GetRefs(object, type, edges); } - + return EVENT_ALLOW; } @@ -288,7 +244,7 @@ class DBMySQL : public Module, public Pipe StartTransaction(); Query query = "SELECT `id` FROM `" + prefix + type->GetName() + "` WHERE `id` = @id@"; - query.SetValue("id", id); + query.SetValue("id", id, false); Result res = Run(query); if (res.Rows() == 0) return EVENT_CONTINUE; @@ -302,7 +258,7 @@ class DBMySQL : public Module, public Pipe Query query = "SELECT `" + field->serialize_name + "`,j1.type AS " + field->serialize_name + "_type FROM `" + prefix + object->GetSerializableType()->GetName() + "` " "JOIN `" + prefix + "objects` AS j1 ON " + prefix + object->GetSerializableType()->GetName() + "." + field->serialize_name + " = j1.id " "WHERE " + prefix + object->GetSerializableType()->GetName() + ".id = @id@"; - query.SetValue("id", object->id); + query.SetValue("id", object->id, false); Result res = Run(query); if (res.Rows() == 0) @@ -329,16 +285,16 @@ class DBMySQL : public Module, public Pipe StartTransaction(); - for (Query &q : SQL->CreateTable(prefix, object->GetSerializableType()->GetName())) + for (Query &q : SQL->CreateTable(prefix, object->GetSerializableType())) Run(q); - for (Query &q : SQL->AlterTable(prefix, object->GetSerializableType()->GetName(), field->serialize_name, is_object)) + for (Query &q : SQL->AlterTable(prefix, object->GetSerializableType(), field)) Run(q); Query q; - q.SetValue("id", object->id); + q.SetValue("id", object->id, false); if (value) - q.SetValue(field->serialize_name, *value); + q.SetValue(field->serialize_name, *value, !is_object); else q.SetNull(field->serialize_name); @@ -364,23 +320,10 @@ class DBMySQL : public Module, public Pipe { Anope::string v = stringify(value->id); DoSet(object, field, true, &v); - - Query query; - query.SetValue("field", field->serialize_name); - query.SetValue("id", object->id); - query.SetValue("other_id", value->id); - - for (Query &q : SQL->Replace(prefix + "edges", query, { "id", "field" })) - Run(q); } else { DoSet(object, field, true, nullptr); - - Query query("DELETE FROM `" + prefix + "edges` WHERE `id` = @id@ AND `field` = @field@"); - query.SetValue("id", object->id); - query.SetValue("field", field->serialize_name); - Run(query); } return EVENT_STOP; @@ -395,12 +338,6 @@ class DBMySQL : public Module, public Pipe EventReturn OnSerializeUnsetSerializable(Serialize::Object *object, Serialize::FieldBase *field) override { DoSet(object, field, true, nullptr); - - Query query("DELETE FROM `" + prefix + "edges` WHERE `id` = @id@ AND `field` = @field@"); - query.SetValue("id", object->id); - query.SetValue("field", field->serialize_name); - Run(query); - return EVENT_STOP; } @@ -408,7 +345,14 @@ class DBMySQL : public Module, public Pipe { SQL::Result::Value v; - return GetValue(object, field, v) && !v.null ? EVENT_STOP : EVENT_CONTINUE; + if (!GetValue(object, field, v)) + return EVENT_CONTINUE; + + if (v.null) + return EVENT_CONTINUE; + + field->UnserializeFromString(object, v.value); + return EVENT_STOP; } EventReturn OnSerializableGetId(Serialize::ID &id) override @@ -427,7 +371,7 @@ class DBMySQL : public Module, public Pipe StartTransaction(); Query q = Query("INSERT INTO `" + prefix + "objects` (`id`,`type`) VALUES (@id@, @type@)"); - q.SetValue("id", object->id); + q.SetValue("id", object->id, false); q.SetValue("type", object->GetSerializableType()->GetName()); Run(q); } @@ -436,10 +380,10 @@ class DBMySQL : public Module, public Pipe { StartTransaction(); - Query query("DELETE FROM `" + prefix + object->GetSerializableType()->GetName() + "` WHERE `id` = " + stringify(object->id)); + Query query("DELETE FROM `" + prefix + "objects` WHERE `id` = " + stringify(object->id)); Run(query); } }; -MODULE_INIT(DBMySQL) +MODULE_INIT(DBSQL) diff --git a/modules/extra/mysql.cpp b/modules/extra/mysql.cpp index b0aec1f6d..b5ff0c3d9 100644 --- a/modules/extra/mysql.cpp +++ b/modules/extra/mysql.cpp @@ -156,8 +156,8 @@ class MySQLService : public Provider std::vector<Query> InitSchema(const Anope::string &prefix) override; std::vector<Query> Replace(const Anope::string &table, const Query &, const std::set<Anope::string> &) override; - std::vector<Query> CreateTable(const Anope::string &prefix, const Anope::string &table) override; - std::vector<Query> AlterTable(const Anope::string &, const Anope::string &table, const Anope::string &field, bool) override; + std::vector<Query> CreateTable(const Anope::string &prefix, Serialize::TypeBase *) override; + std::vector<Query> AlterTable(const Anope::string &, Serialize::TypeBase *, Serialize::FieldBase *) override; std::vector<Query> CreateIndex(const Anope::string &table, const Anope::string &field) override; Query BeginTransaction() override; @@ -393,24 +393,7 @@ std::vector<Query> MySQLService::InitSchema(const Anope::string &prefix) { std::vector<Query> queries; - Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + "id` (" - "`id` bigint(20) NOT NULL" - ") ENGINE=InnoDB"; - queries.push_back(t); - - t = "CREATE TABLE IF NOT EXISTS `" + prefix + "objects` (`id` bigint(20) NOT NULL PRIMARY KEY, `type` varchar(256)) ENGINE=InnoDB"; - queries.push_back(t); - - t = "CREATE TABLE IF NOT EXISTS `" + prefix + "edges` (" - "`id` bigint(20) NOT NULL," - "`field` varchar(64) NOT NULL," - "`other_id` bigint(20) NOT NULL," - "PRIMARY KEY (`id`, `field`)," - "KEY `other` (`other_id`)," - "CONSTRAINT `edges_id_fk` FOREIGN KEY (`id`) REFERENCES `" + prefix + "objects` (`id`)," - "CONSTRAINT `edges_other_id_fk` FOREIGN KEY (`other_id`) REFERENCES `" + prefix + "objects` (`id`)" - ") ENGINE=InnoDB"; - queries.push_back(t); + queries.push_back(Query("CREATE TABLE IF NOT EXISTS `" + prefix + "objects` (`id` bigint(20) NOT NULL PRIMARY KEY, `type` TINYTEXT) ENGINE=InnoDB")); return queries; } @@ -441,41 +424,52 @@ std::vector<Query> MySQLService::Replace(const Anope::string &table, const Query return queries; } -std::vector<Query> MySQLService::CreateTable(const Anope::string &prefix, const Anope::string &table) +std::vector<Query> MySQLService::CreateTable(const Anope::string &prefix, Serialize::TypeBase *base) { std::vector<Query> queries; - if (active_schema.find(prefix + table) == active_schema.end()) + if (active_schema.find(prefix + base->GetName()) == active_schema.end()) { - Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + table + "` (`id` bigint(20) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB"; + Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + base->GetName() + "` (`id` bigint(20) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB"; queries.push_back(t); - t = "ALTER TABLE `" + prefix + table + "` " - "ADD CONSTRAINT `" + table + "_id_fk` FOREIGN KEY (`id`) REFERENCES `" + prefix + "objects` (`id`)"; + t = "ALTER TABLE `" + prefix + base->GetName() + "` " + "ADD CONSTRAINT `" + base->GetName() + "_id_fk` FOREIGN KEY (`id`) REFERENCES `" + prefix + "objects` (`id`) ON DELETE CASCADE"; queries.push_back(t); - active_schema[prefix + table]; + active_schema[prefix + base->GetName()]; } return queries; } -std::vector<Query> MySQLService::AlterTable(const Anope::string &prefix, const Anope::string &table, const Anope::string &field, bool object) +std::vector<Query> MySQLService::AlterTable(const Anope::string &prefix, Serialize::TypeBase *type, Serialize::FieldBase *field) { + const Anope::string &table = type->GetName(); + std::vector<Query> queries; std::set<Anope::string> &s = active_schema[prefix + table]; - if (!s.count(field)) + if (!s.count(field->serialize_name)) { - Query column; - if (!object) - column = "ALTER TABLE `" + prefix + table + "` ADD COLUMN `" + field + "` TINYTEXT"; + Anope::string buf = "ALTER TABLE `" + prefix + table + "` ADD COLUMN `" + field->serialize_name + "` "; + + if (!field->object) + { + buf += "TINYTEXT"; + } else - column = "ALTER TABLE `" + prefix + table + "` " - "ADD COLUMN `" + field + "` bigint(20), " - "ADD CONSTRAINT `" + table + "_" + field + "_fk` FOREIGN KEY (`" + field + "`) REFERENCES `" + prefix + "objects` (`id`)"; - queries.push_back(column); - s.insert(field); + { + buf += "bigint(20), ADD CONSTRAINT `" + table + "_" + field->serialize_name + "_fk` FOREIGN KEY (`" + field->serialize_name + "`) REFERENCES `" + prefix + "objects` (`id`) ON DELETE "; + + if (field->depends) + buf += "CASCADE"; + else + buf += "SET NULL"; + } + + queries.push_back(Query(buf)); + s.insert(field->serialize_name); } return queries; @@ -508,25 +502,19 @@ Query MySQLService::Commit() Serialize::ID MySQLService::GetID(const Anope::string &prefix) { - Query query("SELECT `id` FROM `" + prefix + "id` FOR UPDATE"); - Serialize::ID id; + Query query = "SELECT `id` FROM `" + prefix + "objects` ORDER BY `id` DESC LIMIT 1"; + Serialize::ID id = 0; Result res = RunQuery(query); if (res.Rows()) { id = convertTo<Serialize::ID>(res.Get(0, "id")); - Query update_query("UPDATE `" + prefix + "id` SET `id` = `id` + 1"); - RunQuery(update_query); + /* next id */ + ++id; } - else - { - id = 0; - Query insert_query("INSERT INTO `" + prefix + "id` (id) VALUES(@id@)"); - insert_query.SetValue("id", 1); - RunQuery(insert_query); - } + /* OnSerializableCreate is called immediately after this which does the insert */ return id; } diff --git a/modules/extra/sqlite.cpp b/modules/extra/sqlite.cpp index 2cd93923b..b9966af5f 100644 --- a/modules/extra/sqlite.cpp +++ b/modules/extra/sqlite.cpp @@ -91,8 +91,8 @@ class SQLiteService : public Provider std::vector<Query> InitSchema(const Anope::string &prefix) override; std::vector<Query> Replace(const Anope::string &table, const Query &, const std::set<Anope::string> &) override; - std::vector<Query> CreateTable(const Anope::string &, const Anope::string &table) override; - std::vector<Query> AlterTable(const Anope::string &, const Anope::string &table, const Anope::string &field, bool) override; + std::vector<Query> CreateTable(const Anope::string &, Serialize::TypeBase *) override; + std::vector<Query> AlterTable(const Anope::string &, Serialize::TypeBase *, Serialize::FieldBase *) override; std::vector<Query> CreateIndex(const Anope::string &table, const Anope::string &field) override; Query BeginTransaction() override; @@ -210,7 +210,11 @@ Result SQLiteService::RunQuery(const Query &query) 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)); + const char *msg = sqlite3_errmsg(this->sql); + + Log(LOG_DEBUG) << "sqlite: error in query " << real_query << ": " << msg; + + return SQLiteResult(query, real_query, msg); } int id = sqlite3_last_insert_rowid(this->sql); @@ -218,6 +222,11 @@ Result SQLiteService::RunQuery(const Query &query) sqlite3_finalize(stmt); + if (!result.GetError().empty()) + Log(LOG_DEBUG) << "sqlite: error executing query " << real_query << ": " << result.GetError(); + else + Log(LOG_DEBUG) << "sqlite: executed: " << real_query; + return result; } @@ -225,23 +234,9 @@ std::vector<Query> SQLiteService::InitSchema(const Anope::string &prefix) { std::vector<Query> queries; - Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + "id` (" - "`id`" - ")"; - queries.push_back(t); - - t = "CREATE TABLE IF NOT EXISTS `" + prefix + "objects` (`id` PRIMARY KEY, `type`)"; - queries.push_back(t); + queries.push_back(Query("PRAGMA foreign_keys = ON")); - t = "CREATE TABLE IF NOT EXISTS `" + prefix + "edges` (" - "`id`," - "`field`," - "`other_id`," - "PRIMARY KEY (`id`, `field`)" - ")"; - queries.push_back(t); - - t = "CREATE INDEX IF NOT EXISTS idx_edge ON `" + prefix + "edges` (other_id)"; + Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + "objects` (`id` PRIMARY KEY, `type`)"; queries.push_back(t); return queries; @@ -287,31 +282,77 @@ std::vector<Query> SQLiteService::Replace(const Anope::string &table, const Quer return queries; } -std::vector<Query> SQLiteService::CreateTable(const Anope::string &prefix, const Anope::string &table) +std::vector<Query> SQLiteService::CreateTable(const Anope::string &prefix, Serialize::TypeBase *base) { std::vector<Query> queries; - if (active_schema.find(prefix + table) == active_schema.end()) + if (active_schema.find(prefix + base->GetName()) == active_schema.end()) { - Query t = "CREATE TABLE IF NOT EXISTS `" + prefix + table + "` (`id` bigint(20) NOT NULL, PRIMARY KEY (`id`))"; - queries.push_back(t); + Anope::string query = "CREATE TABLE IF NOT EXISTS `" + prefix + base->GetName() + "` ("; + std::set<Anope::string> fields; + + for (Serialize::FieldBase *field : base->GetFields()) + { + query += "`" + field->serialize_name + "` COLLATE NOCASE"; + fields.insert(field->serialize_name); + + if (field->object) + { + query += " REFERENCES " + prefix + "objects(id) ON DELETE "; + + if (field->depends) + { + query += "CASCADE"; + } + else + { + query += "SET NULL"; + } + + query += " DEFERRABLE INITIALLY DEFERRED"; + } + + query += ","; + } - active_schema[prefix + table]; + query += " `id` NOT NULL PRIMARY KEY, FOREIGN KEY (id) REFERENCES " + prefix + "objects(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"; + queries.push_back(query); + + active_schema[prefix + base->GetName()] = fields; } return queries; } -std::vector<Query> SQLiteService::AlterTable(const Anope::string &prefix, const Anope::string &table, const Anope::string &field, bool) +std::vector<Query> SQLiteService::AlterTable(const Anope::string &prefix, Serialize::TypeBase *type, Serialize::FieldBase *field) { + const Anope::string &table = type->GetName(); + std::vector<Query> queries; std::set<Anope::string> &s = active_schema[prefix + table]; - if (!s.count(field)) + if (!s.count(field->serialize_name)) { - Query t = "ALTER TABLE `" + prefix + table + "` ADD `" + field + "` COLLATE NOCASE"; - queries.push_back(t); - s.insert(field); + Anope::string buf = "ALTER TABLE `" + prefix + table + "` ADD `" + field->serialize_name + "` COLLATE NOCASE"; + + if (field->object) + { + buf += " REFERENCES " + prefix + "objects(id) ON DELETE "; + + if (field->depends) + { + buf += "CASCADE"; + } + else + { + buf += "SET NULL"; + } + + buf += " DEFERRABLE INITIALLY DEFERRED"; + } + + queries.push_back(Query(buf)); + s.insert(field->serialize_name); } return queries; @@ -344,27 |
