summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2016-10-15 16:25:57 -0400
committerAdam <Adam@anope.org>2016-10-15 16:25:57 -0400
commit1ba242179fee46583098f48421af39ce9a8985a1 (patch)
treea276cd7bd53e7270c86ab3744bd6a568a016501b /modules
parent696239e93391f3dfd6459857fb02a6006048093a (diff)
Various improvements/bugfixes to extdb stuff
Diffstat (limited to 'modules')
-rw-r--r--modules/botserv/assign.cpp4
-rw-r--r--modules/botserv/bot.cpp26
-rw-r--r--modules/botserv/info.cpp7
-rw-r--r--modules/botserv/set.cpp2
-rw-r--r--modules/chanserv/main/channeltype.cpp8
-rw-r--r--modules/chanserv/main/channeltype.h2
-rw-r--r--modules/chanserv/main/chanserv.cpp16
-rw-r--r--modules/database/old.cpp4
-rw-r--r--modules/database/sql.cpp184
-rw-r--r--modules/extra/mysql.cpp82
-rw-r--r--modules/extra/sqlite.cpp124
-rw-r--r--modules/nickserv/cert.cpp19
-rw-r--r--modules/nickserv/main/accounttype.cpp13
-rw-r--r--modules/nickserv/main/accounttype.h2
-rw-r--r--modules/nickserv/main/nickserv.cpp9
-rw-r--r--modules/nickserv/main/nicktype.cpp9
-rw-r--r--modules/nickserv/main/nicktype.h2
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