Return to sqlite_driver.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / pdo_sqlite |
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: */