Back to index

php5  5.3.10
sqlite_driver.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Author: Wez Furlong <wez@php.net>                                    |
00016   +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: sqlite_driver.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 #include "php_ini.h"
00027 #include "ext/standard/info.h"
00028 #include "pdo/php_pdo.h"
00029 #include "pdo/php_pdo_driver.h"
00030 #include "php_pdo_sqlite.h"
00031 #include "php_pdo_sqlite_int.h"
00032 #include "zend_exceptions.h"
00033 
00034 int _pdo_sqlite_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line TSRMLS_DC) /* {{{ */
00035 {
00036        pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
00037        pdo_error_type *pdo_err = stmt ? &stmt->error_code : &dbh->error_code;
00038        pdo_sqlite_error_info *einfo = &H->einfo;
00039 
00040        einfo->errcode = sqlite3_errcode(H->db);
00041        einfo->file = file;
00042        einfo->line = line;
00043 
00044        if (einfo->errcode != SQLITE_OK) {
00045               if (einfo->errmsg) {
00046                      pefree(einfo->errmsg, dbh->is_persistent);
00047               }
00048               einfo->errmsg = pestrdup((char*)sqlite3_errmsg(H->db), dbh->is_persistent);
00049        } else { /* no error */
00050               strncpy(*pdo_err, PDO_ERR_NONE, sizeof(PDO_ERR_NONE));
00051               return 0;
00052        }
00053        switch (einfo->errcode) {
00054               case SQLITE_NOTFOUND:
00055                      strncpy(*pdo_err, "42S02", sizeof("42S02"));
00056                      break; 
00057 
00058               case SQLITE_INTERRUPT:
00059                      strncpy(*pdo_err, "01002", sizeof("01002"));
00060                      break;
00061 
00062               case SQLITE_NOLFS:
00063                      strncpy(*pdo_err, "HYC00", sizeof("HYC00"));
00064                      break;
00065 
00066               case SQLITE_TOOBIG:
00067                      strncpy(*pdo_err, "22001", sizeof("22001"));
00068                      break;
00069        
00070               case SQLITE_CONSTRAINT:
00071                      strncpy(*pdo_err, "23000", sizeof("23000"));
00072                      break;
00073 
00074               case SQLITE_ERROR:
00075               default:
00076                      strncpy(*pdo_err, "HY000", sizeof("HY000"));
00077                      break;
00078        }
00079 
00080        if (!dbh->methods) {
00081               zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
00082                             *pdo_err, einfo->errcode, einfo->errmsg);
00083        }
00084        
00085        return einfo->errcode;
00086 }
00087 /* }}} */
00088 
00089 static int pdo_sqlite_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
00090 {
00091        pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
00092        pdo_sqlite_error_info *einfo = &H->einfo;
00093 
00094        if (einfo->errcode) {
00095               add_next_index_long(info, einfo->errcode);
00096               add_next_index_string(info, einfo->errmsg, 1);
00097        }
00098 
00099        return 1;
00100 }
00101 
00102 static void pdo_sqlite_cleanup_callbacks(pdo_sqlite_db_handle *H TSRMLS_DC)
00103 {
00104        struct pdo_sqlite_func *func;
00105 
00106        while (H->funcs) {
00107               func = H->funcs;
00108               H->funcs = func->next;
00109 
00110               if (H->db) {
00111                      /* delete the function from the handle */
00112                      sqlite3_create_function(H->db,
00113                             func->funcname,
00114                             func->argc,
00115                             SQLITE_UTF8,
00116                             func,
00117                             NULL, NULL, NULL);
00118               }
00119 
00120               efree((char*)func->funcname);
00121               if (func->func) {
00122                      zval_ptr_dtor(&func->func);
00123               }
00124               if (func->step) {
00125                      zval_ptr_dtor(&func->step);
00126               }
00127               if (func->fini) {
00128                      zval_ptr_dtor(&func->fini);
00129               }
00130               efree(func);
00131        }
00132 }
00133 
00134 static int sqlite_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
00135 {
00136        pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
00137        
00138        if (H) {
00139               pdo_sqlite_error_info *einfo = &H->einfo;
00140 
00141               pdo_sqlite_cleanup_callbacks(H TSRMLS_CC);
00142               if (H->db) {
00143                      sqlite3_close(H->db);
00144                      H->db = NULL;
00145               }
00146               if (einfo->errmsg) {
00147                      pefree(einfo->errmsg, dbh->is_persistent);
00148                      einfo->errmsg = NULL;
00149               }
00150               pefree(H, dbh->is_persistent);
00151               dbh->driver_data = NULL;
00152        }
00153        return 0;
00154 }
00155 /* }}} */
00156 
00157 static int sqlite_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
00158 {
00159        pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
00160        pdo_sqlite_stmt *S = ecalloc(1, sizeof(pdo_sqlite_stmt));
00161        int i;
00162        const char *tail;
00163 
00164        S->H = H;
00165        stmt->driver_data = S;
00166        stmt->methods = &sqlite_stmt_methods;
00167        stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL|PDO_PLACEHOLDER_NAMED;
00168 
00169        if (PDO_CURSOR_FWDONLY != pdo_attr_lval(driver_options, PDO_ATTR_CURSOR, PDO_CURSOR_FWDONLY TSRMLS_CC)) {
00170               H->einfo.errcode = SQLITE_ERROR;
00171               pdo_sqlite_error(dbh);
00172               return 0;
00173        }
00174 
00175        i = sqlite3_prepare(H->db, sql, sql_len, &S->stmt, &tail);
00176        if (i == SQLITE_OK) {
00177               return 1;
00178        }
00179 
00180        pdo_sqlite_error(dbh);
00181 
00182        return 0;
00183 }
00184 
00185 static long sqlite_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
00186 {
00187        pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
00188        char *errmsg = NULL;
00189 
00190        if (sqlite3_exec(H->db, sql, NULL, NULL, &errmsg) != SQLITE_OK) {
00191               pdo_sqlite_error(dbh);
00192               if (errmsg)
00193                      sqlite3_free(errmsg);
00194 
00195               return -1;
00196        } else {
00197               return sqlite3_changes(H->db);
00198        }
00199 }
00200 
00201 static char *pdo_sqlite_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
00202 {
00203        pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
00204        char *id;
00205        
00206        id = php_pdo_int64_to_str(sqlite3_last_insert_rowid(H->db) TSRMLS_CC);
00207        *len = strlen(id);
00208        return id;
00209 }
00210 
00211 /* NB: doesn't handle binary strings... use prepared stmts for that */
00212 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)
00213 {
00214        *quoted = safe_emalloc(2, unquotedlen, 3);
00215        sqlite3_snprintf(2*unquotedlen + 3, *quoted, "'%q'", unquoted);
00216        *quotedlen = strlen(*quoted);
00217        return 1;
00218 }
00219 
00220 static int sqlite_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
00221 {
00222        pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
00223        char *errmsg = NULL;
00224 
00225        if (sqlite3_exec(H->db, "BEGIN", NULL, NULL, &errmsg) != SQLITE_OK) {
00226               pdo_sqlite_error(dbh);
00227               if (errmsg)
00228                      sqlite3_free(errmsg);
00229               return 0;
00230        }
00231        return 1;
00232 }
00233 
00234 static int sqlite_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
00235 {
00236        pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
00237        char *errmsg = NULL;
00238 
00239        if (sqlite3_exec(H->db, "COMMIT", NULL, NULL, &errmsg) != SQLITE_OK) {
00240               pdo_sqlite_error(dbh);
00241               if (errmsg)
00242                      sqlite3_free(errmsg);
00243               return 0;
00244        }
00245        return 1;
00246 }
00247 
00248 static int sqlite_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
00249 {
00250        pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
00251        char *errmsg = NULL;
00252 
00253        if (sqlite3_exec(H->db, "ROLLBACK", NULL, NULL, &errmsg) != SQLITE_OK) {
00254               pdo_sqlite_error(dbh);
00255               if (errmsg)
00256                      sqlite3_free(errmsg);
00257               return 0;
00258        }
00259        return 1;
00260 }
00261 
00262 static int pdo_sqlite_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)
00263 {
00264        switch (attr) {
00265               case PDO_ATTR_CLIENT_VERSION:
00266               case PDO_ATTR_SERVER_VERSION:
00267                      ZVAL_STRING(return_value, (char *)sqlite3_libversion(), 1);
00268                      break;
00269               
00270               default:
00271                      return 0;     
00272        }
00273 
00274        return 1;
00275 }
00276 
00277 static int pdo_sqlite_set_attr(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
00278 {
00279        pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
00280 
00281        switch (attr) {
00282               case PDO_ATTR_TIMEOUT:
00283                      convert_to_long(val);
00284                      sqlite3_busy_timeout(H->db, Z_LVAL_P(val) * 1000);
00285                      return 1;
00286        }
00287        return 0;
00288 }
00289 
00290 static int do_callback(struct pdo_sqlite_fci *fc, zval *cb,
00291               int argc, sqlite3_value **argv, sqlite3_context *context,
00292               int is_agg TSRMLS_DC)
00293 {
00294        zval ***zargs = NULL;
00295        zval *retval = NULL;
00296        int i;
00297        int ret;
00298        int fake_argc;
00299        zval **agg_context = NULL;
00300        
00301        if (is_agg) {
00302               is_agg = 2;
00303        }
00304        
00305        fake_argc = argc + is_agg;
00306        
00307        fc->fci.size = sizeof(fc->fci);
00308        fc->fci.function_table = EG(function_table);
00309        fc->fci.function_name = cb;
00310        fc->fci.symbol_table = NULL;
00311        fc->fci.object_ptr = NULL;
00312        fc->fci.retval_ptr_ptr = &retval;
00313        fc->fci.param_count = fake_argc;
00314        
00315        /* build up the params */
00316 
00317        if (fake_argc) {
00318               zargs = (zval ***)safe_emalloc(fake_argc, sizeof(zval **), 0);
00319        }
00320 
00321        if (is_agg) {
00322               /* summon the aggregation context */
00323               agg_context = (zval**)sqlite3_aggregate_context(context, sizeof(zval*));
00324               if (!*agg_context) {
00325                      MAKE_STD_ZVAL(*agg_context);
00326                      ZVAL_NULL(*agg_context);
00327               }
00328               zargs[0] = agg_context;
00329 
00330               zargs[1] = emalloc(sizeof(zval*));
00331               MAKE_STD_ZVAL(*zargs[1]);
00332               ZVAL_LONG(*zargs[1], sqlite3_aggregate_count(context));
00333        }
00334        
00335        for (i = 0; i < argc; i++) {
00336               zargs[i + is_agg] = emalloc(sizeof(zval *));
00337               MAKE_STD_ZVAL(*zargs[i + is_agg]);
00338 
00339               /* get the value */
00340               switch (sqlite3_value_type(argv[i])) {
00341                      case SQLITE_INTEGER:
00342                             ZVAL_LONG(*zargs[i + is_agg], sqlite3_value_int(argv[i]));
00343                             break;
00344 
00345                      case SQLITE_FLOAT:
00346                             ZVAL_DOUBLE(*zargs[i + is_agg], sqlite3_value_double(argv[i]));
00347                             break;
00348 
00349                      case SQLITE_NULL:
00350                             ZVAL_NULL(*zargs[i + is_agg]);
00351                             break;
00352 
00353                      case SQLITE_BLOB:
00354                      case SQLITE3_TEXT:
00355                      default:
00356                             ZVAL_STRINGL(*zargs[i + is_agg], (char*)sqlite3_value_text(argv[i]),
00357                                           sqlite3_value_bytes(argv[i]), 1);
00358                             break;
00359               }
00360        }
00361 
00362 
00363        fc->fci.params = zargs;
00364 
00365 
00366        if ((ret = zend_call_function(&fc->fci, &fc->fcc TSRMLS_CC)) == FAILURE) {
00367               php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the callback");
00368        }
00369 
00370        /* clean up the params */
00371        if (zargs) {
00372               for (i = is_agg; i < fake_argc; i++) {
00373                      zval_ptr_dtor(zargs[i]);
00374                      efree(zargs[i]);
00375               }
00376               if (is_agg) {
00377                      zval_ptr_dtor(zargs[1]);
00378                      efree(zargs[1]);
00379               }
00380               efree(zargs);
00381        }
00382 
00383        if (!is_agg || !argv) {
00384               /* only set the sqlite return value if we are a scalar function,
00385                * or if we are finalizing an aggregate */
00386               if (retval) {
00387                      switch (Z_TYPE_P(retval)) {
00388                             case IS_LONG:
00389                                    sqlite3_result_int(context, Z_LVAL_P(retval));
00390                                    break;
00391 
00392                             case IS_NULL:
00393                                    sqlite3_result_null(context);
00394                                    break;
00395 
00396                             case IS_DOUBLE:
00397                                    sqlite3_result_double(context, Z_DVAL_P(retval));
00398                                    break;
00399 
00400                             default:
00401                                    convert_to_string_ex(&retval);
00402                                    sqlite3_result_text(context, Z_STRVAL_P(retval),
00403                                           Z_STRLEN_P(retval), SQLITE_TRANSIENT);
00404                                    break;
00405                      }
00406               } else {
00407                      sqlite3_result_error(context, "failed to invoke callback", 0);
00408               }
00409 
00410               if (agg_context) {
00411                      zval_ptr_dtor(agg_context);
00412               }
00413        } else {
00414               /* we're stepping in an aggregate; the return value goes into
00415                * the context */
00416               if (agg_context) {
00417                      zval_ptr_dtor(agg_context);
00418               }
00419               if (retval) {
00420                      *agg_context = retval;
00421                      retval = NULL;
00422               } else {
00423                      *agg_context = NULL;
00424               }
00425        }
00426 
00427        if (retval) {
00428               zval_ptr_dtor(&retval);
00429        }
00430 
00431        return ret;
00432 }
00433 
00434 static void php_sqlite3_func_callback(sqlite3_context *context, int argc,
00435        sqlite3_value **argv)
00436 {
00437        struct pdo_sqlite_func *func = (struct pdo_sqlite_func*)sqlite3_user_data(context);
00438        TSRMLS_FETCH();
00439 
00440        do_callback(&func->afunc, func->func, argc, argv, context, 0 TSRMLS_CC);
00441 }
00442 
00443 static void php_sqlite3_func_step_callback(sqlite3_context *context, int argc,
00444        sqlite3_value **argv)
00445 {
00446        struct pdo_sqlite_func *func = (struct pdo_sqlite_func*)sqlite3_user_data(context);
00447        TSRMLS_FETCH();
00448 
00449        do_callback(&func->astep, func->step, argc, argv, context, 1 TSRMLS_CC);
00450 }
00451 
00452 static void php_sqlite3_func_final_callback(sqlite3_context *context)
00453 {
00454        struct pdo_sqlite_func *func = (struct pdo_sqlite_func*)sqlite3_user_data(context);
00455        TSRMLS_FETCH();
00456 
00457        do_callback(&func->afini, func->fini, 0, NULL, context, 1 TSRMLS_CC);
00458 }
00459 
00460 /* {{{ bool SQLite::sqliteCreateFunction(string name, mixed callback [, int argcount])
00461    Registers a UDF with the sqlite db handle */
00462 static PHP_METHOD(SQLite, sqliteCreateFunction)
00463 {
00464        struct pdo_sqlite_func *func;
00465        zval *callback;
00466        char *func_name;
00467        int func_name_len;
00468        long argc = -1;
00469        char *cbname = NULL;
00470        pdo_dbh_t *dbh;
00471        pdo_sqlite_db_handle *H;
00472        int ret;
00473 
00474        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l",
00475                      &func_name, &func_name_len, &callback, &argc)) {
00476               RETURN_FALSE;
00477        }
00478        
00479        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
00480        PDO_CONSTRUCT_CHECK;
00481 
00482        if (!zend_is_callable(callback, 0, &cbname TSRMLS_CC)) {
00483               php_error_docref(NULL TSRMLS_CC, E_WARNING, "function '%s' is not callable", cbname);
00484               efree(cbname);
00485               RETURN_FALSE;
00486        }
00487        efree(cbname);
00488        
00489        H = (pdo_sqlite_db_handle *)dbh->driver_data;
00490 
00491        func = (struct pdo_sqlite_func*)ecalloc(1, sizeof(*func));
00492 
00493        ret = sqlite3_create_function(H->db, func_name, argc, SQLITE_UTF8,
00494                      func, php_sqlite3_func_callback, NULL, NULL);
00495        if (ret == SQLITE_OK) {
00496               func->funcname = estrdup(func_name);
00497               
00498               MAKE_STD_ZVAL(func->func);
00499               MAKE_COPY_ZVAL(&callback, func->func);
00500               
00501               func->argc = argc;
00502 
00503               func->next = H->funcs;
00504               H->funcs = func;
00505 
00506               RETURN_TRUE;
00507        }
00508 
00509        efree(func);
00510        RETURN_FALSE;
00511 }
00512 /* }}} */
00513 
00514 /* {{{ bool SQLite::sqliteCreateAggregate(string name, mixed step, mixed fini [, int argcount])
00515    Registers a UDF with the sqlite db handle */
00516 
00517 /* The step function should have the prototype:
00518    mixed step(mixed $context, int $rownumber, $value [, $value2 [, ...]])
00519 
00520    $context will be null for the first row; on subsequent rows it will have
00521    the value that was previously returned from the step function; you should
00522    use this to maintain state for the aggregate.
00523 
00524    The fini function should have the prototype:
00525    mixed fini(mixed $context, int $rownumber)
00526 
00527    $context will hold the return value from the very last call to the step function.
00528    rownumber will hold the number of rows over which the aggregate was performed.
00529    The return value of this function will be used as the return value for this
00530    aggregate UDF.
00531 */
00532    
00533 static PHP_METHOD(SQLite, sqliteCreateAggregate)
00534 {
00535        struct pdo_sqlite_func *func;
00536        zval *step_callback, *fini_callback;
00537        char *func_name;
00538        int func_name_len;
00539        long argc = -1;
00540        char *cbname = NULL;
00541        pdo_dbh_t *dbh;
00542        pdo_sqlite_db_handle *H;
00543        int ret;
00544 
00545        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szz|l",
00546                      &func_name, &func_name_len, &step_callback, &fini_callback, &argc)) {
00547               RETURN_FALSE;
00548        }
00549        
00550        dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
00551        PDO_CONSTRUCT_CHECK;
00552 
00553        if (!zend_is_callable(step_callback, 0, &cbname TSRMLS_CC)) {
00554               php_error_docref(NULL TSRMLS_CC, E_WARNING, "function '%s' is not callable", cbname);
00555               efree(cbname);
00556               RETURN_FALSE;
00557        }
00558        efree(cbname);
00559        if (!zend_is_callable(fini_callback, 0, &cbname TSRMLS_CC)) {
00560               php_error_docref(NULL TSRMLS_CC, E_WARNING, "function '%s' is not callable", cbname);
00561               efree(cbname);
00562               RETURN_FALSE;
00563        }
00564        efree(cbname);
00565        
00566        H = (pdo_sqlite_db_handle *)dbh->driver_data;
00567 
00568        func = (struct pdo_sqlite_func*)ecalloc(1, sizeof(*func));
00569 
00570        ret = sqlite3_create_function(H->db, func_name, argc, SQLITE_UTF8,
00571                      func, NULL, php_sqlite3_func_step_callback, php_sqlite3_func_final_callback);
00572        if (ret == SQLITE_OK) {
00573               func->funcname = estrdup(func_name);
00574               
00575               MAKE_STD_ZVAL(func->step);
00576               MAKE_COPY_ZVAL(&step_callback, func->step);
00577 
00578               MAKE_STD_ZVAL(func->fini);
00579               MAKE_COPY_ZVAL(&fini_callback, func->fini);
00580               
00581               func->argc = argc;
00582 
00583               func->next = H->funcs;
00584               H->funcs = func;
00585 
00586               RETURN_TRUE;
00587        }
00588 
00589        efree(func);
00590        RETURN_FALSE;
00591 }
00592 /* }}} */
00593 static const zend_function_entry dbh_methods[] = {
00594        PHP_ME(SQLite, sqliteCreateFunction, NULL, ZEND_ACC_PUBLIC)
00595        PHP_ME(SQLite, sqliteCreateAggregate, NULL, ZEND_ACC_PUBLIC)
00596        PHP_FE_END
00597 };
00598 
00599 static const zend_function_entry *get_driver_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
00600 {
00601        switch (kind) {
00602               case PDO_DBH_DRIVER_METHOD_KIND_DBH:
00603                      return dbh_methods;
00604 
00605               default:
00606                      return NULL;
00607        }
00608 }
00609 
00610 static void pdo_sqlite_request_shutdown(pdo_dbh_t *dbh TSRMLS_DC)
00611 {
00612        pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
00613        /* unregister functions, so that they don't linger for the next
00614         * request */
00615        if (H) {
00616               pdo_sqlite_cleanup_callbacks(H TSRMLS_CC);
00617        }
00618 }
00619 
00620 static struct pdo_dbh_methods sqlite_methods = {
00621        sqlite_handle_closer,
00622        sqlite_handle_preparer,
00623        sqlite_handle_doer,
00624        sqlite_handle_quoter,
00625        sqlite_handle_begin,
00626        sqlite_handle_commit,
00627        sqlite_handle_rollback,
00628        pdo_sqlite_set_attr,
00629        pdo_sqlite_last_insert_id,
00630        pdo_sqlite_fetch_error_func,
00631        pdo_sqlite_get_attribute,
00632        NULL,  /* check_liveness: not needed */
00633        get_driver_methods,
00634        pdo_sqlite_request_shutdown
00635 };
00636 
00637 static char *make_filename_safe(const char *filename TSRMLS_DC)
00638 {
00639        if (*filename && strncmp(filename, ":memory:", sizeof(":memory:")-1)) {
00640               char *fullpath = expand_filepath(filename, NULL TSRMLS_CC);
00641 
00642               if (!fullpath) {
00643                      return NULL;
00644               }
00645 
00646               if (PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
00647                      efree(fullpath);
00648                      return NULL;
00649               }
00650 
00651               if (php_check_open_basedir(fullpath TSRMLS_CC)) {
00652                      efree(fullpath);
00653                      return NULL;
00654               }
00655               return fullpath;
00656        }
00657        return estrdup(filename);
00658 }
00659 
00660 static int authorizer(void *autharg, int access_type, const char *arg3, const char *arg4,
00661               const char *arg5, const char *arg6)
00662 {
00663        char *filename;
00664        switch (access_type) {
00665               case SQLITE_COPY: {
00666                      TSRMLS_FETCH();
00667                      filename = make_filename_safe(arg4 TSRMLS_CC);
00668                      if (!filename) {
00669                             return SQLITE_DENY;
00670                      }
00671                      efree(filename);
00672                      return SQLITE_OK;
00673               }
00674 
00675               case SQLITE_ATTACH: {
00676                      TSRMLS_FETCH();
00677                      filename = make_filename_safe(arg3 TSRMLS_CC);
00678                      if (!filename) {
00679                             return SQLITE_DENY;
00680                      }
00681                      efree(filename);
00682                      return SQLITE_OK;
00683               }
00684 
00685               default:
00686                      /* access allowed */
00687                      return SQLITE_OK;
00688        }
00689 }
00690 
00691 static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
00692 {
00693        pdo_sqlite_db_handle *H;
00694        int i, ret = 0;
00695        long timeout = 60;
00696        char *filename;
00697 
00698        H = pecalloc(1, sizeof(pdo_sqlite_db_handle), dbh->is_persistent);
00699        
00700        H->einfo.errcode = 0;
00701        H->einfo.errmsg = NULL;
00702        dbh->driver_data = H;
00703 
00704        filename = make_filename_safe(dbh->data_source TSRMLS_CC);
00705 
00706        if (!filename) {
00707               zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC,
00708                      "safe_mode/open_basedir prohibits opening %s",
00709                      dbh->data_source);
00710               goto cleanup;
00711        }
00712 
00713        i = sqlite3_open(filename, &H->db);
00714        efree(filename);
00715 
00716        if (i != SQLITE_OK) {
00717               pdo_sqlite_error(dbh);
00718               goto cleanup;
00719        }
00720 
00721        if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) {
00722               sqlite3_set_authorizer(H->db, authorizer, NULL);
00723        }
00724 
00725        if (driver_options) {
00726               timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, timeout TSRMLS_CC);
00727        }
00728        sqlite3_busy_timeout(H->db, timeout * 1000);
00729 
00730        dbh->alloc_own_columns = 1;
00731        dbh->max_escaped_char_length = 2;
00732 
00733        ret = 1;
00734        
00735 cleanup:
00736        dbh->methods = &sqlite_methods;
00737        
00738        return ret;
00739 }
00740 /* }}} */
00741 
00742 pdo_driver_t pdo_sqlite_driver = {
00743        PDO_DRIVER_HEADER(sqlite),
00744        pdo_sqlite_handle_factory
00745 };
00746 
00747 /*
00748  * Local variables:
00749  * tab-width: 4
00750  * c-basic-offset: 4
00751  * End:
00752  * vim600: noet sw=4 ts=4 fdm=marker
00753  * vim<600: noet sw=4 ts=4
00754  */