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>