]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_sqlite3.cpp
Merge insp20
[user/henk/code/inspircd.git] / src / modules / extra / m_sqlite3.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2007-2009 Dennis Friis <peavey@inspircd.org>
6  *   Copyright (C) 2007, 2009 Craig Edwards <craigedwards@brainbox.cc>
7  *   Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
8  *
9  * This file is part of InspIRCd.  InspIRCd is free software: you can
10  * redistribute it and/or modify it under the terms of the GNU General Public
11  * License as published by the Free Software Foundation, version 2.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22
23 #include "inspircd.h"
24 #include <sqlite3.h>
25 #include "modules/sql.h"
26
27 #ifdef _WIN32
28 # pragma comment(lib, "sqlite3.lib")
29 #endif
30
31 /* $ModDesc: sqlite3 provider */
32 /* $CompileFlags: pkgconfversion("sqlite3","3.3") pkgconfincludes("sqlite3","/sqlite3.h","") */
33 /* $LinkerFlags: pkgconflibs("sqlite3","/libsqlite3.so","-lsqlite3") */
34 /* $NoPedantic */
35
36 class SQLConn;
37 typedef std::map<std::string, SQLConn*> ConnMap;
38
39 class SQLite3Result : public SQLResult
40 {
41  public:
42         int currentrow;
43         int rows;
44         std::vector<std::string> columns;
45         std::vector<SQLEntries> fieldlists;
46
47         SQLite3Result() : currentrow(0), rows(0)
48         {
49         }
50
51         int Rows()
52         {
53                 return rows;
54         }
55
56         bool GetRow(SQLEntries& result)
57         {
58                 if (currentrow < rows)
59                 {
60                         result.assign(fieldlists[currentrow].begin(), fieldlists[currentrow].end());
61                         currentrow++;
62                         return true;
63                 }
64                 else
65                 {
66                         result.clear();
67                         return false;
68                 }
69         }
70
71         void GetCols(std::vector<std::string>& result)
72         {
73                 result.assign(columns.begin(), columns.end());
74         }
75 };
76
77 class SQLConn : public SQLProvider
78 {
79         sqlite3* conn;
80         reference<ConfigTag> config;
81
82  public:
83         SQLConn(Module* Parent, ConfigTag* tag) : SQLProvider(Parent, "SQL/" + tag->getString("id")), config(tag)
84         {
85                 std::string host = tag->getString("hostname");
86                 if (sqlite3_open_v2(host.c_str(), &conn, SQLITE_OPEN_READWRITE, 0) != SQLITE_OK)
87                 {
88                         ServerInstance->Logs->Log("m_sqlite3", LOG_DEFAULT, "WARNING: Could not open DB with id: " + tag->getString("id"));
89                         conn = NULL;
90                 }
91         }
92
93         ~SQLConn()
94         {
95                 sqlite3_interrupt(conn);
96                 sqlite3_close(conn);
97         }
98
99         void Query(SQLQuery* query, const std::string& q)
100         {
101                 SQLite3Result res;
102                 sqlite3_stmt *stmt;
103                 int err = sqlite3_prepare_v2(conn, q.c_str(), q.length(), &stmt, NULL);
104                 if (err != SQLITE_OK)
105                 {
106                         SQLerror error(SQL_QSEND_FAIL, sqlite3_errmsg(conn));
107                         query->OnError(error);
108                         return;
109                 }
110                 int cols = sqlite3_column_count(stmt);
111                 res.columns.resize(cols);
112                 for(int i=0; i < cols; i++)
113                 {
114                         res.columns[i] = sqlite3_column_name(stmt, i);
115                 }
116                 while (1)
117                 {
118                         err = sqlite3_step(stmt);
119                         if (err == SQLITE_ROW)
120                         {
121                                 // Add the row
122                                 res.fieldlists.resize(res.rows + 1);
123                                 res.fieldlists[res.rows].resize(cols);
124                                 for(int i=0; i < cols; i++)
125                                 {
126                                         const char* txt = (const char*)sqlite3_column_text(stmt, i);
127                                         if (txt)
128                                                 res.fieldlists[res.rows][i] = SQLEntry(txt);
129                                 }
130                                 res.rows++;
131                         }
132                         else if (err == SQLITE_DONE)
133                         {
134                                 query->OnResult(res);
135                                 break;
136                         }
137                         else
138                         {
139                                 SQLerror error(SQL_QREPLY_FAIL, sqlite3_errmsg(conn));
140                                 query->OnError(error);
141                                 break;
142                         }
143                 }
144                 sqlite3_finalize(stmt);
145         }
146
147         void submit(SQLQuery* query, const std::string& q)
148         {
149                 Query(query, q);
150                 delete query;
151         }
152
153         void submit(SQLQuery* query, const std::string& q, const ParamL& p)
154         {
155                 std::string res;
156                 unsigned int param = 0;
157                 for(std::string::size_type i = 0; i < q.length(); i++)
158                 {
159                         if (q[i] != '?')
160                                 res.push_back(q[i]);
161                         else
162                         {
163                                 if (param < p.size())
164                                 {
165                                         char* escaped = sqlite3_mprintf("%q", p[param++].c_str());
166                                         res.append(escaped);
167                                         sqlite3_free(escaped);
168                                 }
169                         }
170                 }
171                 submit(query, res);
172         }
173
174         void submit(SQLQuery* query, const std::string& q, const ParamM& p)
175         {
176                 std::string res;
177                 for(std::string::size_type i = 0; i < q.length(); i++)
178                 {
179                         if (q[i] != '$')
180                                 res.push_back(q[i]);
181                         else
182                         {
183                                 std::string field;
184                                 i++;
185                                 while (i < q.length() && isalnum(q[i]))
186                                         field.push_back(q[i++]);
187                                 i--;
188
189                                 ParamM::const_iterator it = p.find(field);
190                                 if (it != p.end())
191                                 {
192                                         char* escaped = sqlite3_mprintf("%q", it->second.c_str());
193                                         res.append(escaped);
194                                         sqlite3_free(escaped);
195                                 }
196                         }
197                 }
198                 submit(query, res);
199         }
200 };
201
202 class ModuleSQLite3 : public Module
203 {
204         ConnMap conns;
205
206  public:
207         void init() CXX11_OVERRIDE
208         {
209                 ReadConf();
210
211                 Implementation eventlist[] = { I_OnRehash };
212                 ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
213         }
214
215         ~ModuleSQLite3()
216         {
217                 ClearConns();
218         }
219
220         void ClearConns()
221         {
222                 for(ConnMap::iterator i = conns.begin(); i != conns.end(); i++)
223                 {
224                         SQLConn* conn = i->second;
225                         ServerInstance->Modules->DelService(*conn);
226                         delete conn;
227                 }
228                 conns.clear();
229         }
230
231         void ReadConf()
232         {
233                 ClearConns();
234                 ConfigTagList tags = ServerInstance->Config->ConfTags("database");
235                 for(ConfigIter i = tags.first; i != tags.second; i++)
236                 {
237                         if (i->second->getString("module", "sqlite") != "sqlite")
238                                 continue;
239                         SQLConn* conn = new SQLConn(this, i->second);
240                         conns.insert(std::make_pair(i->second->getString("id"), conn));
241                         ServerInstance->Modules->AddService(*conn);
242                 }
243         }
244
245         void OnRehash(User* user) CXX11_OVERRIDE
246         {
247                 ReadConf();
248         }
249
250         Version GetVersion() CXX11_OVERRIDE
251         {
252                 return Version("sqlite3 provider", VF_VENDOR);
253         }
254 };
255
256 MODULE_INIT(ModuleSQLite3)