Line data Source code
1 : /*
2 : * lwan - web server
3 : * Copyright (c) 2014 L. A. F. Pereira <l@tia.mat.br>
4 : *
5 : * This program is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU General Public License
7 : * as published by the Free Software Foundation; either version 2
8 : * of the License, or any later version.
9 : *
10 : * This program is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : * GNU General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU General Public License
16 : * along with this program; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 : * USA.
19 : */
20 :
21 : #include <string.h>
22 : #include <mysql.h>
23 : #include <sqlite3.h>
24 : #include <stddef.h>
25 : #include <stdlib.h>
26 : #include <stdarg.h>
27 :
28 : #include "database.h"
29 : #include "lwan-status.h"
30 :
31 : struct db_stmt {
32 : bool (*bind)(const struct db_stmt *stmt,
33 : struct db_row *rows,
34 : size_t n_rows);
35 : bool (*step)(const struct db_stmt *stmt, const char *signature, va_list ap);
36 : void (*finalize)(struct db_stmt *stmt);
37 : };
38 :
39 : struct db {
40 : void (*disconnect)(struct db *db);
41 : struct db_stmt *(*prepare)(const struct db *db,
42 : const char *sql,
43 : const size_t sql_len);
44 : };
45 :
46 : /* MySQL */
47 :
48 : struct db_mysql {
49 : struct db base;
50 : MYSQL *con;
51 : };
52 :
53 : struct db_stmt_mysql {
54 : struct db_stmt base;
55 : MYSQL_STMT *stmt;
56 : MYSQL_BIND *param_bind;
57 : MYSQL_BIND *result_bind;
58 : bool must_execute_again;
59 : };
60 :
61 0 : static bool db_stmt_bind_mysql(const struct db_stmt *stmt,
62 : struct db_row *rows,
63 : size_t n_rows)
64 : {
65 0 : struct db_stmt_mysql *stmt_mysql = (struct db_stmt_mysql *)stmt;
66 :
67 0 : stmt_mysql->must_execute_again = true;
68 :
69 0 : if (!stmt_mysql->param_bind) {
70 0 : stmt_mysql->param_bind = calloc(n_rows, sizeof(MYSQL_BIND));
71 0 : if (!stmt_mysql->param_bind)
72 0 : return false;
73 : } else {
74 0 : mysql_stmt_reset(stmt_mysql->stmt);
75 : }
76 :
77 0 : for (size_t row = 0; row < n_rows && rows[row].kind; row++) {
78 0 : MYSQL_BIND *param = &stmt_mysql->param_bind[row];
79 :
80 0 : switch (rows[row].kind) {
81 0 : case 's':
82 0 : param->buffer_type = MYSQL_TYPE_STRING;
83 0 : param->buffer = rows[row].u.s;
84 0 : break;
85 0 : case 'i':
86 0 : param->buffer_type = MYSQL_TYPE_LONG;
87 0 : param->buffer = &rows[row].u.i;
88 0 : break;
89 0 : default:
90 0 : return false;
91 : }
92 :
93 0 : param->is_null = false;
94 0 : param->length = 0;
95 : }
96 :
97 0 : return !mysql_stmt_bind_param(stmt_mysql->stmt, stmt_mysql->param_bind);
98 : }
99 :
100 0 : static bool db_stmt_step_mysql(const struct db_stmt *stmt,
101 : const char *signature,
102 : va_list ap)
103 : {
104 0 : struct db_stmt_mysql *stmt_mysql = (struct db_stmt_mysql *)stmt;
105 :
106 0 : if (stmt_mysql->must_execute_again) {
107 0 : stmt_mysql->must_execute_again = false;
108 0 : if (mysql_stmt_execute(stmt_mysql->stmt))
109 0 : return false;
110 : }
111 :
112 0 : if (!stmt_mysql->result_bind) {
113 0 : if (*signature == '\0')
114 0 : return false;
115 :
116 0 : stmt_mysql->result_bind =
117 0 : calloc(strlen(signature), sizeof(*stmt_mysql->result_bind));
118 0 : if (!stmt_mysql->result_bind)
119 0 : return false;
120 :
121 0 : free(stmt_mysql->param_bind);
122 0 : stmt_mysql->param_bind = NULL;
123 :
124 0 : MYSQL_BIND *result = stmt_mysql->result_bind;
125 0 : for (size_t r = 0; signature[r]; r++) {
126 0 : switch (signature[r]) {
127 0 : case 's':
128 0 : result[r].buffer_type = MYSQL_TYPE_STRING;
129 0 : result[r].buffer = va_arg(ap, char *);
130 0 : result[r].buffer_length = va_arg(ap, size_t);
131 0 : break;
132 0 : case 'i':
133 0 : result[r].buffer_type = MYSQL_TYPE_LONG;
134 0 : result[r].buffer = va_arg(ap, long *);
135 0 : result[r].buffer_length = 0;
136 0 : break;
137 0 : default:
138 0 : goto out;
139 : }
140 :
141 0 : result[r].is_null = false;
142 : }
143 :
144 0 : if (mysql_stmt_bind_result(stmt_mysql->stmt, result))
145 0 : goto out;
146 : }
147 :
148 0 : return mysql_stmt_fetch(stmt_mysql->stmt) == 0;
149 :
150 0 : out:
151 0 : free(stmt_mysql->result_bind);
152 0 : stmt_mysql->result_bind = NULL;
153 :
154 0 : return false;
155 : }
156 :
157 0 : static void db_stmt_finalize_mysql(struct db_stmt *stmt)
158 : {
159 0 : struct db_stmt_mysql *stmt_mysql = (struct db_stmt_mysql *)stmt;
160 :
161 0 : mysql_stmt_close(stmt_mysql->stmt);
162 0 : free(stmt_mysql->result_bind);
163 0 : free(stmt_mysql->param_bind);
164 0 : free(stmt_mysql);
165 0 : }
166 :
167 : static struct db_stmt *
168 0 : db_prepare_mysql(const struct db *db, const char *sql, const size_t sql_len)
169 : {
170 0 : const struct db_mysql *db_mysql = (const struct db_mysql *)db;
171 0 : struct db_stmt_mysql *stmt_mysql = malloc(sizeof(*stmt_mysql));
172 :
173 0 : if (!stmt_mysql)
174 0 : return NULL;
175 :
176 0 : stmt_mysql->stmt = mysql_stmt_init(db_mysql->con);
177 0 : if (!stmt_mysql->stmt)
178 0 : goto out_free_stmt;
179 :
180 0 : if (mysql_stmt_prepare(stmt_mysql->stmt, sql, sql_len))
181 0 : goto out_close_stmt;
182 :
183 0 : stmt_mysql->base.bind = db_stmt_bind_mysql;
184 0 : stmt_mysql->base.step = db_stmt_step_mysql;
185 0 : stmt_mysql->base.finalize = db_stmt_finalize_mysql;
186 0 : stmt_mysql->result_bind = NULL;
187 0 : stmt_mysql->param_bind = NULL;
188 0 : stmt_mysql->must_execute_again = true;
189 :
190 0 : return (struct db_stmt *)stmt_mysql;
191 :
192 0 : out_close_stmt:
193 0 : mysql_stmt_close(stmt_mysql->stmt);
194 0 : out_free_stmt:
195 0 : free(stmt_mysql);
196 :
197 0 : return NULL;
198 : }
199 :
200 0 : static void db_disconnect_mysql(struct db *db)
201 : {
202 0 : struct db_mysql *db_mysql = (struct db_mysql *)db;
203 :
204 0 : mysql_close(db_mysql->con);
205 0 : free(db);
206 0 : }
207 :
208 0 : struct db *db_connect_mysql(const char *host,
209 : const char *user,
210 : const char *pass,
211 : const char *database)
212 : {
213 0 : struct db_mysql *db_mysql = malloc(sizeof(*db_mysql));
214 :
215 0 : if (!db_mysql)
216 0 : return NULL;
217 :
218 0 : db_mysql->con = mysql_init(NULL);
219 0 : if (!db_mysql->con) {
220 0 : free(db_mysql);
221 0 : return NULL;
222 : }
223 :
224 0 : if (!mysql_real_connect(db_mysql->con, host, user, pass, database, 0, NULL,
225 : 0))
226 0 : goto error;
227 :
228 0 : if (mysql_set_character_set(db_mysql->con, "utf8"))
229 0 : goto error;
230 :
231 0 : db_mysql->base.disconnect = db_disconnect_mysql;
232 0 : db_mysql->base.prepare = db_prepare_mysql;
233 :
234 0 : return (struct db *)db_mysql;
235 :
236 0 : error:
237 0 : mysql_close(db_mysql->con);
238 0 : free(db_mysql);
239 0 : return NULL;
240 : }
241 :
242 : /* SQLite */
243 :
244 : struct db_sqlite {
245 : struct db base;
246 : sqlite3 *sqlite;
247 : };
248 :
249 : struct db_stmt_sqlite {
250 : struct db_stmt base;
251 : sqlite3_stmt *sqlite;
252 : };
253 :
254 1115 : static bool db_stmt_bind_sqlite(const struct db_stmt *stmt,
255 : struct db_row *rows,
256 : size_t n_rows)
257 : {
258 1115 : const struct db_stmt_sqlite *stmt_sqlite =
259 : (const struct db_stmt_sqlite *)stmt;
260 :
261 1115 : sqlite3_reset(stmt_sqlite->sqlite);
262 1115 : sqlite3_clear_bindings(stmt_sqlite->sqlite);
263 :
264 2230 : for (size_t row = 1; row <= n_rows; row++) {
265 1115 : const struct db_row *r = &rows[row - 1];
266 : int ret;
267 :
268 1115 : switch (r->kind) {
269 0 : case 's':
270 0 : ret = sqlite3_bind_text(stmt_sqlite->sqlite, (int)row, r->u.s, -1,
271 : NULL);
272 0 : break;
273 1115 : case 'i':
274 1115 : ret = sqlite3_bind_int(stmt_sqlite->sqlite, (int)row, r->u.i);
275 1115 : break;
276 0 : default:
277 0 : return false;
278 : }
279 :
280 1115 : if (ret != SQLITE_OK)
281 0 : return false;
282 : }
283 :
284 1115 : return true;
285 : }
286 :
287 1128 : static bool db_stmt_step_sqlite(const struct db_stmt *stmt,
288 : const char *signature,
289 : va_list ap)
290 : {
291 1128 : const struct db_stmt_sqlite *stmt_sqlite =
292 : (const struct db_stmt_sqlite *)stmt;
293 :
294 1128 : if (sqlite3_step(stmt_sqlite->sqlite) != SQLITE_ROW)
295 1 : return false;
296 :
297 3381 : for (int r = 0; signature[r]; r++) {
298 2254 : switch (signature[r]) {
299 2242 : case 'i':
300 2242 : *va_arg(ap, long *) = sqlite3_column_int(stmt_sqlite->sqlite, r);
301 2242 : break;
302 12 : case 's': {
303 12 : char *out = va_arg(ap, char *);
304 12 : size_t bufsize = va_arg(ap, size_t);
305 :
306 12 : strncpy(out,
307 12 : (const char *)sqlite3_column_text(stmt_sqlite->sqlite, r),
308 : bufsize);
309 :
310 12 : break;
311 : }
312 0 : default:
313 0 : return false;
314 : }
315 : }
316 :
317 1127 : return true;
318 : }
319 :
320 10 : static void db_stmt_finalize_sqlite(struct db_stmt *stmt)
321 : {
322 10 : struct db_stmt_sqlite *stmt_sqlite = (struct db_stmt_sqlite *)stmt;
323 :
324 10 : sqlite3_finalize(stmt_sqlite->sqlite);
325 10 : free(stmt_sqlite);
326 10 : }
327 :
328 : static struct db_stmt *
329 10 : db_prepare_sqlite(const struct db *db, const char *sql, const size_t sql_len)
330 : {
331 10 : const struct db_sqlite *db_sqlite = (const struct db_sqlite *)db;
332 10 : struct db_stmt_sqlite *stmt_sqlite = malloc(sizeof(*stmt_sqlite));
333 :
334 10 : if (!stmt_sqlite)
335 0 : return NULL;
336 :
337 10 : int ret = sqlite3_prepare_v2(db_sqlite->sqlite, sql, (int)sql_len,
338 : &stmt_sqlite->sqlite, NULL);
339 10 : if (ret != SQLITE_OK) {
340 0 : free(stmt_sqlite);
341 0 : return NULL;
342 : }
343 :
344 10 : stmt_sqlite->base.bind = db_stmt_bind_sqlite;
345 10 : stmt_sqlite->base.step = db_stmt_step_sqlite;
346 10 : stmt_sqlite->base.finalize = db_stmt_finalize_sqlite;
347 :
348 10 : return (struct db_stmt *)stmt_sqlite;
349 : }
350 :
351 0 : static void db_disconnect_sqlite(struct db *db)
352 : {
353 0 : struct db_sqlite *db_sqlite = (struct db_sqlite *)db;
354 :
355 0 : sqlite3_close(db_sqlite->sqlite);
356 0 : free(db);
357 0 : }
358 :
359 : struct db *
360 4 : db_connect_sqlite(const char *path, bool read_only, const char *pragmas[])
361 : {
362 4 : struct db_sqlite *db_sqlite = malloc(sizeof(*db_sqlite));
363 :
364 4 : if (!db_sqlite)
365 0 : return NULL;
366 :
367 4 : int flags = read_only ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
368 4 : int ret = sqlite3_open_v2(path, &db_sqlite->sqlite, flags, NULL);
369 4 : if (ret != SQLITE_OK) {
370 0 : free(db_sqlite);
371 0 : return NULL;
372 : }
373 :
374 4 : if (pragmas) {
375 16 : for (size_t p = 0; pragmas[p]; p++)
376 12 : sqlite3_exec(db_sqlite->sqlite, pragmas[p], NULL, NULL, NULL);
377 : }
378 :
379 4 : db_sqlite->base.disconnect = db_disconnect_sqlite;
380 4 : db_sqlite->base.prepare = db_prepare_sqlite;
381 :
382 4 : return (struct db *)db_sqlite;
383 : }
384 :
385 : /* Generic */
386 :
387 : inline bool
388 1115 : db_stmt_bind(const struct db_stmt *stmt, struct db_row *rows, size_t n_rows)
389 : {
390 1115 : return stmt->bind(stmt, rows, n_rows);
391 : }
392 :
393 : inline bool
394 1128 : db_stmt_step(const struct db_stmt *stmt, const char *signature, ...)
395 : {
396 : va_list ap;
397 : bool ret;
398 :
399 1128 : va_start(ap, signature);
400 1128 : ret = stmt->step(stmt, signature, ap);
401 1128 : va_end(ap);
402 :
403 1128 : return ret;
404 : }
405 :
406 10 : inline void db_stmt_finalize(struct db_stmt *stmt) { stmt->finalize(stmt); }
407 :
408 0 : inline void db_disconnect(struct db *db) { db->disconnect(db); }
409 :
410 : inline struct db_stmt *
411 10 : db_prepare_stmt(const struct db *db, const char *sql, const size_t sql_len)
412 : {
413 10 : return db->prepare(db, sql, sql_len);
414 : }
|