Mercurial > dovecot > core-2.2
annotate src/lib-sql/driver-sqlite.c @ 4294:1a98cb709395 HEAD
Added sql_escape_string()
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 31 May 2006 14:02:50 +0300 |
parents | 5b21fb41d14d |
children | d0d04db8e7a6 |
rev | line source |
---|---|
3923 | 1 /* Copyright (C) 2006 Jakob Hirsch */ |
2 | |
3 #include "lib.h" | |
4 #include "str.h" | |
4294 | 5 #include "strescape.h" |
3923 | 6 #include "sql-api-private.h" |
7 | |
3943
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
8 #ifdef BUILD_SQLITE |
3923 | 9 #include <sqlite3.h> |
10 | |
11 /* retry time if db is busy (in ms) */ | |
12 const int sqlite_busy_timeout = 1000; | |
13 | |
14 struct sqlite_db { | |
15 struct sql_db api; | |
16 | |
17 pool_t pool; | |
18 const char *dbfile; | |
19 sqlite3 *sqlite; | |
20 unsigned int connected:1; | |
21 int rc; | |
22 }; | |
23 | |
24 struct sqlite_result { | |
25 struct sql_result api; | |
26 sqlite3_stmt *stmt; | |
27 unsigned int cols; | |
28 const char **row; | |
29 }; | |
30 | |
31 struct sqlite_transaction_context { | |
32 struct sql_transaction_context ctx; | |
33 unsigned int failed:1; | |
34 }; | |
35 | |
3943
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
36 extern struct sql_db driver_sqlite_db; |
3923 | 37 extern struct sql_result driver_sqlite_result; |
38 extern struct sql_result driver_sqlite_error_result; | |
39 | |
40 static int driver_sqlite_connect(struct sql_db *_db) | |
41 { | |
42 struct sqlite_db *db = (struct sqlite_db *)_db; | |
43 | |
44 if (db->connected) | |
45 return 1; | |
46 | |
47 db->rc = sqlite3_open(db->dbfile, &db->sqlite); | |
48 | |
49 if (db->rc == SQLITE_OK) { | |
50 db->connected = TRUE; | |
51 sqlite3_busy_timeout(db->sqlite, sqlite_busy_timeout); | |
52 return 1; | |
53 } else { | |
54 i_error("sqlite: open(%s) failed: %s", db->dbfile, | |
55 sqlite3_errmsg(db->sqlite)); | |
56 sqlite3_close(db->sqlite); | |
57 return -1; | |
58 } | |
59 } | |
60 | |
3943
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
61 static struct sql_db *_driver_sqlite_init(const char *connect_string) |
3923 | 62 { |
63 struct sqlite_db *db; | |
64 pool_t pool; | |
65 | |
66 i_assert(connect_string != NULL); | |
67 | |
68 pool = pool_alloconly_create("sqlite driver", 512); | |
69 db = p_new(pool, struct sqlite_db, 1); | |
70 db->pool = pool; | |
71 db->api = driver_sqlite_db; | |
72 db->dbfile = p_strdup(db->pool, connect_string); | |
73 db->connected = FALSE; | |
74 | |
75 return &db->api; | |
76 } | |
77 | |
3943
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
78 static void _driver_sqlite_deinit(struct sql_db *_db) |
3923 | 79 { |
80 struct sqlite_db *db = (struct sqlite_db *)_db; | |
81 | |
82 sqlite3_close(db->sqlite); | |
83 pool_unref(db->pool); | |
84 } | |
85 | |
86 static enum sql_db_flags | |
87 driver_sqlite_get_flags(struct sql_db *db __attr_unused__) | |
88 { | |
89 return SQL_DB_FLAG_BLOCKING; | |
90 } | |
91 | |
4294 | 92 static char *driver_sqlite_escape_string(struct sql_db *_db __attr_unused__, |
93 const char *string) | |
94 { | |
95 return t_strdup_noconst(str_escape(string)); | |
96 } | |
97 | |
3923 | 98 static void driver_sqlite_exec(struct sql_db *_db, const char *query) |
99 { | |
100 struct sqlite_db *db = (struct sqlite_db *)_db; | |
101 | |
102 db->rc = sqlite3_exec(db->sqlite, query, NULL, 0, NULL); | |
103 if (db->rc != SQLITE_OK) { | |
104 i_error("sqlite: exec(%s) failed: %s (%d)", | |
105 query, sqlite3_errmsg(db->sqlite), db->rc); | |
106 } | |
107 } | |
108 | |
109 static void driver_sqlite_query(struct sql_db *db, const char *query, | |
110 sql_query_callback_t *callback, void *context) | |
111 { | |
112 struct sql_result *result; | |
113 | |
114 result = sql_query_s(db, query); | |
115 result->callback = TRUE; | |
116 callback(result, context); | |
3946 | 117 result->callback = FALSE; |
3923 | 118 sql_result_free(result); |
119 } | |
120 | |
121 static struct sql_result * | |
122 driver_sqlite_query_s(struct sql_db *_db, const char *query) | |
123 { | |
124 struct sqlite_db *db = (struct sqlite_db *)_db; | |
125 struct sqlite_result *result; | |
126 int rc; | |
127 | |
128 result = i_new(struct sqlite_result, 1); | |
129 | |
130 rc = sqlite3_prepare(db->sqlite, query, -1, &result->stmt, NULL); | |
131 if (rc == SQLITE_OK) { | |
132 result->api = driver_sqlite_result; | |
133 result->cols = sqlite3_column_count(result->stmt); | |
134 result->row = i_new(const char *, result->cols); | |
135 } else { | |
136 result->api = driver_sqlite_error_result; | |
137 result->stmt = NULL; | |
138 result->cols = 0; | |
139 } | |
140 result->api.db = _db; | |
141 | |
142 return &result->api; | |
143 } | |
144 | |
145 static void driver_sqlite_result_free(struct sql_result *_result) | |
146 { | |
147 struct sqlite_result *result = (struct sqlite_result *)_result; | |
148 struct sqlite_db *db = (struct sqlite_db *) result->api.db; | |
149 int rc; | |
150 | |
3947 | 151 if (_result->callback) |
152 return; | |
153 | |
3923 | 154 if (result->stmt != NULL) { |
155 if ((rc = sqlite3_finalize(result->stmt)) != SQLITE_OK) { | |
156 i_warning("sqlite: finalize failed: %s (%d)", | |
157 sqlite3_errmsg(db->sqlite), rc); | |
158 } | |
159 i_free(result->row); | |
160 } | |
161 i_free(result); | |
162 } | |
163 | |
164 static int driver_sqlite_result_next_row(struct sql_result *_result) | |
165 { | |
166 struct sqlite_result *result = (struct sqlite_result *)_result; | |
167 | |
168 switch (sqlite3_step(result->stmt)) { | |
169 case SQLITE_ROW: | |
170 return 1; | |
171 case SQLITE_DONE: | |
172 return 0; | |
173 default: | |
174 return -1; | |
175 } | |
176 } | |
177 | |
178 static unsigned int | |
179 driver_sqlite_result_get_fields_count(struct sql_result *_result) | |
180 { | |
181 struct sqlite_result *result = (struct sqlite_result *)_result; | |
182 | |
183 return result->cols; | |
184 } | |
185 | |
186 static const char * | |
187 driver_sqlite_result_get_field_name(struct sql_result *_result, | |
188 unsigned int idx) | |
189 { | |
190 struct sqlite_result *result = (struct sqlite_result *)_result; | |
191 | |
192 return sqlite3_column_name(result->stmt, idx); | |
193 } | |
194 | |
195 static int driver_sqlite_result_find_field(struct sql_result *_result, | |
196 const char *field_name) | |
197 { | |
198 struct sqlite_result *result = (struct sqlite_result *)_result; | |
199 unsigned int i; | |
200 | |
201 for (i = 0; i < result->cols; ++i) { | |
202 const char *col = sqlite3_column_name(result->stmt, i); | |
203 | |
204 if (strcmp(col, field_name) == 0) | |
205 return i; | |
206 } | |
207 | |
208 return -1; | |
209 } | |
210 | |
211 static const char * | |
212 driver_sqlite_result_get_field_value(struct sql_result *_result, | |
213 unsigned int idx) | |
214 { | |
215 struct sqlite_result *result = (struct sqlite_result *)_result; | |
216 | |
3936
8e827b05047b
Compiler warning fix. Patch by Marcus Rueckert
Timo Sirainen <tss@iki.fi>
parents:
3923
diff
changeset
|
217 return (const char*)sqlite3_column_text(result->stmt, idx); |
3923 | 218 } |
219 | |
220 static const char * | |
221 driver_sqlite_result_find_field_value(struct sql_result *result, | |
222 const char *field_name) | |
223 { | |
224 int idx; | |
225 | |
226 idx = driver_sqlite_result_find_field(result, field_name); | |
227 if (idx < 0) | |
228 return NULL; | |
229 return driver_sqlite_result_get_field_value(result, idx); | |
230 } | |
231 | |
232 static const char *const * | |
233 driver_sqlite_result_get_values(struct sql_result *_result) | |
234 { | |
235 struct sqlite_result *result = (struct sqlite_result *)_result; | |
236 unsigned int i; | |
237 | |
238 for (i = 0; i < result->cols; ++i) { | |
239 result->row[i] = | |
240 driver_sqlite_result_get_field_value(_result, i); | |
241 } | |
242 | |
243 return (const char *const *)result->row; | |
244 } | |
245 | |
246 static const char *driver_sqlite_result_get_error(struct sql_result *_result) | |
247 { | |
248 struct sqlite_result *result = (struct sqlite_result *)_result; | |
249 struct sqlite_db *db = (struct sqlite_db *)result->api.db; | |
250 | |
251 return sqlite3_errmsg(db->sqlite); | |
252 } | |
253 | |
254 static struct sql_transaction_context * | |
255 driver_sqlite_transaction_begin(struct sql_db *_db) | |
256 { | |
257 struct sqlite_transaction_context *ctx; | |
258 struct sqlite_db *db = (struct sqlite_db *)_db; | |
259 | |
260 ctx = i_new(struct sqlite_transaction_context, 1); | |
261 ctx->ctx.db = _db; | |
262 | |
263 sql_exec(_db, "BEGIN TRANSACTION"); | |
264 if (db->rc != SQLITE_OK) | |
265 ctx->failed = TRUE; | |
266 | |
267 return &ctx->ctx; | |
268 } | |
269 | |
270 static void | |
271 driver_sqlite_transaction_rollback(struct sql_transaction_context *_ctx) | |
272 { | |
273 struct sqlite_transaction_context *ctx = | |
274 (struct sqlite_transaction_context *)_ctx; | |
275 | |
276 sql_exec(_ctx->db, "ROLLBACK"); | |
277 i_free(ctx); | |
278 } | |
279 | |
280 static void | |
281 driver_sqlite_transaction_commit(struct sql_transaction_context *_ctx, | |
282 sql_commit_callback_t *callback, void *context) | |
283 { | |
284 struct sqlite_transaction_context *ctx = | |
285 (struct sqlite_transaction_context *)_ctx; | |
286 struct sqlite_db *db = (struct sqlite_db *)ctx->ctx.db; | |
287 const char *errmsg; | |
288 | |
289 if (!ctx->failed) { | |
290 sql_exec(_ctx->db, "COMMIT"); | |
291 if (db->rc != SQLITE_OK) | |
292 ctx->failed = TRUE; | |
293 } | |
294 | |
295 if (ctx->failed) { | |
296 errmsg = sqlite3_errmsg(db->sqlite); | |
297 callback(errmsg, context); | |
298 /* also does i_free(ctx) */ | |
299 driver_sqlite_transaction_rollback(_ctx); | |
300 } else { | |
301 callback(NULL, context); | |
302 i_free(ctx); | |
303 } | |
304 } | |
305 | |
306 static int | |
307 driver_sqlite_transaction_commit_s(struct sql_transaction_context *_ctx, | |
308 const char **error_r) | |
309 { | |
310 struct sqlite_transaction_context *ctx = | |
311 (struct sqlite_transaction_context *)_ctx; | |
312 struct sqlite_db *db = (struct sqlite_db *) ctx->ctx.db; | |
313 | |
314 if (ctx->failed) { | |
315 /* also does i_free(ctx) */ | |
316 driver_sqlite_transaction_rollback(_ctx); | |
317 return -1; | |
318 } | |
319 | |
320 sql_exec(_ctx->db, "COMMIT"); | |
321 *error_r = sqlite3_errmsg(db->sqlite); | |
322 i_free(ctx); | |
323 return 0; | |
324 } | |
325 | |
326 static void | |
327 driver_sqlite_update(struct sql_transaction_context *_ctx, const char *query) | |
328 { | |
329 struct sqlite_transaction_context *ctx = | |
330 (struct sqlite_transaction_context *)_ctx; | |
331 struct sqlite_db *db = (struct sqlite_db *)ctx->ctx.db; | |
332 | |
333 if (ctx->failed) | |
334 return; | |
335 | |
336 sql_exec(_ctx->db, query); | |
337 if (db->rc != SQLITE_OK) | |
338 ctx->failed = TRUE; | |
339 } | |
340 | |
341 struct sql_db driver_sqlite_db = { | |
342 "sqlite", | |
343 | |
3943
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
344 _driver_sqlite_init, |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
345 _driver_sqlite_deinit, |
3923 | 346 driver_sqlite_get_flags, |
347 driver_sqlite_connect, | |
4294 | 348 driver_sqlite_escape_string, |
3923 | 349 driver_sqlite_exec, |
350 driver_sqlite_query, | |
351 driver_sqlite_query_s, | |
352 | |
353 driver_sqlite_transaction_begin, | |
354 driver_sqlite_transaction_commit, | |
355 driver_sqlite_transaction_commit_s, | |
356 driver_sqlite_transaction_rollback, | |
357 driver_sqlite_update | |
358 }; | |
359 | |
360 struct sql_result driver_sqlite_result = { | |
361 NULL, | |
362 | |
363 driver_sqlite_result_free, | |
364 driver_sqlite_result_next_row, | |
365 driver_sqlite_result_get_fields_count, | |
366 driver_sqlite_result_get_field_name, | |
367 driver_sqlite_result_find_field, | |
368 driver_sqlite_result_get_field_value, | |
369 driver_sqlite_result_find_field_value, | |
370 driver_sqlite_result_get_values, | |
371 driver_sqlite_result_get_error, | |
372 | |
373 FALSE | |
374 }; | |
375 | |
376 static int | |
377 driver_sqlite_result_error_next_row(struct sql_result *result __attr_unused__) | |
378 { | |
379 return -1; | |
380 } | |
381 | |
382 struct sql_result driver_sqlite_error_result = { | |
383 NULL, | |
384 | |
385 driver_sqlite_result_free, | |
386 driver_sqlite_result_error_next_row, | |
387 NULL, NULL, NULL, NULL, NULL, NULL, | |
388 driver_sqlite_result_get_error, | |
389 | |
390 FALSE | |
391 }; | |
392 | |
3943
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
393 void driver_sqlite_init(void); |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
394 void driver_sqlite_deinit(void); |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
395 |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
396 void driver_sqlite_init(void) |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
397 { |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
398 sql_driver_register(&driver_sqlite_db); |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
399 } |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
400 |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
401 void driver_sqlite_deinit(void) |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
402 { |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
403 sql_driver_unregister(&driver_sqlite_db); |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
404 } |
cbe5c6772e0d
Added support for dynamically building SQL drivers.
Timo Sirainen <tss@iki.fi>
parents:
3936
diff
changeset
|
405 |
3923 | 406 #endif |