1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Author: Wez Furlong <wez@php.net> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: sqlite_driver.c 272374 2008-12-31 11:17:49Z sebastian $ */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include "config.h"
23 : #endif
24 :
25 : #include "php.h"
26 : #include "php_ini.h"
27 : #include "ext/standard/info.h"
28 : #include "pdo/php_pdo.h"
29 : #include "pdo/php_pdo_driver.h"
30 : #include "php_pdo_sqlite.h"
31 : #include "php_pdo_sqlite_int.h"
32 : #include "zend_exceptions.h"
33 :
34 : int _pdo_sqlite_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line TSRMLS_DC) /* {{{ */
35 312 : {
36 312 : pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
37 312 : pdo_error_type *pdo_err = stmt ? &stmt->error_code : &dbh->error_code;
38 312 : pdo_sqlite_error_info *einfo = &H->einfo;
39 :
40 312 : einfo->errcode = sqlite3_errcode(H->db);
41 312 : einfo->file = file;
42 312 : einfo->line = line;
43 :
44 312 : if (einfo->errcode != SQLITE_OK) {
45 312 : if (einfo->errmsg) {
46 209 : pefree(einfo->errmsg, dbh->is_persistent);
47 : }
48 312 : einfo->errmsg = pestrdup((char*)sqlite3_errmsg(H->db), dbh->is_persistent);
49 : } else { /* no error */
50 0 : strcpy(*pdo_err, PDO_ERR_NONE);
51 0 : return 0;
52 : }
53 312 : switch (einfo->errcode) {
54 : case SQLITE_NOTFOUND:
55 0 : strcpy(*pdo_err, "42S02");
56 0 : break;
57 :
58 : case SQLITE_INTERRUPT:
59 0 : strcpy(*pdo_err, "01002");
60 0 : break;
61 :
62 : case SQLITE_NOLFS:
63 0 : strcpy(*pdo_err, "HYC00");
64 0 : break;
65 :
66 : case SQLITE_TOOBIG:
67 0 : strcpy(*pdo_err, "22001");
68 0 : break;
69 :
70 : case SQLITE_CONSTRAINT:
71 0 : strcpy(*pdo_err, "23000");
72 0 : break;
73 :
74 : case SQLITE_ERROR:
75 : default:
76 312 : strcpy(*pdo_err, "HY000");
77 : break;
78 : }
79 :
80 312 : if (!dbh->methods) {
81 0 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
82 : *pdo_err, einfo->errcode, einfo->errmsg);
83 : }
84 :
85 312 : return einfo->errcode;
86 : }
87 : /* }}} */
88 :
89 : static int pdo_sqlite_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
90 9 : {
91 9 : pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
92 9 : pdo_sqlite_error_info *einfo = &H->einfo;
93 :
94 9 : if (einfo->errcode) {
95 8 : add_next_index_long(info, einfo->errcode);
96 8 : add_next_index_string(info, einfo->errmsg, 1);
97 : }
98 :
99 9 : return 1;
100 : }
101 :
102 : static void pdo_sqlite_cleanup_callbacks(pdo_sqlite_db_handle *H TSRMLS_DC)
103 129 : {
104 : struct pdo_sqlite_func *func;
105 :
106 260 : while (H->funcs) {
107 2 : func = H->funcs;
108 2 : H->funcs = func->next;
109 :
110 2 : if (H->db) {
111 : /* delete the function from the handle */
112 2 : sqlite3_create_function(H->db,
113 : func->funcname,
114 : func->argc,
115 : SQLITE_UTF8,
116 : func,
117 : NULL, NULL, NULL);
118 : }
119 :
120 2 : efree((char*)func->funcname);
121 2 : if (func->func) {
122 1 : zval_ptr_dtor(&func->func);
123 : }
124 2 : if (func->step) {
125 1 : zval_ptr_dtor(&func->step);
126 : }
127 2 : if (func->fini) {
128 1 : zval_ptr_dtor(&func->fini);
129 : }
130 2 : efree(func);
131 : }
132 129 : }
133 :
134 : static int sqlite_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
135 129 : {
136 129 : pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
137 :
138 129 : if (H) {
139 129 : pdo_sqlite_error_info *einfo = &H->einfo;
140 :
141 129 : pdo_sqlite_cleanup_callbacks(H TSRMLS_CC);
142 129 : if (H->db) {
143 129 : sqlite3_close(H->db);
144 129 : H->db = NULL;
145 : }
146 129 : if (einfo->errmsg) {
147 102 : pefree(einfo->errmsg, dbh->is_persistent);
148 102 : einfo->errmsg = NULL;
149 : }
150 129 : pefree(H, dbh->is_persistent);
151 129 : dbh->driver_data = NULL;
152 : }
153 129 : return 0;
154 : }
155 : /* }}} */
156 :
157 : static int sqlite_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
158 134 : {
159 134 : pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
160 134 : pdo_sqlite_stmt *S = ecalloc(1, sizeof(pdo_sqlite_stmt));
161 : int i;
162 : const char *tail;
163 :
164 134 : S->H = H;
165 134 : stmt->driver_data = S;
166 134 : stmt->methods = &sqlite_stmt_methods;
167 134 : stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL|PDO_PLACEHOLDER_NAMED;
168 :
169 134 : if (PDO_CURSOR_FWDONLY != pdo_attr_lval(driver_options, PDO_ATTR_CURSOR, PDO_CURSOR_FWDONLY TSRMLS_CC)) {
170 0 : H->einfo.errcode = SQLITE_ERROR;
171 0 : pdo_sqlite_error(dbh);
172 0 : return 0;
173 : }
174 :
175 134 : i = sqlite3_prepare(H->db, sql, sql_len, &S->stmt, &tail);
176 134 : if (i == SQLITE_OK) {
177 133 : return 1;
178 : }
179 :
180 1 : pdo_sqlite_error(dbh);
181 :
182 1 : return 0;
183 : }
184 :
185 : static long sqlite_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
186 452 : {
187 452 : pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
188 452 : char *errmsg = NULL;
189 :
190 452 : if (sqlite3_exec(H->db, sql, NULL, NULL, &errmsg) != SQLITE_OK) {
191 309 : pdo_sqlite_error(dbh);
192 309 : if (errmsg)
193 309 : sqlite3_free(errmsg);
194 :
195 309 : return -1;
196 : } else {
197 143 : return sqlite3_changes(H->db);
198 : }
199 : }
200 :
201 : static char *pdo_sqlite_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
202 1 : {
203 1 : pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
204 : char *id;
205 :
206 1 : id = php_pdo_int64_to_str(sqlite3_last_insert_rowid(H->db) TSRMLS_CC);
207 1 : *len = strlen(id);
208 1 : return id;
209 : }
210 :
211 : /* NB: doesn't handle binary strings... use prepared stmts for that */
212 : static int sqlite_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC)
213 1 : {
214 1 : *quoted = safe_emalloc(2, unquotedlen, 3);
215 1 : sqlite3_snprintf(2*unquotedlen + 3, *quoted, "'%q'", unquoted);
216 1 : *quotedlen = strlen(*quoted);
217 1 : return 1;
218 : }
219 :
220 : static int sqlite_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
221 5 : {
222 5 : pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
223 5 : char *errmsg = NULL;
224 :
225 5 : if (sqlite3_exec(H->db, "BEGIN", NULL, NULL, &errmsg) != SQLITE_OK) {
226 0 : pdo_sqlite_error(dbh);
227 0 : if (errmsg)
228 0 : sqlite3_free(errmsg);
229 0 : return 0;
230 : }
231 5 : return 1;
232 : }
233 :
234 : static int sqlite_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
235 2 : {
236 2 : pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
237 2 : char *errmsg = NULL;
238 :
239 2 : if (sqlite3_exec(H->db, "COMMIT", NULL, NULL, &errmsg) != SQLITE_OK) {
240 0 : pdo_sqlite_error(dbh);
241 0 : if (errmsg)
242 0 : sqlite3_free(errmsg);
243 0 : return 0;
244 : }
245 2 : return 1;
246 : }
247 :
248 : static int sqlite_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
249 3 : {
250 3 : pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
251 3 : char *errmsg = NULL;
252 :
253 3 : if (sqlite3_exec(H->db, "ROLLBACK", NULL, NULL, &errmsg) != SQLITE_OK) {
254 0 : pdo_sqlite_error(dbh);
255 0 : if (errmsg)
256 0 : sqlite3_free(errmsg);
257 0 : return 0;
258 : }
259 3 : return 1;
260 : }
261 :
262 : static int pdo_sqlite_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)
263 0 : {
264 0 : switch (attr) {
265 : case PDO_ATTR_CLIENT_VERSION:
266 : case PDO_ATTR_SERVER_VERSION:
267 0 : ZVAL_STRING(return_value, (char *)sqlite3_libversion(), 1);
268 : break;
269 :
270 : default:
271 0 : return 0;
272 : }
273 :
274 0 : return 1;
275 : }
276 :
277 : static int pdo_sqlite_set_attr(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
278 19 : {
279 19 : pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
280 :
281 19 : switch (attr) {
282 : case PDO_ATTR_TIMEOUT:
283 18 : convert_to_long(val);
284 18 : sqlite3_busy_timeout(H->db, Z_LVAL_P(val) * 1000);
285 18 : return 1;
286 : }
287 1 : return 0;
288 : }
289 :
290 : static int do_callback(struct pdo_sqlite_fci *fc, zval *cb,
291 : int argc, sqlite3_value **argv, sqlite3_context *context,
292 : int is_agg TSRMLS_DC)
293 5 : {
294 5 : zval ***zargs = NULL;
295 5 : zval *retval = NULL;
296 : int i;
297 : int ret;
298 : int fake_argc;
299 5 : zval **agg_context = NULL;
300 :
301 5 : if (is_agg) {
302 3 : is_agg = 2;
303 : }
304 :
305 5 : fake_argc = argc + is_agg;
306 :
307 5 : fc->fci.size = sizeof(fc->fci);
308 5 : fc->fci.function_table = EG(function_table);
309 5 : fc->fci.function_name = cb;
310 5 : fc->fci.symbol_table = NULL;
311 5 : fc->fci.object_pp = NULL;
312 5 : fc->fci.retval_ptr_ptr = &retval;
313 5 : fc->fci.param_count = fake_argc;
314 :
315 : /* build up the params */
316 :
317 5 : if (fake_argc) {
318 5 : zargs = (zval ***)safe_emalloc(fake_argc, sizeof(zval **), 0);
319 : }
320 :
321 5 : if (is_agg) {
322 : /* summon the aggregation context */
323 3 : agg_context = (zval**)sqlite3_aggregate_context(context, sizeof(zval*));
324 3 : if (!*agg_context) {
325 1 : MAKE_STD_ZVAL(*agg_context);
326 1 : ZVAL_NULL(*agg_context);
327 : }
328 3 : zargs[0] = agg_context;
329 :
330 3 : zargs[1] = emalloc(sizeof(zval*));
331 3 : MAKE_STD_ZVAL(*zargs[1]);
332 3 : ZVAL_LONG(*zargs[1], sqlite3_aggregate_count(context));
333 : }
334 :
335 9 : for (i = 0; i < argc; i++) {
336 4 : zargs[i + is_agg] = emalloc(sizeof(zval *));
337 4 : MAKE_STD_ZVAL(*zargs[i + is_agg]);
338 :
339 : /* get the value */
340 4 : switch (sqlite3_value_type(argv[i])) {
341 : case SQLITE_INTEGER:
342 0 : ZVAL_LONG(*zargs[i + is_agg], sqlite3_value_int(argv[i]));
343 0 : break;
344 :
345 : case SQLITE_FLOAT:
346 0 : ZVAL_DOUBLE(*zargs[i + is_agg], sqlite3_value_double(argv[i]));
347 0 : break;
348 :
349 : case SQLITE_NULL:
350 0 : ZVAL_NULL(*zargs[i + is_agg]);
351 0 : break;
352 :
353 : case SQLITE_BLOB:
354 : case SQLITE3_TEXT:
355 : default:
356 4 : ZVAL_STRINGL(*zargs[i + is_agg], (char*)sqlite3_value_text(argv[i]),
357 : sqlite3_value_bytes(argv[i]), 1);
358 : break;
359 : }
360 : }
361 :
362 :
363 5 : fc->fci.params = zargs;
364 :
365 :
366 5 : if ((ret = zend_call_function(&fc->fci, &fc->fcc TSRMLS_CC)) == FAILURE) {
367 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the callback");
368 : }
369 :
370 : /* clean up the params */
371 5 : if (zargs) {
372 9 : for (i = is_agg; i < fake_argc; i++) {
373 4 : zval_ptr_dtor(zargs[i]);
374 4 : efree(zargs[i]);
375 : }
376 5 : if (is_agg) {
377 3 : zval_ptr_dtor(zargs[1]);
378 3 : efree(zargs[1]);
379 : }
380 5 : efree(zargs);
381 : }
382 :
383 8 : if (!is_agg || !argv) {
384 : /* only set the sqlite return value if we are a scalar function,
385 : * or if we are finalizing an aggregate */
386 3 : if (retval) {
387 3 : switch (Z_TYPE_P(retval)) {
388 : case IS_LONG:
389 0 : sqlite3_result_int(context, Z_LVAL_P(retval));
390 0 : break;
391 :
392 : case IS_NULL:
393 0 : sqlite3_result_null(context);
394 0 : break;
395 :
396 : case IS_DOUBLE:
397 0 : sqlite3_result_double(context, Z_DVAL_P(retval));
398 0 : break;
399 :
400 : default:
401 3 : convert_to_string_ex(&retval);
402 3 : sqlite3_result_text(context, Z_STRVAL_P(retval),
403 : Z_STRLEN_P(retval), SQLITE_TRANSIENT);
404 : break;
405 : }
406 : } else {
407 0 : sqlite3_result_error(context, "failed to invoke callback", 0);
408 : }
409 :
410 3 : if (agg_context) {
411 1 : zval_ptr_dtor(agg_context);
412 : }
413 : } else {
414 : /* we're stepping in an aggregate; the return value goes into
415 : * the context */
416 2 : if (agg_context) {
417 2 : zval_ptr_dtor(agg_context);
418 : }
419 2 : if (retval) {
420 2 : *agg_context = retval;
421 2 : retval = NULL;
422 : } else {
423 0 : *agg_context = NULL;
424 : }
425 : }
426 :
427 5 : if (retval) {
428 3 : zval_ptr_dtor(&retval);
429 : }
430 :
431 5 : return ret;
432 : }
433 :
434 : static void php_sqlite3_func_callback(sqlite3_context *context, int argc,
435 : sqlite3_value **argv)
436 2 : {
437 2 : struct pdo_sqlite_func *func = (struct pdo_sqlite_func*)sqlite3_user_data(context);
438 : TSRMLS_FETCH();
439 :
440 2 : do_callback(&func->afunc, func->func, argc, argv, context, 0 TSRMLS_CC);
441 2 : }
442 :
443 : static void php_sqlite3_func_step_callback(sqlite3_context *context, int argc,
444 : sqlite3_value **argv)
445 2 : {
446 2 : struct pdo_sqlite_func *func = (struct pdo_sqlite_func*)sqlite3_user_data(context);
447 : TSRMLS_FETCH();
448 :
449 2 : do_callback(&func->astep, func->step, argc, argv, context, 1 TSRMLS_CC);
450 2 : }
451 :
452 : static void php_sqlite3_func_final_callback(sqlite3_context *context)
453 1 : {
454 1 : struct pdo_sqlite_func *func = (struct pdo_sqlite_func*)sqlite3_user_data(context);
455 : TSRMLS_FETCH();
456 :
457 1 : do_callback(&func->afini, func->fini, 0, NULL, context, 1 TSRMLS_CC);
458 1 : }
459 :
460 : /* {{{ bool SQLite::sqliteCreateFunction(string name, mixed callback [, int argcount])
461 : Registers a UDF with the sqlite db handle */
462 : static PHP_METHOD(SQLite, sqliteCreateFunction)
463 1 : {
464 : struct pdo_sqlite_func *func;
465 : zval *callback;
466 : char *func_name;
467 : int func_name_len;
468 1 : long argc = -1;
469 1 : char *cbname = NULL;
470 : pdo_dbh_t *dbh;
471 : pdo_sqlite_db_handle *H;
472 : int ret;
473 :
474 1 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l",
475 : &func_name, &func_name_len, &callback, &argc)) {
476 0 : RETURN_FALSE;
477 : }
478 :
479 1 : dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
480 1 : PDO_CONSTRUCT_CHECK;
481 :
482 1 : if (!zend_is_callable(callback, 0, &cbname)) {
483 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "function '%s' is not callable", cbname);
484 0 : efree(cbname);
485 0 : RETURN_FALSE;
486 : }
487 1 : efree(cbname);
488 :
489 1 : H = (pdo_sqlite_db_handle *)dbh->driver_data;
490 :
491 1 : func = (struct pdo_sqlite_func*)ecalloc(1, sizeof(*func));
492 :
493 1 : ret = sqlite3_create_function(H->db, func_name, argc, SQLITE_UTF8,
494 : func, php_sqlite3_func_callback, NULL, NULL);
495 1 : if (ret == SQLITE_OK) {
496 1 : func->funcname = estrdup(func_name);
497 :
498 1 : MAKE_STD_ZVAL(func->func);
499 1 : *(func->func) = *callback;
500 1 : zval_copy_ctor(func->func);
501 1 : INIT_PZVAL(func->func);
502 :
503 1 : func->argc = argc;
504 :
505 1 : func->next = H->funcs;
506 1 : H->funcs = func;
507 :
508 1 : RETURN_TRUE;
509 : }
510 :
511 0 : efree(func);
512 0 : RETURN_FALSE;
513 : }
514 : /* }}} */
515 :
516 : /* {{{ bool SQLite::sqliteCreateAggregate(string name, mixed step, mixed fini [, int argcount])
517 : Registers a UDF with the sqlite db handle */
518 :
519 : /* The step function should have the prototype:
520 : mixed step(mixed $context, int $rownumber, $value [, $value2 [, ...]])
521 :
522 : $context will be null for the first row; on subsequent rows it will have
523 : the value that was previously returned from the step function; you should
524 : use this to maintain state for the aggregate.
525 :
526 : The fini function should have the prototype:
527 : mixed fini(mixed $context, int $rownumber)
528 :
529 : $context will hold the return value from the very last call to the step function.
530 : rownumber will hold the number of rows over which the aggregate was performed.
531 : The return value of this function will be used as the return value for this
532 : aggregate UDF.
533 : */
534 :
535 : static PHP_METHOD(SQLite, sqliteCreateAggregate)
536 1 : {
537 : struct pdo_sqlite_func *func;
538 : zval *step_callback, *fini_callback;
539 : char *func_name;
540 : int func_name_len;
541 1 : long argc = -1;
542 1 : char *cbname = NULL;
543 : pdo_dbh_t *dbh;
544 : pdo_sqlite_db_handle *H;
545 : int ret;
546 :
547 1 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szz|l",
548 : &func_name, &func_name_len, &step_callback, &fini_callback, &argc)) {
549 0 : RETURN_FALSE;
550 : }
551 :
552 1 : dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
553 1 : PDO_CONSTRUCT_CHECK;
554 :
555 1 : if (!zend_is_callable(step_callback, 0, &cbname)) {
556 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "function '%s' is not callable", cbname);
557 0 : efree(cbname);
558 0 : RETURN_FALSE;
559 : }
560 1 : efree(cbname);
561 1 : if (!zend_is_callable(fini_callback, 0, &cbname)) {
562 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "function '%s' is not callable", cbname);
563 0 : efree(cbname);
564 0 : RETURN_FALSE;
565 : }
566 1 : efree(cbname);
567 :
568 1 : H = (pdo_sqlite_db_handle *)dbh->driver_data;
569 :
570 1 : func = (struct pdo_sqlite_func*)ecalloc(1, sizeof(*func));
571 :
572 1 : ret = sqlite3_create_function(H->db, func_name, argc, SQLITE_UTF8,
573 : func, NULL, php_sqlite3_func_step_callback, php_sqlite3_func_final_callback);
574 1 : if (ret == SQLITE_OK) {
575 1 : func->funcname = estrdup(func_name);
576 :
577 1 : MAKE_STD_ZVAL(func->step);
578 1 : *(func->step) = *step_callback;
579 1 : zval_copy_ctor(func->step);
580 1 : INIT_PZVAL(func->step);
581 :
582 1 : MAKE_STD_ZVAL(func->fini);
583 1 : *(func->fini) = *fini_callback;
584 1 : zval_copy_ctor(func->fini);
585 1 : INIT_PZVAL(func->fini);
586 :
587 1 : func->argc = argc;
588 :
589 1 : func->next = H->funcs;
590 1 : H->funcs = func;
591 :
592 1 : RETURN_TRUE;
593 : }
594 :
595 0 : efree(func);
596 0 : RETURN_FALSE;
597 : }
598 : /* }}} */
599 : static zend_function_entry dbh_methods[] = {
600 : PHP_ME(SQLite, sqliteCreateFunction, NULL, ZEND_ACC_PUBLIC)
601 : PHP_ME(SQLite, sqliteCreateAggregate, NULL, ZEND_ACC_PUBLIC)
602 : {NULL, NULL, NULL}
603 : };
604 :
605 : static zend_function_entry *get_driver_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
606 2 : {
607 2 : switch (kind) {
608 : case PDO_DBH_DRIVER_METHOD_KIND_DBH:
609 2 : return dbh_methods;
610 :
611 : default:
612 0 : return NULL;
613 : }
614 : }
615 :
616 : static void pdo_sqlite_request_shutdown(pdo_dbh_t *dbh TSRMLS_DC)
617 0 : {
618 0 : pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
619 : /* unregister functions, so that they don't linger for the next
620 : * request */
621 0 : if (H) {
622 0 : pdo_sqlite_cleanup_callbacks(H TSRMLS_CC);
623 : }
624 0 : }
625 :
626 : static struct pdo_dbh_methods sqlite_methods = {
627 : sqlite_handle_closer,
628 : sqlite_handle_preparer,
629 : sqlite_handle_doer,
630 : sqlite_handle_quoter,
631 : sqlite_handle_begin,
632 : sqlite_handle_commit,
633 : sqlite_handle_rollback,
634 : pdo_sqlite_set_attr,
635 : pdo_sqlite_last_insert_id,
636 : pdo_sqlite_fetch_error_func,
637 : pdo_sqlite_get_attribute,
638 : NULL, /* check_liveness: not needed */
639 : get_driver_methods,
640 : pdo_sqlite_request_shutdown
641 : };
642 :
643 : static char *make_filename_safe(const char *filename TSRMLS_DC)
644 130 : {
645 130 : if (strncmp(filename, ":memory:", sizeof(":memory:")-1)) {
646 13 : char *fullpath = expand_filepath(filename, NULL TSRMLS_CC);
647 :
648 13 : if (!fullpath) {
649 0 : return NULL;
650 : }
651 :
652 13 : if (PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
653 0 : efree(fullpath);
654 0 : return NULL;
655 : }
656 :
657 13 : if (php_check_open_basedir(fullpath TSRMLS_CC)) {
658 0 : efree(fullpath);
659 0 : return NULL;
660 : }
661 13 : return fullpath;
662 : }
663 117 : return estrdup(filename);
664 : }
665 :
666 : static int authorizer(void *autharg, int access_type, const char *arg3, const char *arg4,
667 : const char *arg5, const char *arg6)
668 0 : {
669 : char *filename;
670 0 : switch (access_type) {
671 : case SQLITE_COPY: {
672 : TSRMLS_FETCH();
673 0 : filename = make_filename_safe(arg4 TSRMLS_CC);
674 0 : if (!filename) {
675 0 : return SQLITE_DENY;
676 : }
677 0 : efree(filename);
678 0 : return SQLITE_OK;
679 : }
680 :
681 : case SQLITE_ATTACH: {
682 : TSRMLS_FETCH();
683 0 : filename = make_filename_safe(arg3 TSRMLS_CC);
684 0 : if (!filename) {
685 0 : return SQLITE_DENY;
686 : }
687 0 : efree(filename);
688 0 : return SQLITE_OK;
689 : }
690 :
691 : default:
692 : /* access allowed */
693 0 : return SQLITE_OK;
694 : }
695 : }
696 :
697 : static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
698 130 : {
699 : pdo_sqlite_db_handle *H;
700 130 : int i, ret = 0;
701 130 : long timeout = 60;
702 : char *filename;
703 :
704 130 : H = pecalloc(1, sizeof(pdo_sqlite_db_handle), dbh->is_persistent);
705 :
706 130 : H->einfo.errcode = 0;
707 130 : H->einfo.errmsg = NULL;
708 130 : dbh->driver_data = H;
709 :
710 130 : filename = make_filename_safe(dbh->data_source TSRMLS_CC);
711 :
712 130 : if (!filename) {
713 0 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC,
714 : "safe_mode/open_basedir prohibits opening %s",
715 : dbh->data_source);
716 0 : goto cleanup;
717 : }
718 :
719 130 : i = sqlite3_open(filename, &H->db);
720 130 : efree(filename);
721 :
722 130 : if (i != SQLITE_OK) {
723 0 : pdo_sqlite_error(dbh);
724 0 : goto cleanup;
725 : }
726 :
727 130 : if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) {
728 0 : sqlite3_set_authorizer(H->db, authorizer, NULL);
729 : }
730 :
731 130 : if (driver_options) {
732 1 : timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, timeout TSRMLS_CC);
733 : }
734 130 : sqlite3_busy_timeout(H->db, timeout * 1000);
735 :
736 130 : dbh->alloc_own_columns = 1;
737 130 : dbh->max_escaped_char_length = 2;
738 :
739 130 : ret = 1;
740 :
741 130 : cleanup:
742 130 : dbh->methods = &sqlite_methods;
743 :
744 130 : return ret;
745 : }
746 : /* }}} */
747 :
748 : pdo_driver_t pdo_sqlite_driver = {
749 : PDO_DRIVER_HEADER(sqlite),
750 : pdo_sqlite_handle_factory
751 : };
752 :
753 : /*
754 : * Local variables:
755 : * tab-width: 4
756 : * c-basic-offset: 4
757 : * End:
758 : * vim600: noet sw=4 ts=4 fdm=marker
759 : * vim<600: noet sw=4 ts=4
760 : */
|