]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_sqlite3.cpp
m_sasl: use host/ip from m_cgiirc if applicable
[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 "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         ~SQLite3Result()
52         {
53         }
54
55         virtual int Rows()
56         {
57                 return rows;
58         }
59
60         virtual bool GetRow(SQLEntries& result)
61         {
62                 if (currentrow < rows)
63                 {
64                         result.assign(fieldlists[currentrow].begin(), fieldlists[currentrow].end());
65                         currentrow++;
66                         return true;
67                 }
68                 else
69                 {
70                         result.clear();
71                         return false;
72                 }
73         }
74
75         virtual void GetCols(std::vector<std::string>& result)
76         {
77                 result.assign(columns.begin(), columns.end());
78         }
79 };
80
81 class SQLConn : public SQLProvider
82 {
83  private:
84         sqlite3* conn;
85         reference<ConfigTag> config;
86
87  public:
88         SQLConn(Module* Parent, ConfigTag* tag) : SQLProvider(Parent, "SQL/" + tag->getString("id")), config(tag)
89         {
90                 std::string host = tag->getString("hostname");
91                 if (sqlite3_open_v2(host.c_str(), &conn, SQLITE_OPEN_READWRITE, 0) != SQLITE_OK)
92                 {
93                         // Even in case of an error conn must be closed
94                         sqlite3_close(conn);
95                         conn = NULL;
96                         ServerInstance->Logs->Log("m_sqlite3",DEFAULT, "WARNING: Could not open DB with id: " + tag->getString("id"));
97                 }
98         }
99
100         ~SQLConn()
101         {
102                 if (conn)
103                 {
104                         sqlite3_interrupt(conn);
105                         sqlite3_close(conn);
106                 }
107         }
108
109         void Query(SQLQuery* query, const std::string& q)
110         {
111                 SQLite3Result res;
112                 sqlite3_stmt *stmt;
113                 int err = sqlite3_prepare_v2(conn, q.c_str(), q.length(), &stmt, NULL);
114                 if (err != SQLITE_OK)
115                 {
116                         SQLerror error(SQL_QSEND_FAIL, sqlite3_errmsg(conn));
117                         query->OnError(error);
118                         return;
119                 }
120                 int cols = sqlite3_column_count(stmt);
121                 res.columns.resize(cols);
122                 for(int i=0; i < cols; i++)
123                 {
124                         res.columns[i] = sqlite3_column_name(stmt, i);
125                 }
126                 while (1)
127                 {
128                         err = sqlite3_step(stmt);
129                         if (err == SQLITE_ROW)
130                         {
131                                 // Add the row
132                                 res.fieldlists.resize(res.rows + 1);
133                                 res.fieldlists[res.rows].resize(cols);
134                                 for(int i=0; i < cols; i++)
135                                 {
136                                         const char* txt = (const char*)sqlite3_column_text(stmt, i);
137                                         if (txt)
138                                                 res.fieldlists[res.rows][i] = SQLEntry(txt);
139                                 }
140                                 res.rows++;
141                         }
142                         else if (err == SQLITE_DONE)
143                         {
144                                 query->OnResult(res);
145                                 break;
146                         }
147                         else
148                         {
149                                 SQLerror error(SQL_QREPLY_FAIL, sqlite3_errmsg(conn));
150                                 query->OnError(error);
151                                 break;
152                         }
153                 }
154                 sqlite3_finalize(stmt);
155         }
156
157         virtual void submit(SQLQuery* query, const std::string& q)
158         {
159                 Query(query, q);
160                 delete query;
161         }
162
163         virtual void submit(SQLQuery* query, const std::string& q, const ParamL& p)
164         {
165                 std::string res;
166                 unsigned int param = 0;
167                 for(std::string::size_type i = 0; i < q.length(); i++)
168                 {
169                         if (q[i] != '?')
170                                 res.push_back(q[i]);
171                         else
172                         {
173                                 if (param < p.size())
174                                 {
175                                         char* escaped = sqlite3_mprintf("%q", p[param++].c_str());
176                                         res.append(escaped);
177                                         sqlite3_free(escaped);
178                                 }
179                         }
180                 }
181                 submit(query, res);
182         }
183
184         virtual void submit(SQLQuery* query, const std::string& q, const ParamM& p)
185         {
186                 std::string res;
187                 for(std::string::size_type i = 0; i < q.length(); i++)
188                 {
189                         if (q[i] != '$')
190                                 res.push_back(q[i]);
191                         else
192                         {
193                                 std::string field;
194                                 i++;
195                                 while (i < q.length() && isalnum(q[i]))
196                                         field.push_back(q[i++]);
197                                 i--;
198
199                                 ParamM::const_iterator it = p.find(field);
200                                 if (it != p.end())
201                                 {
202                                         char* escaped = sqlite3_mprintf("%q", it->second.c_str());
203                                         res.append(escaped);
204                                         sqlite3_free(escaped);
205                                 }
206                         }
207                 }
208                 submit(query, res);
209         }
210 };
211
212 class ModuleSQLite3 : public Module
213 {
214  private:
215         ConnMap conns;
216
217  public:
218         ModuleSQLite3()
219         {
220         }
221
222         void init()
223         {
224                 ReadConf();
225
226                 Implementation eventlist[] = { I_OnRehash };
227                 ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
228         }
229
230         virtual ~ModuleSQLite3()
231         {
232                 ClearConns();
233         }
234
235         void ClearConns()
236         {
237                 for(ConnMap::iterator i = conns.begin(); i != conns.end(); i++)
238                 {
239                         SQLConn* conn = i->second;
240                         ServerInstance->Modules->DelService(*conn);
241                         delete conn;
242                 }
243                 conns.clear();
244         }
245
246         void ReadConf()
247         {
248                 ClearConns();
249                 ConfigTagList tags = ServerInstance->Config->ConfTags("database");
250                 for(ConfigIter i = tags.first; i != tags.second; i++)
251                 {
252                         if (i->second->getString("module", "sqlite") != "sqlite")
253                                 continue;
254                         SQLConn* conn = new SQLConn(this, i->second);
255                         conns.insert(std::make_pair(i->second->getString("id"), conn));
256                         ServerInstance->Modules->AddService(*conn);
257                 }
258         }
259
260         void OnRehash(User* user)
261         {
262                 ReadConf();
263         }
264
265         Version GetVersion()
266         {
267                 return Version("sqlite3 provider", VF_VENDOR);
268         }
269 };
270
271 MODULE_INIT(ModuleSQLite3)