/*
* InspIRCd -- Internet Relay Chat Daemon
*
+ * Copyright (C) 2019 linuxdaemon <linuxdaemon.irc@gmail.com>
+ * Copyright (C) 2015 Daniel Vassdal <shutter@canternet.org>
+ * Copyright (C) 2014, 2016 Adam <Adam@anope.org>
+ * Copyright (C) 2013-2014 Attila Molnar <attilamolnar@hush.com>
+ * Copyright (C) 2013, 2016-2020 Sadie Powell <sadie@witchery.services>
+ * Copyright (C) 2012 Robby <robby@chatbelgie.be>
+ * Copyright (C) 2012 ChrisTX <xpipe@hotmail.de>
* Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
- * Copyright (C) 2006-2007, 2009 Dennis Friis <peavey@inspircd.org>
- * Copyright (C) 2006-2009 Craig Edwards <craigedwards@brainbox.cc>
- * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2009 Uli Schlachter <psychon@inspircd.org>
+ * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org>
+ * Copyright (C) 2005, 2008-2010 Craig Edwards <brain@inspircd.org>
*
* This file is part of InspIRCd. InspIRCd is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public
* worker thread wakes up, and checks if there is a request at the head of its queue.
* If there is, it processes this request, blocking the worker thread but leaving the ircd
* thread to go about its business as usual. During this period, the ircd thread is able
- * to insert futher pending requests into the queue.
+ * to insert further pending requests into the queue.
*
* Once the processing of a request is complete, it is removed from the incoming queue to
* an outgoing queue, and initialized as a 'response'. The worker thread then signals the
* one the module was originally instantiated upon, there is a chance of all hell breaking loose
* if a module is ever put in a re-enterant state (stack corruption could occur, crashes, data
* corruption, and worse, so DONT think about it until the day comes when InspIRCd is 100%
- * gauranteed threadsafe!)
+ * guaranteed threadsafe!)
*/
class SQLConnection;
class MySQLresult;
class DispatcherThread;
-struct QQueueItem
+struct QueryQueueItem
{
- SQL::Query* q;
- std::string query;
- SQLConnection* c;
- QQueueItem(SQL::Query* Q, const std::string& S, SQLConnection* C) : q(Q), query(S), c(C) {}
+ // An SQL database which this query is executed on.
+ SQLConnection* connection;
+
+ // An object which handles the result of the query.
+ SQL::Query* query;
+
+ // The SQL query which is to be executed.
+ std::string querystr;
+
+ QueryQueueItem(SQL::Query* q, const std::string& s, SQLConnection* c)
+ : connection(c)
+ , query(q)
+ , querystr(s)
+ {
+ }
};
-struct RQueueItem
+struct ResultQueueItem
{
- SQL::Query* q;
- MySQLresult* r;
- RQueueItem(SQL::Query* Q, MySQLresult* R) : q(Q), r(R) {}
+ // An object which handles the result of the query.
+ SQL::Query* query;
+
+ // The result returned from executing the MySQL query.
+ MySQLresult* result;
+
+ ResultQueueItem(SQL::Query* q, MySQLresult* r)
+ : query(q)
+ , result(r)
+ {
+ }
};
typedef insp::flat_map<std::string, SQLConnection*> ConnMap;
-typedef std::deque<QQueueItem> QueryQueue;
-typedef std::deque<RQueueItem> ResultQueue;
+typedef std::deque<QueryQueueItem> QueryQueue;
+typedef std::deque<ResultQueueItem> ResultQueue;
/** MySQL module
* */
std::vector<std::string> colnames;
std::vector<SQL::Row> fieldlists;
- MySQLresult(MYSQL_RES* res, int affected_rows) : err(SQL::SUCCESS), currentrow(0), rows(0)
+ MySQLresult(MYSQL_RES* res, int affected_rows)
+ : err(SQL::SUCCESS)
+ , currentrow(0)
+ , rows(0)
{
if (affected_rows >= 1)
{
}
}
- MySQLresult(SQL::Error& e) : err(e)
+ MySQLresult(SQL::Error& e)
+ : err(e)
+ , currentrow(0)
+ , rows(0)
{
}
~SQLConnection()
{
- Close();
+ mysql_close(connection);
}
// This method connects to the database using the credentials supplied to the constructor, and returns
/* Parse the command string and dispatch it to mysql */
if (CheckConnection() && !mysql_real_query(connection, query.data(), query.length()))
{
- /* Successfull query */
+ /* Successful query */
MYSQL_RES* res = mysql_use_result(connection);
unsigned long rows = mysql_affected_rows(connection);
return new MySQLresult(res, rows);
return true;
}
- void Close()
- {
- mysql_close(connection);
- }
-
void Submit(SQL::Query* q, const std::string& qs) CXX11_OVERRIDE
{
ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Executing MySQL query: " + qs);
Parent()->Dispatcher->LockQueue();
- Parent()->qq.push_back(QQueueItem(q, qs, this));
+ Parent()->qq.push_back(QueryQueueItem(q, qs, this));
Parent()->Dispatcher->UnlockQueueWakeup();
}
};
ModuleSQL::ModuleSQL()
+ : Dispatcher(NULL)
{
- Dispatcher = NULL;
}
void ModuleSQL::init()
for (size_t j = qq.size(); j > 0; j--)
{
size_t k = j - 1;
- if (qq[k].c == i->second)
+ if (qq[k].connection == i->second)
{
- qq[k].q->OnError(err);
- delete qq[k].q;
+ qq[k].query->OnError(err);
+ delete qq[k].query;
qq.erase(qq.begin() + k);
}
}
while (i > 0)
{
i--;
- if (qq[i].q->creator == mod)
+ if (qq[i].query->creator == mod)
{
if (i == 0)
{
// need to wait until the query is done
// (the result will be discarded)
- qq[i].c->lock.Lock();
- qq[i].c->lock.Unlock();
+ qq[i].connection->lock.Lock();
+ qq[i].connection->lock.Unlock();
}
- qq[i].q->OnError(err);
- delete qq[i].q;
+ qq[i].query->OnError(err);
+ delete qq[i].query;
qq.erase(qq.begin() + i);
}
}
Version ModuleSQL::GetVersion()
{
- return Version("Provides MySQL support", VF_VENDOR);
+ return Version("Provides the ability for SQL modules to query a MySQL database.", VF_VENDOR);
}
void DispatcherThread::Run()
{
if (!Parent->qq.empty())
{
- QQueueItem i = Parent->qq.front();
- i.c->lock.Lock();
+ QueryQueueItem i = Parent->qq.front();
+ i.connection->lock.Lock();
this->UnlockQueue();
- MySQLresult* res = i.c->DoBlockingQuery(i.query);
- i.c->lock.Unlock();
+ MySQLresult* res = i.connection->DoBlockingQuery(i.querystr);
+ i.connection->lock.Unlock();
/*
* At this point, the main thread could be working on:
- * Rehash - delete i.c out from under us. We don't care about that.
- * UnloadModule - delete i.q and the qq item. Need to avoid reporting results.
+ * Rehash - delete i.connection out from under us. We don't care about that.
+ * UnloadModule - delete i.query and the qq item. Need to avoid reporting results.
*/
this->LockQueue();
- if (!Parent->qq.empty() && Parent->qq.front().q == i.q)
+ if (!Parent->qq.empty() && Parent->qq.front().query == i.query)
{
Parent->qq.pop_front();
- Parent->rq.push_back(RQueueItem(i.q, res));
+ Parent->rq.push_back(ResultQueueItem(i.query, res));
NotifyParent();
}
else
this->LockQueue();
for(ResultQueue::iterator i = Parent->rq.begin(); i != Parent->rq.end(); i++)
{
- MySQLresult* res = i->r;
+ MySQLresult* res = i->result;
if (res->err.code == SQL::SUCCESS)
- i->q->OnResult(*res);
+ i->query->OnResult(*res);
else
- i->q->OnError(res->err);
- delete i->q;
- delete i->r;
+ i->query->OnError(res->err);
+ delete i->query;
+ delete i->result;
}
Parent->rq.clear();
this->UnlockQueue();