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