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